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

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

综述由AI生成encrypt-labs 前端加密靶场的完整攻防流程。首先通过 Docker 搭建靶场环境,并配置 BurpSuite 插件(Galaxy、autoDecoder)辅助加解密。随后详细解析了十种常见加密场景:包括 AES 固定 Key、服务端获取 Key、RSA 加密、AES+RSA 混合加密、DES 规律 Key、明文加签、服务端加签及禁止重放机制。文章提供了具体的 Python 脚本实现方案,帮助安全研究人员掌握前端加密逻辑分析与绕过技巧。

松间照月发布于 2026/4/6更新于 2026/5/2219 浏览
前端加密 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

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 = 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['error']('获取签名失败:', _0x55d2c7['statusText']),alert('获取签名失败,请稍后重试。');
             return;
        }
        const {signature: _0x2755ad}=await _0x55d2c7[_0x5b14e6(0x26b,0x279)]();
        if(!_0x2755ad){
            alert('签名获取失败,服务器未返回签名。');
            return;
        }
        const _0x58deb5 = await fetch(''+ _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 = new JSEncrypt();
        _0x3ef89b[_0x434cfc(0x300,0x2f2)](_0x201f27);
        const _0x311c6b = _0x3ef89b[_0x434cfc(0x2ed,0x2fc)](_0x482893['toString']());
        function _0x434cfc(_0x57eb61, _0x7fc509){
            return _0x34b479(_0x57eb61 --0x7d, _0x7fc509);
        }
        if(!_0x311c6b) throw new Error('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_val = base64.b64encode(encrypted_bytes).decode()
        # 更新请求体中的字段
        request_body["random"] = random_val
        # 构造新的请求体
        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

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

更多推荐文章

查看全部
  • Python+AI 学习路线:从基础到实战
  • 基于C++的嵌入式AI模块化架构设计全流程
  • Python 打造 AI 三剑客:文档总结、代码生成与智能检索
  • 仓库管理系统前端开发:主区域查询与重置功能
  • C 语言指针与数组的核心关系及实战应用
  • OpenClaw 上下文记忆短问题:Token 限制分析与 6 种扩容方案
  • Python 爬虫从零入门:豆瓣电影数据抓取实战指南
  • AI 产品经理面试指南:核心能力、技术问答与项目实战
  • Seedance 2.0 实操教程:从入门到 AI 导演模式
  • GitNexus 核心引擎深度解析
  • Oracle 索引核心原理、类型详解与创建实战
  • Claude Code 模型配置详解
  • AI 数据准备:EasyLink 多模态非结构化数据处理方案
  • 基于 n8n 与网页解锁服务的自动化资讯采集实战
  • 全栈毕业设计实战:前后端分离架构与核心实现指南
  • AMD 显卡运行 ComfyUI-Zluda 配置与优化指南
  • RAG 技术为何对下一代 AI 开发至关重要
  • llama.cpp 实战指南:普通电脑运行大模型方案
  • 使用 Cpolar 和 JuiceSSH 远程连接内网 Linux 虚拟机
  • PHP 项目开发流程与配置指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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