跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python大前端算法

前端加密 encrypt-labs 靶场实战:环境搭建与全关卡解析

前端加密 encrypt-labs 靶场实战涵盖环境搭建、插件配置及多类加密算法破解。通过 Docker 部署靶场,利用 Galaxy 和 autoDecoder 插件实现请求加解密自动化。解析 AES 固定 Key、服务端获取 Key、RSA 加密、混合加密、DES 规律 Key、明文加签及防重放等关卡原理。结合浏览器栈跟踪定位混淆代码,使用 Python 脚本模拟客户端逻辑完成爆破,理解前端防护核心机制与绕过方法。

虚拟内存发布于 2026/4/6更新于 2026/6/1221 浏览
前端加密 encrypt-labs 靶场实战:环境搭建与全关卡解析

前言

在 Web 前端安全防护中,为抵御密码爆破攻击,开发人员常会在前端对登录关键参数(如签名、密码等)采用加密技术处理后再提交请求,增加了爆破的技术门槛。

encrypt-labs 作为专项练习靶场,用于探索这类前端加密场景下的破解思路。我们需要先分析前端加密逻辑,掌握常用的解密/逆向手法,再构造符合服务端验证规则的请求,以此完成密码爆破的技术练习,理解前端加密防护的核心原理与破解要点。

⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。

1 环境搭建(Docker 混淆版)

基于 Ubuntu 24.04.3 TLS 环境。

git clone https://github.com/Ta0ing/encrypt-labs-docker.git # 修改数据库配置
cd src sudo vim database.php # 修改如下 4 行
$host='encrypt_labs_mysql';
$dbname='encrypt_labs_db';
$username='encrypt_user';
$password='encrypt_password';
# docker 镜像配置
sudo vim /etc/docker/daemon.json 
{"registry-mirrors":["https://docker.1ms.run", "https://dockerproxy.cn", "https://hub.rat.dev"]}
systemctl restart docker
# 老版本 Docker(独立安装 docker-compose)
docker-compose up -d --build
# 新版本 Docker(内置命令 compose)
docker compose up -d --build

访问 你的靶机 ip:82 地址,默认账户密码:admin 123456

图片

图片

2 配置插件

配置 BurpSuite 插件的目的:

  • 加解密可以通过任意语言的代码实现,但是解密后在 BurpSuite 中可以直接配置明文,更直观的进行爆破;
  • 如果不通过 BurpSuite 进行爆破,完全可以仅通过脚本来实现请求的加解密和爆破。
  • 2.1 Galaxy

    安装 BurpSuite 插件:https://github.com/outlaws-bai/Galaxy

    插件介绍:https://github.com/outlaws-bai/Galaxy/wiki/%E5%8A%9F%E8%83%BD%E8%AF%A6%E8%A7%A3

    图片

    下载脚本示例代码:便于独立脚本的开发

    git clone https://github.com/outlaws-bai/GalaxyHttpHooker.git 
    

    示例说明:

    • aes_cbc.py(基础版本)直接处理请求体中的 JSON 数据
    • aes_cbc_form.py(表单版本)处理表单数据 (a=1&b=2)
    • aes_cbc_query.py(查询参数版本)只对查询参数中的字段进行加解密 (?a=1&b=2)

    因此我们遇到的 HTTP 参数加密请求,可以依据上述模板进行修改。

    图片

    所有脚本围绕 4 个 hook 方法:hookRequestToBurp,hookRequestToServer,hookResponseToBurp,hookResponseToClient。

    作用分别如下:我们对请求的加解密是前 2 个方法,如果响应内容加密了,你想解密需要实现后 2 个方法。

    ①:HTTP 请求从客户端到达 Burp 时被触发。你需要在此处完成请求解密的代码,这样就可以在 Burp 中看到明文的请求报文。

    ②:HTTP 请求从 Burp 将要发送到 Server 时被触发。你需要在此处完成请求加密的代码,这样就可以将加密后的请求报文发送到 Server。

    ③:HTTP 响应从 Server 到达 Burp 时被触发。你需要在此处完成响应解密的代码,这样就可以在 Burp 中看到明文的响应报文。

    ④:HTTP 响应从 Burp 将要返回到 Client 时被触发。你需要在此处完成响应加密的代码,这样就可以将加密后的响应报文返回给 Client。

    2.2 autoDecoder

    官方仓库:https://github.com/f0ng/autoDecoder

    3 AES 固定 Key

    使用火狐浏览器的'栈跟踪'功能,查看调用的所有 js 代码。

    可以看到 sendDataAes http://192.168.10.11:82/js/app.js:1:1098 和发起者都是 app.js,因此从 app.js 查询加密逻辑。

    图片

    如果是谷歌浏览器,只能看发起时的 js 文件,当然这个靶场不复杂,无伤大雅。

    图片

    继续使用火狐浏览器演示,查看 app.js 代码,可以看到代码经过了混淆。

    图片

    在右边 click 处勾上,表示点击时调试。

    图片

    点击登录按钮,然后点击'AES 固定 key',继续调试。

    图片

    自动定位到如下 sendDataAes 函数中,可以看到对用户名、密码的对象使用 AES 加密,包含 iv、CBC 的 mode、padding 填充信息。

    图片

    我们需要知道是如何将用户名密码进行 AES 加密的,直接将此处代码给 AI 分析下:

    函数:sendDataAes()

    加密参数:

    • 算法:AES-CBC
    • 密钥(Key):固定 16 位字符串 1234567890123456(Utf8 编码)
    • 偏移量(IV):固定 16 位字符串 1234567890123456(Utf8 编码)
    • 填充方式:PKCS7(默认填充规则)
    • 输出:Base64 编码的加密结果

    传输方式:将加密后的数据拼接为 encryptedData=加密值,以 application/x-www-form-urlencoded 格式 POST 提交

    抓包查看请求信息,是表单格式的。

    图片

    点击 start 按钮启动插件,这里不勾选 Hook Response,原因是响应内容是明文,request.host 填入的是靶机的 IP。

    图片

    直接复制 aes_cbc_form.py 脚本进行修改:这里修改了 KEY、IV 的值,将模板中的 username 修改为 encryptedData,因为请求时的参数是 encryptedData。

    import json
    import base64
    import typing as t
    from fastapi import FastAPI
    from urllib.parse import parse_qs, urlencode
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad, unpad
    from _base_classes import *
    
    KEY = b"1234567890123456"
    IV = b"1234567890123456"
    JSON_KEY = "data"
    
    app = FastAPI()
    
    @app.post("/hookRequestToBurp", response_model=RequestModel)
    async def hook_request_to_burp(request: RequestModel):
        """HTTP 请求从数据客户端到达 Burp 时被调用。在此处完成请求解密的代码就可以在 Burp 中看到明文的请求报文。"""
        # 获取需要解密的数据
        encrypted_data: bytes = base64.b64decode(parse_qs(request.content.decode())["encryptedData"][0])
        # 调用函数解密
        data: bytes = decrypt(encrypted_data)
        print(f"[DEBUG] 解密后的数据:{data.decode()}")
        # 更新 query
        request.content = urlencode({"encryptedData": data.decode()}).encode()
        return request
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到 Server。"""
        # 获取被解密的数据
        data: bytes = parse_qs(request.content.decode())["encryptedData"][0].encode()
        # 调用函数加密回去
        encryptedData: bytes = encrypt(data)
        print(f"[DEBUG] 加密后的数据:{base64.b64encode(encryptedData)}")
        # 更新 query
        request.content = urlencode({"encryptedData": base64.b64encode(encryptedData)}).encode()
        return request
    
    @app.post("/hookResponseToBurp", response_model=ResponseModel)
    async def hook_response_to_burp(response: ResponseModel):
        return response
    
    @app.post("/hookResponseToClient", response_model=ResponseModel)
    async def hook_response_to_client(response: ResponseModel):
        return response
    
    def decrypt(content: bytes) -> bytes:
        cipher = AES.new(KEY, AES.MODE_CBC, IV)
        return unpad(cipher.decrypt(content), AES.block_size)
    
    def encrypt(content: bytes) -> bytes:
        cipher = AES.new(KEY, AES.MODE_CBC, IV)
        return cipher.encrypt(pad(content, AES.block_size))
    
    def get_data(content: bytes) -> bytes:
        body_json: t.Dict = json.loads(content)
        return base64.b64decode(body_json[JSON_KEY])
    
    def to_data(contnet: bytes) -> bytes:
        body_json = {}
        body_json[JSON_KEY] = base64.b64encode(contnet).decode()
        return json.dumps(body_json).encode()
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    然后可以在 proxy 请求中尝试解密,操作如下:

    图片

    解密后可以看到明文显示,这里是弹出了一个窗口,可以看到 url 编码后的结果;注意这里的 X-Galaxy-Http-Hook: HookedRequest 是 Galaxy 插件 hook 的标识,有这个标识才会进行加密脚本中 hookRequestToServer 的执行。

    图片

    使用 Decoder 模块进行 URL 解码看看结果。

    图片

    如果觉得手动解码有点麻烦,可以将请求发送到 repeater 模块中解密,右侧的 inspector 功能自动解码,省去一次操作步骤。

    图片

    脚本也会同步打印调试信息,可以看到解密后的信息。

    图片

    那么我们修改输入的明文,看看插件的效果,能否自动加密后发送请求。

    图片

    可以看到,脚本中的 hookRequestToServer 将明文加密后发送给服务端。

    图片

    接下来就是如何进行爆破的问题,其实跟普通的爆破是一样的,将解密后端请求添加到 intruder 模块中,针对爆破参数添加字典进行爆破即可(后续题目不再赘述爆破步骤)。

    图片

    可以看到响应结果是正常显示。

    图片

    插件脚本也会自动进行加密后发送请求,这里提供的脚本也同步打印了加密的信息。

    图片

    4 AES 服务端获取 Key

    查看请求:先从服务端获取 aes 加密的 key 和 iv 的值,多次请求可以看到这 2 个值是固定的。

    图片

    然后发送加密请求,响应内容存在 Unicode 编码,使用 python print 解码得到 用户名或密码错误

    图片

    图片

    通过栈跟踪,定位到关键代码后分析如下:

    请求格式:POST + application/json + encryptedData 的 JSON 体;

    请求内容:明文是账号密码 JSON,加密后仅传加密字符串;

    加密方式:AES-CBC + PKCS7 填充 + Base64 输出;

    加密参数:Key/IV 从后端动态获取(Base64 解码后使用),长度均为 16 字节(AES-128)。

    图片

    那么我们复制模板中的 aes_cbc.py 脚本,修改对 key 和 iv 进行 base64 解码、修改 JSON_KEY 为请求中的参数 encryptedData:

    import json
    import base64
    import typing as t
    from fastapi import FastAPI
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad, unpad
    from _base_classes import *
    
    KEY = base64.b64decode("UMmKw73GSNZcCFqj6/XN5A==")
    IV = base64.b64decode("1SofbOFnjQCBcNt2M35PTQ==")
    JSON_KEY = "encryptedData"
    
    app = FastAPI()
    
    @app.post("/hookRequestToBurp", response_model=RequestModel)
    async def hook_request_to_burp(request: RequestModel):
        """HTTP 请求从客户端到达 Burp 时被调用。在此处完成请求解密的代码就可以在 Burp 中看到明文的请求报文。"""
        # print(f"[+] hookRequestToBurp be called. request: {request.model_dump_json()}")
        # 获取需要解密的数据
        encrypted_data: bytes = get_data(request.content)
        # 调用函数解密
        data: bytes = decrypt(encrypted_data)
        print(f"[DEBUG] 解密后的数据:{data.decode()}")
        # 更新 body 为已解密的数据
        request.content = data
        return request
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到 Server。"""
        # print(f"[+] hookRequestToServer be called. request: {request.model_dump_json()}")
        # 获取被解密的数据
        data: bytes = request.content
        # 调用函数加密回去
        encryptedData: bytes = encrypt(data)
        # 将已加密的数据转换为 Server 可识别的格式
        body: bytes = to_data(encryptedData)
        print(f"[DEBUG] 加密后的数据:{base64.b64encode(encryptedData)}")
        # 更新 body
        request.content = body
        return request
    
    @app.post("/hookResponseToBurp", response_model=ResponseModel)
    async def hook_response_to_burp(response: ResponseModel):
        return response
    
    @app.post("/hookResponseToClient", response_model=ResponseModel)
    async def hook_response_to_client(response: ResponseModel):
        return response
    
    def decrypt(content: bytes) -> bytes:
        cipher = AES.new(KEY, AES.MODE_CBC, IV)
        return unpad(cipher.decrypt(content), AES.block_size)
    
    def encrypt(content: bytes) -> bytes:
        cipher = AES.new(KEY, AES.MODE_CBC, IV)
        return cipher.encrypt(pad(content, AES.block_size))
    
    def get_data(content: bytes) -> bytes:
        body_json: t.Dict = json.loads(content)
        return base64.b64decode(body_json[JSON_KEY])
    
    def to_data(contnet: bytes) -> bytes:
        body_json = {}
        body_json[JSON_KEY] = base64.b64encode(contnet).decode()
        return json.dumps(body_json).encode()
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    启动后将加密请求发送到 repeater 模块进行解密。

    图片

    成功解密,脚本也正常打印调试信息。

    图片

    修改密码请求,发送成功

    图片

    脚本也成功打印调试信息。

    图片

    5 Rsa 加密

    加密请求如下:

    图片

    通过栈追踪定位到如下代码,分析结果如下:

    请求方式:POST + 表单格式(application/x-www-form-urlencoded);

    请求参数:明文是账号密码 JSON 串(格式是 data={"username":"xxx","password":"xxx"}),加密后为 Base64 格式的 RSA 密文;

    加密方法:RSA 非对称加密,PKCS#1 v1.5 填充;

    加密参数:固定硬编码的 RSA 1024 位公钥。

    图片

    Galaxy

    改造模板中的 rsa.py 代码:

    • 本题不知道解密的私钥,只能尝试进行请求的加密(前面分析已经知道了请求体的格式);
    • 这个题目需要对加密后的结果进行 url 编码;
    • 注意公钥书写的格式,\n 手动换行;
    • 提取请求的参数 JSON_KEY 是 data;
    • 需要对 BurpSuite 请求添加请求头 X-Galaxy-Http-Hook: HookedRequest,以让 Galaxy 插件识别是要加密的请求。
    import base64
    from urllib.parse import parse_qs, quote_plus
    from Crypto.Cipher import PKCS1_v1_5
    from Crypto.PublicKey import RSA
    from fastapi import FastAPI
    from _base_classes import *
    
    pub_key = """-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
    NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
    DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
    ocDbsNeCwNpRxwjIdQIDAQAB
    -----END PUBLIC KEY-----"""
    
    JSON_KEY = "data"
    
    app = FastAPI()
    
    @app.post("/hookRequestToBurp", response_model=RequestModel)
    async def hook_request_to_burp(request: RequestModel):
        return request
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到 Server。"""
        # 获取请求内容
        content_str = request.content.decode('utf-8')
        # 解析请求内容,提取参数的值
        try:
            parsed_data = parse_qs(content_str)
            if 'data' in parsed_data:
                # 获取参数的值
                original_data = parsed_data['data'][0]
                print(f"[DEBUG] 加密前的数据:{original_data}")
                # 对值进行 RSA 加密
                encrypted_data = encrypt(original_data.encode('utf-8'), pub_key)
                # Base64 编码
                encrypted_b64 = base64.b64encode(encrypted_data).decode('utf-8')
                # URL 编码
                encrypted_url_encoded = quote_plus(encrypted_b64)
                # 构造新的请求内容
                new_content = f"data={encrypted_url_encoded}"
                print(f"[DEBUG] 加密后的数据:{new_content}")
                # 更新请求内容
                request.content = new_content.encode('utf-8')
            else:
                print("[WARNING] 请求中未找到指定参数")
        except Exception as e:
            print(f"[ERROR] 处理请求时出错:{e}")
            pass
        return request
    
    def encrypt(content: bytes, secret: bytes) -> bytes:
        rsa_key = RSA.import_key(secret)
        cipher = PKCS1_v1_5.new(rsa_key)
        return cipher.encrypt(content)
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    启动脚本后,通过构造 BurpSuite 请求完成加密请求,注意添加请求体 X-Galaxy-Http-Hook: HookedRequest,让请求走我们编写的 Galaxy 的脚本。

    图片

    图片

    autoDecoder

    配置如下图:题目中的密文还进行了 url 编码,所有要勾选 2

    图片

    注意密钥是公钥:填写格式如下:

    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb ocDbsNeCwNpRxwjIdQIDAQAB 
    

    图片

    配置后在 repeater 模块发送请求,可以成功加密。

    图片

    6 AES+Rsa 加密

    加密请求如下:

    图片

    定位到加密代码,分析如下:

    使用算法:

    • AES-CBC 模式,加密数据格式 {"username":"xxx","password":"xxx"},AES 的 key 和 iv 随机 16 字节。
    • RSA 公钥加密,_0x41d8d9[_0x13ef4f(953, 972)](_0x13ef4f(990, 973)) 这一行,就是设置 RSA 公钥的地方;_0x13ef4f(953, 972)对应 setPublicKey,(_0x13ef4f(990, 973)即公钥内容。
    {
    "encryptedData":"AES 加密后的用户名 + 密码 JSON 字符串",
    // AES 加密数据
    "encryptedKey":"RSA 加密后的 AES key(Base64 格式)",
    // RSA 加密后的 AES key
    "encryptedIv":"RSA 加密后的 AES iv(Base64 格式)"
    // RSA 加密后的 AES iv
    }
    

    图片

    在浏览器的控制台打印 console.log(_0x13ef4f(990, 973)) 获取 RSA 公钥:

    图片

    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
    NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
    DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
    ocDbsNeCwNpRxwjIdQIDAQAB
    -----END PUBLIC KEY-----
    

    思路:

    • 目标是替换 encryptedData 的内容,因此需要进行 AES 解密;
    • AES 解密需要 AES 的 key 和 iv;
    • key 和 iv 在 encryptedKey 和 encryptedIv 中被 RSA 的公钥加密;
    • 不知道 RSA 私钥无法解密 key 和 iv;通过 Chrome 浏览器固定 AES 的 key 和 iv 的值;
    • 传参时 encryptedData 使用明文数据(格式前面分析已经知道);encryptedKey 和 encryptedIv 使用请求中的原始密文。
    • 加密时通过 AES 算法加密 encryptedData 的值。

    使用 Chrome 浏览器的 override content 功能替换 app.js:先将原始 app.js 下载到本地,在浏览器源码处右键 Overrides content 选择本地的文件,选中后修改代码中固定 key 和 iv 为 16 字节,修改完按 Ctrl+S 保存,注意格式。

    注意:下次打开浏览器即使该页面启用了 Overrides content 也会失效,需要在修改的地方打断点,用 debugger 的形式运行。

    , _0x4515a4 = CryptoJS.enc.Utf8.parse('1234567890123456') , _0x5e9345 = CryptoJS.enc.Utf8.parse('1234567890123456')
    

    图片

    然后抓包,可以看到使用固定 key 和 iv 进行 AES 加密后的 encryptedData,重试一次保证 encryptedData 的值不变,说明代码修改有效。

    图片

    Galaxy

    脚本需要实现的是使用 AES 加密参数 encryptedData 的值,固定 key 和 iv 为我们指定的值;其他 2 个参数的值不变。

    import base64
    import json
    from Crypto.Cipher import PKCS1_v1_5, AES
    from Crypto.PublicKey import RSA
    from Crypto.Util.Padding import pad
    from fastapi import FastAPI
    from _base_classes import *
    
    KEY = b"1234567890123456"  # 16 字节
    IV = b"1234567890123456"  # 16 字节
    JSON_KEY1 = "encryptedData"
    
    app = FastAPI()
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        try:
            # 获取请求内容
            data: bytes = request.content
            # 解析 JSON
            request_json = json.loads(data.decode())
            # print(f"解析的 JSON: {request_json}")
            # 只修改 encryptedData 参数,保持其他参数不变
            if JSON_KEY1 in request_json:
                # 获取原始的 encryptedData 值
                original_encrypted_data = request_json[JSON_KEY1]
                print(f"原始 encryptedData: {original_encrypted_data}")
                # 处理 encryptedData 值
                if isinstance(original_encrypted_data, str):
                    try:
                        # 尝试将字符串解析为 JSON 对象
                        inner_json = json.loads(original_encrypted_data)
                        print(f"解析出的 JSON: {inner_json}")
                        # 重新序列化为字符串用于加密
                        encrypted_data_bytes = original_encrypted_data.encode()
                    except json.JSONDecodeError:
                        # 如果不是有效的 JSON 字符串,直接使用原字符串
                        print("encryptedData 不是有效的 JSON 格式,直接使用原值")
                        encrypted_data_bytes = original_encrypted_data.encode()
                else:
                    # 如果不是字符串,转换为字符串
                    encrypted_data_bytes = str(original_encrypted_data).encode()
                # 对 encryptedData 进行 AES 加密
                encryptedData1: bytes = aes_encrypt(encrypted_data_bytes)
                # 更新 encryptedData 参数的值
                request_json[JSON_KEY1] = base64.b64encode(encryptedData1).decode()
                # 构造新的请求体
                body: bytes = json.dumps(request_json, ensure_ascii=False).encode()
                encrypted_json_str = body.decode()
                print(f"[DEBUG] 修改后的数据:{encrypted_json_str}")
                request.content = body
            else:
                print(f"未找到 {JSON_KEY1} 参数")
        except Exception as e:
            print(f"处理错误:{e}")
        return request
    
    def aes_encrypt(content: bytes) -> bytes:
        cipher = AES.new(KEY, AES.MODE_CBC, IV)
        return cipher.encrypt(pad(content, AES.block_size))
    
    def rsa_encrypt(content: bytes, secret: bytes) -> bytes:
        rsa_key = RSA.import_key(secret)
        cipher = PKCS1_v1_5.new(rsa_key)
        return cipher.encrypt(content)
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    启动编写的脚本,将加密请求发送到 repeater 模块,添加 hook 的请求头,修改加密数据为 {"username":"admin","password":"123456"},发送请求后,服务端成功响应。

    图片

    脚本也同步打印调试信息:

    图片

    autoDecoder

    使用 autoDecoder 比较方便,配置如下(记得保存配置):正则是 "encryptedData":"(.*)","encryptedKey"。

    图片

    记得重新加载下新配置,以免不生效。

    图片

    直接在请求中明文输入,内容是 {"username":"admin","password":"123456"},实战中可以对这里进行爆破。

    图片

    7 DES 规律 key

    请求如下:

    图片

    核心代码使用 DES-CBC 模式加密密码,核心规则:

    • 密钥(Key):从用户名截取前 8 位(0 开始),不足补字符 6 到 8 位;
    • 向量(IV):固定前缀 9999 + 用户名前 4 位(0 开始),不足补字符 9 到 8 位;
    • 填充方式:PKCS7(CryptoJS 默认);
    • 输出格式:加密后的二进制密文转 16 进制字符串(而非 Base64);
    • 加密对象:页面输入的密码(password 输入框的值)。

    一句话总结:通过用户名获取 key 和 iv 的值,对密码进行 DES-CBC 加密,结果转 16 进制字符串。

    图片

    Galaxy

    脚本代码如下:实现的就是对 password 值的加解密,需要获取 username 来生成 key 和 iv 的值。

    import json
    from Crypto.Cipher import DES
    from Crypto.Util.Padding import pad, unpad
    from fastapi import FastAPI
    from _base_classes import *
    
    KEY = b""
    IV = b""
    
    app = FastAPI()
    
    @app.post("/hookRequestToBurp", response_model=RequestModel)
    async def hook_request_to_burp(request: RequestModel):
        """HTTP 请求从客户端到达 Burp 时被调用。在此处完成请求解密的代码就可以在 Burp 中看到明文的请求报文。"""
        # print(f"[+] hookRequestToBurp be called. request: {request.model_dump_json()}")
        try:
            # 解析请求体 JSON
            request_body = json.loads(request.content.decode())
            username = request_body.get("username", "")
            password_encrypted = request_body.get("password", "")
            if not username or not password_encrypted:
                print("缺少 username 或 password 字段")
                return request
            # 生成 KEY 和 IV
            global KEY, IV
            KEY, IV = generate_key_iv(username)
            print(f"生成的 KEY: {KEY}, IV: {IV}")
            # 将十六进制字符串转换为字节用于解密
            encrypted_bytes = bytes.fromhex(password_encrypted)
            # 使用 decrypt 方法解密
            decrypted_bytes = decrypt(encrypted_bytes)
            password_decrypted = decrypted_bytes.decode('utf-8')
            print(f"解密后的 password: {password_decrypted}")
            # 更新请求体
            request_body["password"] = password_decrypted
            request.content = json.dumps(request_body, ensure_ascii=False).encode()
        except Exception as e:
            print(f"解密过程出错:{e}")
        return request
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求加密的代码就可以将加密后的请求报文发送到 Server。"""
        # print(f"[+] hookRequestToServer be called. request: {request.model_dump_json()}")
        try:
            # 解析请求体 JSON(此时 password 应该是明文)
            request_body = json.loads(request.content.decode())
            username = request_body.get("username", "")
            password_decrypted = request_body.get("password", "")
            if not username or not password_decrypted:
                print("缺少 username 或 password 字段")
                return request
            # 生成 KEY 和 IV
            global KEY, IV
            KEY, IV = generate_key_iv(username)
            print(f"[+] 生成的 KEY: {KEY}, IV: {IV}")
            # 使用现有的 encrypt 方法加密 password
            password_bytes = password_decrypted.encode('utf-8')
            encrypted_bytes = encrypt(password_bytes)
            # 转换为十六进制字符串
            password_encrypted = encrypted_bytes.hex()
            print(f"加密后的 password: {password_encrypted}")
            # 只更新 password 字段
            request_body["password"] = password_encrypted
            # 构造新的请求体
            request.content = json.dumps(request_body, ensure_ascii=False).encode()
        except Exception as e:
            print(f"加密过程出错:{e}")
        return request
    
    def generate_key_iv(username: str) -> tuple[bytes, bytes]:
        """
        根据用户名生成 KEY 和 IV
        KEY: 用户名截取前 8 位(0 开始),不足补字符'6'到 8 位
        IV: 固定前缀'9999' + 用户名前 4 位(0 开始),不足补字符'9'到 8 位
        """
        # 生成 KEY
        username_prefix = username[:8]
        key = username_prefix.ljust(8, '6').encode()
        # 生成 IV
        username_prefix_4 = username[:4]
        iv_str = "9999" + username_prefix_4.ljust(4, '9')
        iv = iv_str.encode()
        return key, iv
    
    def decrypt(content: bytes) -> bytes:
        cipher = DES.new(KEY, DES.MODE_CBC, IV)
        return unpad(cipher.decrypt(content), DES.block_size)
    
    def encrypt(content: bytes) -> bytes:
        cipher = DES.new(KEY, DES.MODE_CBC, IV)
        return cipher.encrypt(pad(content, DES.block_size))
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    在 repeater 中解密请求:

    图片

    解密后密码是明文:

    图片

    发送也正常:

    图片

    脚本调试信息也正常:

    图片

    autoDecoder

    使用这个工具的话只能单个进行验证,需要自己算 key 和 iv,密码记得选 16 进制 (hex);因此这关使用 autoDecoder 工具只能爆破固定用户名的密码。

    图片

    8 明文加签

    请求如下:

    图片

    核心代码分析如下:

    随机数

    • 签名算法:HmacSHA256(基于哈希的消息认证码,不可逆);
    • nonce 是随机小数转换成 36 进制再去掉 0.;
    • timestamp 是获取当前毫秒时间戳,除以 1000 并向下取整;
    • 签名密钥:固定值 be56e057f20f883e;
    • 签名原文:用户名 + 密码 + 随机数 (nonce) + 时间戳 (timestamp);
    • 签名输出:HmacSHA256 结果转 16 进制字符串。

    图片

    选中使用 Galaxy 进行请求加签,脚本如下:

    import hashlib
    import hmac
    import json
    import random
    import string
    import time
    from fastapi import FastAPI
    from _base_classes import *
    
    app = FastAPI()
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求签名计算的代码。"""
        try:
            # 获取原始请求内容
            content_str = request.content.decode('utf-8')
            # 解析请求体 JSON
            request_body = json.loads(content_str)
            # 获取用户名和密码
            username = request_body.get("username", "")
            password = request_body.get("password", "")
            if not username or not password:
                print("缺少 username 或 password 字段")
                return request
            # 生成随机数
            nonce = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
            # 获取当前毫秒时间戳
            timestamp = int(time.time())
            # 签名密钥
            secret_key = "be56e057f20f883e"
            # 构造签名原文:用户名 + 密码 + 随机数 + 时间戳
            sign_text = f"{username}{password}{nonce}{timestamp}"
            # 计算 HmacSHA256 签名
            signature = hmac.new(
                secret_key.encode('utf-8'),
                sign_text.encode('utf-8'),
                hashlib.sha256
            ).hexdigest()
            # 更新请求体中的字段
            request_body["nonce"] = nonce
            request_body["timestamp"] = timestamp
            request_body["signature"] = signature
            # 构造新的请求体
            new_content = json.dumps(request_body, ensure_ascii=False).encode()
            request.content = new_content
            print(f"新的请求内容:{new_content.decode()}")
        except json.JSONDecodeError as e:
            print(f"JSON 解析错误:{e}")
            return request
        except Exception as e:
            print(f"签名计算过程出错:{e}")
            return request
        return request
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    发送请求时记得添加请求头:X-Galaxy-Http-Hook: HookedRequest

    图片

    图片

    9 加签 key 在服务器端

    请求有 2 个,先从服务端获取签名,再发送请求:

    图片

    图片

    核心代码逻辑:账号密码 + 生成时间戳 → 找服务器要签名 → 带签名提交登录信息。

    async function sendDataWithNonceServer(_0xb4476b){
    function _0x5b14e6(_0x9f039f, _0x3746ee){return _0x4f79d5(_0x9f039f -0xde, _0x3746ee);}
    const _0x41822d = document['getElementById']('username')['value'], _0x3c65d8 = document['getElementById']('password')['value'], _0x173dbd = Math[_0x5b14e6(0x281,0x282)](Date[_0x5b14e6(0x282,0x26f)]()/0x3e8);
    try{
    const _0x55d2c7 =awaitfetch(_0xb4476b +_0x5b14e6(0x283,0x28d),{'method':_0x5b14e6(0x27a,0x26b),'headers':{'Content-Type':_0x5b14e6(0x280,0x26f)},'body':JSON['stringify']({'username': _0x41822d,'password': _0x3c65d8,'timestamp': _0x173dbd })});
    closeModal();
    if(!_0x55d2c7['ok']){ console['error']('获取签名失败:', _0x55d2c7['statusText']),alert('获取签名失败,请稍后重试。');return;}
    const{signature: _0x2755ad}=await _0x55d2c7[_0x5b14e6(0x26b,0x279)]();
    if(!_0x2755ad){alert('签名获取失败,服务器未返回签名。');return;}
    const _0x58deb5 =awaitfetch(''+ _0xb4476b,{'method':'POST','headers':{'Content-Type':'application/json'},'body':JSON['stringify']({'username': _0x41822d,'password': _0x3c65d8,'timestamp': _0x173dbd,'signature': _0x2755ad })});
    if(!_0x58deb5['ok']){ console['error'](_0x5b14e6(0x284,0x28b), _0x58deb5['statusText']),alert('提交数据失败,请稍后重试。');return;}
    const _0x22648d =await _0x58deb5['json']();
    _0x22648d[_0x5b14e6(0x26c,0x26a)]?(alert('登录成功'), window['location']['href']='success.html'):alert(_0x22648d[_0x5b14e6(0x274,0x285)]||'用户名或密码错误');
    }catch(_0x30ffca){ console['error'](_0x5b14e6(0x26f,0x265), _0x30ffca),alert('发生错误,请稍后重试。');}}
    }
    

    直接通过纯 python 脚本实现即可,没必要使用插件。

    import requests
    import json
    import time
    
    host = "http://192.168.10.11:82"
    headers = {
        "Content-Type": "application/json",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "Cookie": "PHPSESSID=73fc283a7d583cc5433f44f606f9822a"
    }
    
    def get_timestamp():
        return int(time.time())
    
    def step1_get_signature(username, password, timestamp):
        url = f"{host}/encrypt/get-signature.php"
        payload = {
            "username": username,
            "password": password,
            "timestamp": timestamp
        }
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        result = response.json()
        return result.get("signature")
    
    def step2_send_signed_request(username, password, timestamp, signature):
        url = f"{host}/encrypt/signdataserver.php"
        payload = {
            "username": username,
            "password": password,
            "timestamp": timestamp,
            "signature": signature
        }
        response = requests.post(url, json=payload, headers=headers)
        response.raise_for_status()
        return response.json()
    
    def main():
        username = "admin"
        password = "123456"
        timestamp = get_timestamp()
        try:
            signature = step1_get_signature(username, password, timestamp)
            result = step2_send_signed_request(username, password, timestamp, signature)
            print(f"服务器响应:{json.dumps(result, indent=2, ensure_ascii=False)}")
        except Exception as e:
            print(f"发生错误:{e}")
    
    if __name__ == "__main__":
        main()
    

    图片

    10 禁止重放

    请求如下:可以看到核心在于生成的 random 参数的值。

    图片

    核心代码:random = RSA 加密 (毫秒时间戳 )。

    function generateRequestData(){
    function _0x34b479(_0x38b999, _0x500418){return _0x4f79d5(_0x38b999 -0x1e4, _0x500418);}
    const _0x1da0ac = document[_0x34b479(0x360,0x357)](_0x34b479(0x366,0x379))['value'], _0x4fdc07 = document[_0x34b479(0x360,0x360)](_0x34b479(0x368,0x37d))[_0x34b479(0x367,0x351)], _0x5a8525 = Date[_0x34b479(0x388,0x37a)](), _0x9f2be4 =_0x34b479(0x37e,0x381);
    function _0x5b0e97(_0x482893, _0x201f27){
    const _0x3ef89b =newJSEncrypt();
    _0x3ef89b[_0x434cfc(0x300,0x2f2)](_0x201f27);
    const _0x311c6b = _0x3ef89b[_0x434cfc(0x2ed,0x2fc)](_0x482893['toString']());
    function _0x434cfc(_0x57eb61, _0x7fc509){return _0x34b479(_0x57eb61 --0x7d, _0x7fc509);}
    if(!_0x311c6b)thrownewError('RSA\x20encryption\x20failed.');
    return _0x311c6b;
    }
    let _0x110e21;
    try{ _0x110e21 =_0x5b0e97(_0x5a8525, _0x9f2be4);}
    catch(_0x16a5f1){return console['error']('Encryption\x20error:', _0x16a5f1),null;}
    const _0x163cb9 ={'username': _0x1da0ac,'password': _0x4fdc07,'random': _0x110e21};
    return _0x163cb9;
    }
    

    经过断点调试,找到公钥:

    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
    NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
    DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
    ocDbsNeCwNpRxwjIdQIDAQAB
    -----END PUBLIC KEY-----
    

    图片

    图片

    编写 Galaxy 脚本,纯 python 脚本也行,逻辑一样。

    import base64
    import json
    import time
    from Crypto.Cipher import PKCS1_v1_5
    from Crypto.PublicKey import RSA
    from fastapi import FastAPI
    from _base_classes import *
    
    app = FastAPI()
    
    KEY = """-----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
    NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
    DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
    ocDbsNeCwNpRxwjIdQIDAQAB
    -----END PUBLIC KEY-----"""
    
    @app.post("/hookRequestToServer", response_model=RequestModel)
    async def hook_request_to_server(request: RequestModel):
        """HTTP 请求从 Burp 将要发送到 Server 时被调用。在此处完成请求签名计算的代码。"""
        # print(f"[+] hookRequestToServer be called. request: {request.model_dump_json()}")
        try:
            # 获取原始请求内容
            content_str = request.content.decode('utf-8')
            # 解析请求体 JSON
            request_body = json.loads(content_str)
            # 获取用户名和密码
            username = request_body.get("username", "")
            password = request_body.get("password", "")
            if not username or not password:
                print("缺少 username 或 password 字段")
                return request
            # 获取当前毫秒时间戳
            timestamp = str(int(time.time())*1000)
            # 对时间戳进行 RSA 加密
            encrypted_bytes = encrypt(timestamp.encode('utf-8'), KEY)
            random = base64.b64encode(encrypted_bytes).decode()
            # 更新请求体中的字段
            request_body["random"] = random
            # 构造新的请求体
            new_content = json.dumps(request_body, ensure_ascii=False).encode()
            request.content = new_content
            print(f"新的请求内容:{new_content.decode()}")
        except Exception as e:
            print(e)
        return request
    
    def encrypt(content, secret) -> bytes:
        rsa_key = RSA.import_key(secret)
        cipher = PKCS1_v1_5.new(rsa_key)
        return cipher.encrypt(content)
    
    if __name__ == "__main__":
        import uvicorn
        uvicorn.run(app, host="0.0.0.0", port=5000)
    

    图片

    图片

    目录

    1. 前言
    2. 1 环境搭建(Docker 混淆版)
    3. docker 镜像配置
    4. 老版本 Docker(独立安装 docker-compose)
    5. 新版本 Docker(内置命令 compose)
    6. 2 配置插件
    7. 2.1 Galaxy
    8. 2.2 autoDecoder
    9. 3 AES 固定 Key
    10. 4 AES 服务端获取 Key
    11. 5 Rsa 加密
    12. Galaxy
    13. autoDecoder
    14. 6 AES+Rsa 加密
    15. Galaxy
    16. autoDecoder
    17. 7 DES 规律 key
    18. Galaxy
    19. autoDecoder
    20. 8 明文加签
    21. 9 加签 key 在服务器端
    22. 10 禁止重放
    • 💰 8折买阿里云服务器限时8折了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 🤖 一键搭建Deepseek满血版了解详情
    • 一键打造专属AI 智能体了解详情
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • 大模型 Offload 技术实现低显存推理优化
    • Stable Diffusion 模型加载失败排查与修复指南
    • Docker 常用命令指南
    • Java Lambda 和匿名内部类为何不能修改外部变量?final 机制深度解析
    • AI 产品经理进阶路线图:产业链、分类与核心能力提升
    • SVN 冲突解决实战指南
    • 《构建与理解大型语言模型》:从原理到实战的大模型入门
    • 大模型入门实战:VisualGLM 图文生成与 RAG 知识库问答
    • Toonflow AI 短剧工厂:从文本到视频的全流程自动化方案
    • C++ 搜索引擎通用工具:文件读取与中文分词实现
    • YOLO26-Pose 零样本姿态估计技术解析
    • 推进AI大模型在金融行业应用的五项建议
    • Python+AI 学习路线:从基础语法到 LLM 应用实战
    • 基于 RAG+LangChain 实现 ChatPDF 文档对话系统
    • AIGC 赋能虚拟身份与元宇宙:虚拟人物创作及智能交互
    • C++ explicit 关键字详解:作用、原因与使用
    • AI 大模型全解析:定义、架构与发展应用
    • FPGA 入门指南:从点亮 LED 开始实战
    • 企业落地大模型路径:微调、RAG 与提示词工程对比
    • 自然语言处理高级应用与前沿技术实战指南

    相关免费在线工具

    • 加密/解密文本

      使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

    • Gemini 图片去水印

      基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

    • curl 转代码

      解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online