跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
|注册
博客列表

目录

  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 禁止重放
Python大前端算法

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

介绍 encrypt-labs 前端加密靶场的搭建与破解流程。通过 Docker 部署环境,利用 BurpSuite 插件 Galaxy 和 autoDecoder 拦截并处理 HTTP 请求。详细解析了 AES 固定 Key、服务端动态获取 Key、RSA 加密、AES+RSA 混合加密、DES 规律 Key、明文加签及服务器端签名等关卡的逆向逻辑与 Python 脚本实现,旨在帮助读者掌握前端加密防护原理与爆破技巧。

极光发布于 2026/4/5更新于 2026/4/130 浏览
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 个方法。

  1. HTTP 请求从客户端到达 Burp 时被触发。你需要在此处完成请求解密的代码,这样就可以在 Burp 中看到明文的请求报文。
  2. HTTP 请求从 Burp 将要发送到 Server 时被触发。你需要在此处完成请求加密的代码,这样就可以将加密后的请求报文发送到 Server。
  3. HTTP 响应从 Server 到达 Burp 时被触发。你需要在此处完成响应解密的代码,这样就可以在 Burp 中看到明文的响应报文。
  4. 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:  = parse_qs(request.content.decode())[][].encode()
    
    encryptedData:  = encrypt(data)
    ()
    
    request.content = urlencode({: base64.b64encode(encryptedData)}).encode()
     request


  ():
     response


  ():
     response

 () -> :
    cipher = AES.new(KEY, AES.MODE_CBC, IV)
     unpad(cipher.decrypt(content), AES.block_size)

 () -> :
    cipher = AES.new(KEY, AES.MODE_CBC, IV)
     cipher.encrypt(pad(content, AES.block_size))

 () -> :
    body_json: t. = json.loads(content)
     base64.b64decode(body_json[JSON_KEY])

 () -> :
    body_json = {}
    body_json[JSON_KEY] = base64.b64encode(contnet).decode()
     json.dumps(body_json).encode()

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

然后可以在 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:  = request.content
    
    encryptedData:  = encrypt(data)
    
    body:  = to_data(encryptedData)
    ()
    
    request.content = body
     request


  ():
     response


  ():
     response

 () -> :
    cipher = AES.new(KEY, AES.MODE_CBC, IV)
     unpad(cipher.decrypt(content), AES.block_size)

 () -> :
    cipher = AES.new(KEY, AES.MODE_CBC, IV)
     cipher.encrypt(pad(content, AES.block_size))

 () -> :
    body_json: t. = json.loads(content)
     base64.b64decode(body_json[JSON_KEY])

 () -> :
    body_json = {}
    body_json[JSON_KEY] = base64.b64encode(contnet).decode()
     json.dumps(body_json).encode()

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

启动后将加密请求发送到 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 编码;
  • 注意公钥书写的格式, 手动换行;
  • 提取请求的参数 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(), pub_key)
            
            encrypted_b64 = base64.b64encode(encrypted_data).decode()
            
            encrypted_url_encoded = quote_plus(encrypted_b64)
            
            new_content = 
            ()
            
            request.content = new_content.encode()
        :
            ()
     Exception  e:
        ()
        
     request

 () -> :
    rsa_key = RSA.import_key(secret)
    cipher = PKCS1_v1_5.new(rsa_key)
     cipher.encrypt(content)

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

启动脚本后,通过构造 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: ")
                    
                    encrypted_data_bytes = original_encrypted_data.encode()
                 json.JSONDecodeError:
                    
                    ()
                    encrypted_data_bytes = original_encrypted_data.encode()
            :
                
                encrypted_data_bytes = (original_encrypted_data).encode()
            
            encryptedData1:  = aes_encrypt(encrypted_data_bytes)
            
            request_json[JSON_KEY1] = base64.b64encode(encryptedData1).decode()
            
            body:  = json.dumps(request_json, ensure_ascii=).encode()
            encrypted_json_str = body.decode()
            ()
            request.content = body
        :
            ()
     Exception  e:
        ()
     request

 () -> :
    cipher = AES.new(KEY, AES.MODE_CBC, IV)
     cipher.encrypt(pad(content, AES.block_size))

 () -> :
    rsa_key = RSA.import_key(secret)
    cipher = PKCS1_v1_5.new(rsa_key)
     cipher.encrypt(content)

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

启动编写的脚本,将加密请求发送到 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')
        ()
        
        request_body[] = password_decrypted
        request.content = json.dumps(request_body, ensure_ascii=).encode()
     Exception  e:
        ()
     request


  ():
    
    
    :
        
        request_body = json.loads(request.content.decode())
        username = request_body.get(, )
        password_decrypted = request_body.get(, )
          username   password_decrypted:
            ()
             request
        
         KEY, IV
        KEY, IV = generate_key_iv(username)
        ()
        
        password_bytes = password_decrypted.encode()
        encrypted_bytes = encrypt(password_bytes)
        
        password_encrypted = encrypted_bytes.()
        ()
        
        request_body[] = password_encrypted
        
        request.content = json.dumps(request_body, ensure_ascii=).encode()
     Exception  e:
        ()
     request

 () -> [, ]:
    
    
    username_prefix = username[:]
    key = username_prefix.ljust(, ).encode()
    
    username_prefix_4 = username[:]
    iv_str =  + username_prefix_4.ljust(, )
    iv = iv_str.encode()
     key, iv

 () -> :
    cipher = DES.new(KEY, DES.MODE_CBC, IV)
     unpad(cipher.decrypt(content), DES.block_size)

 () -> :
    cipher = DES.new(KEY, DES.MODE_CBC, IV)
     cipher.encrypt(pad(content, DES.block_size))

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

在 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}"
        
        signature = hmac.new(
            secret_key.encode(),
            sign_text.encode(),
            hashlib.sha256
        ).hexdigest()
        
        request_body[] = nonce
        request_body[] = timestamp
        request_body[] = signature
        
        new_content = json.dumps(request_body, ensure_ascii=).encode()
        request.content = new_content
        ()
     json.JSONDecodeError  e:
        ()
         request
     Exception  e:
        ()
         request
     request

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

发送请求时记得添加请求头: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 =await fetch(_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[](, _0x55d2c7[]),();;}
{: _0x2755ad}= _0x55d2c7[(,)]();
(!_0x2755ad){();;}
 _0x58deb5 = (+ _0xb4476b,{:,:{:},:[]({: _0x41822d,: _0x3c65d8,: _0x173dbd,: _0x2755ad })});
(!_0x58deb5[]){ []((,), _0x58deb5[]),();;}
 _0x22648d = _0x58deb5[](); _0x22648d[(,)]?((), [][]=):(_0x22648d[(,)]||);
}(_0x30ffca){ []((,), _0x30ffca),();}
}

直接通过纯 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)
        ()
     Exception  e:
        ()

 __name__ == :
    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 = new JSEncrypt();
_0x3ef89b[_0x434cfc(0x300,0x2f2)](_0x201f27);
const _0x311c6b = _0x3ef89b[_0x434cfc(0x2ed,0x2fc)](_0x482893['toString']());
function _0x434cfc(_0x57eb61, _0x7fc509){return _0x34b479(_0x57eb61 --, _0x7fc509);}
(!_0x311c6b)   ();
 _0x311c6b;
}
 _0x110e21;
{ _0x110e21 =(_0x5a8525, _0x9f2be4);}
(_0x16a5f1){ [](, _0x16a5f1),;}
 _0x163cb9 ={: _0x1da0ac,: _0x4fdc07,: _0x110e21};
 _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(), KEY)
        random_val = base64.b64encode(encrypted_bytes).decode()
        
        request_body[] = random_val
        
        new_content = json.dumps(request_body, ensure_ascii=).encode()
        request.content = new_content
        ()
     Exception  e:
        (e)
     request

 request

 () -> :
    rsa_key = RSA.import_key(secret)
    cipher = PKCS1_v1_5.new(rsa_key)
     cipher.encrypt(content)

 __name__ == :
     uvicorn
    uvicorn.run(app, host=, port=)

在这里插入图片描述

在这里插入图片描述

极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 前端数据可视化工具对比与选型指南
  • 基于 Microi 低代码框架构建 Vue 高效应用指南
  • Ubuntu 24.04 国内镜像源配置及一键脚本(含清华/阿里云/163 源)
  • Ubuntu 国内镜像源更换指南:阿里/清华/中科大对比
  • 基于 Three.js 渲染三维无人机模型(WebGL / Vue / React)
  • 量化、算子融合、内存映射:C 语言实现 AI 推理优化
  • 单 Agent 与多 Agent 系统架构对比及选型指南
  • 基于 Claude 大模型与前端设计规则的可上线 UI 生成工作流
  • AI Prompt 工程指南:提示词设计原则与实战技巧
  • Z-Image-Turbo 模型部署与 AI 绘画效率优化
  • PX4+ROS 无人机 Offboard 控制模式解析与实战
  • libwebkit2gtk-4.1-0 安装全流程与配置说明
  • GitHub 十大 Claude Skills 推荐与配置指南
  • OpenClaw self-improving-agent 技能详解:实现 AI 持续自我改进
  • AI 实践:Token 与上下文窗口
  • Harness 工程:构建 AI 智能体可靠运行的系统指南
  • OpenClaw 功能、Ubuntu 部署、扩展与 AI Native 架构借鉴
  • 高效AIGC工具推荐:10个热门平台免费与付费功能全指南
  • 昇腾 NPU 运行 Llama 模型:环境搭建与性能测试
  • 基于 SpringBoot、Vue、Netty 与 WebRTC 的视频聊天实现

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,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

  • HTML 转 Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online

bytes
"encryptedData"
0
# 调用函数加密回去
bytes
print
f"[DEBUG] 加密后的数据:{base64.b64encode(encryptedData)}"
# 更新 query
"encryptedData"
return
@app.post("/hookResponseToBurp", response_model=ResponseModel)
async
def
hook_response_to_burp
response: ResponseModel
return
@app.post("/hookResponseToClient", response_model=ResponseModel)
async
def
hook_response_to_client
response: ResponseModel
return
def
decrypt
content: bytes
bytes
return
def
encrypt
content: bytes
bytes
return
def
get_data
content: bytes
bytes
Dict
return
def
to_data
contnet: bytes
bytes
return
if
"__main__"
import
"0.0.0.0"
5000
bytes
# 调用函数加密回去
bytes
# 将已加密的数据转换为 Server 可识别的格式
bytes
print
f"[DEBUG] 加密后的数据:{base64.b64encode(encryptedData)}"
# 更新 body
return
@app.post("/hookResponseToBurp", response_model=ResponseModel)
async
def
hook_response_to_burp
response: ResponseModel
return
@app.post("/hookResponseToClient", response_model=ResponseModel)
async
def
hook_response_to_client
response: ResponseModel
return
def
decrypt
content: bytes
bytes
return
def
encrypt
content: bytes
bytes
return
def
get_data
content: bytes
bytes
Dict
return
def
to_data
contnet: bytes
bytes
return
if
"__main__"
import
"0.0.0.0"
5000
'utf-8'
# Base64 编码
'utf-8'
# URL 编码
# 构造新的请求内容
f"data={encrypted_url_encoded}"
print
f"[DEBUG] 加密后的数据:{new_content}"
# 更新请求内容
'utf-8'
else
print
"[WARNING] 请求中未找到指定参数"
except
as
print
f"[ERROR] 处理请求时出错:{e}"
pass
return
def
encrypt
content: bytes, secret: bytes
bytes
return
if
"__main__"
import
"0.0.0.0"
5000
{inner_json}
# 重新序列化为字符串用于加密
except
# 如果不是有效的 JSON 字符串,直接使用原字符串
print
"encryptedData 不是有效的 JSON 格式,直接使用原值"
else
# 如果不是字符串,转换为字符串
str
# 对 encryptedData 进行 AES 加密
bytes
# 更新 encryptedData 参数的值
# 构造新的请求体
bytes
False
print
f"[DEBUG] 修改后的数据:{encrypted_json_str}"
else
print
f"未找到 {JSON_KEY1} 参数"
except
as
print
f"处理错误:{e}"
return
def
aes_encrypt
content: bytes
bytes
return
def
rsa_encrypt
content: bytes, secret: bytes
bytes
return
if
"__main__"
import
"0.0.0.0"
5000
print
f"解密后的 password: {password_decrypted}"
# 更新请求体
"password"
False
except
as
print
f"解密过程出错:{e}"
return
@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 应该是明文)
"username"
""
"password"
""
if
not
or
not
print
"缺少 username 或 password 字段"
return
# 生成 KEY 和 IV
global
print
f"[+] 生成的 KEY: {KEY}, IV: {IV}"
# 使用现有的 encrypt 方法加密 password
'utf-8'
# 转换为十六进制字符串
hex
print
f"加密后的 password: {password_encrypted}"
# 只更新 password 字段
"password"
# 构造新的请求体
False
except
as
print
f"加密过程出错:{e}"
return
def
generate_key_iv
username: str
tuple
bytes
bytes
""" 根据用户名生成 KEY 和 IV KEY: 用户名截取前 8 位(0 开始),不足补字符'6'到 8 位 IV: 固定前缀'9999' + 用户名前 4 位(0 开始),不足补字符'9'到 8 位 """
# 生成 KEY
8
8
'6'
# 生成 IV
4
"9999"
4
'9'
return
def
decrypt
content: bytes
bytes
return
def
encrypt
content: bytes
bytes
return
if
"__main__"
import
"0.0.0.0"
5000
{timestamp}
# 计算 HmacSHA256 签名
'utf-8'
'utf-8'
# 更新请求体中的字段
"nonce"
"timestamp"
"signature"
# 构造新的请求体
False
print
f"新的请求内容:{new_content.decode()}"
except
as
print
f"JSON 解析错误:{e}"
return
except
as
print
f"签名计算过程出错:{e}"
return
return
if
"__main__"
import
"0.0.0.0"
5000
'error'
'获取签名失败:'
'statusText'
alert
'获取签名失败,请稍后重试。'
return
const
signature
await
_0x5b14e6
0x26b
0x279
if
alert
'签名获取失败,服务器未返回签名。'
return
const
await
fetch
''
'method'
'POST'
'headers'
'Content-Type'
'application/json'
'body'
JSON
'stringify'
'username'
'password'
'timestamp'
'signature'
if
'ok'
console
'error'
_0x5b14e6
0x284
0x28b
'statusText'
alert
'提交数据失败,请稍后重试。'
return
const
await
'json'
_0x5b14e6
0x26c
0x26a
alert
'登录成功'
window
'location'
'href'
'success.html'
alert
_0x5b14e6
0x274
0x285
'用户名或密码错误'
catch
console
'error'
_0x5b14e6
0x26f
0x265
alert
'发生错误,请稍后重试。'
print
f"服务器响应:{json.dumps(result, indent=2, ensure_ascii=False)}"
except
as
print
f"发生错误:{e}"
if
"__main__"
0x7d
if
throw
new
Error
'RSA\x20encryption\x20failed.'
return
let
try
_0x5b0e97
catch
return
console
'error'
'Encryption\x20error:'
null
const
'username'
'password'
'random'
return
'utf-8'
# 更新请求体中的字段
"random"
# 构造新的请求体
False
print
f"新的请求内容:{new_content.decode()}"
except
as
print
return
return
def
encrypt
content, secret
bytes
return
if
"__main__"
import
"0.0.0.0"
5000