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

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

详细讲解了 encrypt-labs 靶场的搭建与全关卡解析。涵盖环境部署、BurpSuite 插件配置(Galaxy 与 autoDecoder),以及 AES 固定 Key、AES 服务端获取 Key、RSA 加密、AES+RSA 组合加密、DES 规律 Key、明文加签、服务端加签和禁止重放等常见前端加密场景的逆向分析与绕过方案。通过实际代码示例,演示了如何利用 Python 脚本拦截请求、解密参数并构造合法请求,帮助读者深入理解前端加密防护原理及对应的渗透测试技巧。

全栈工匠发布于 2026/4/7更新于 2026/10/26108 浏览
前端加密攻防实战:encrypt-labs 靶场环境搭建与通关解析

前言

在 Web 安全测试中,为了抵御暴力破解,开发人员常在前端对关键参数(如签名、密码)进行加密处理。这增加了爆破的技术门槛,但也留下了逆向分析的空间。

"encrypt-labs" 是一个专门针对前端加密场景的练习靶场。我们需要先分析前端的加密逻辑,掌握常用的解密和逆向手法,再构造符合服务端验证规则的请求,以此完成渗透练习,深入理解前端加密防护的核心原理。

环境搭建

基于 Ubuntu 24.04.3 TLS 环境进行部署。

git clone https://github.com/Ta0ing/encrypt-labs-docker.git
cd src
sudo vim database.php

修改数据库配置如下:

$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。

登录界面

插件配置

配置 BurpSuite 插件的目的是为了在抓包时直接查看明文或自动加解密,从而更直观地进行爆破。如果不使用插件,完全可以通过脚本实现请求的加解密。

Galaxy 插件

安装地址:https://github.com/outlaws-bai/Galaxy

该插件支持通过 Hook 机制拦截请求和响应。下载脚本示例代码便于独立开发:

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

提供的模板包括基础 JSON 处理 (aes_cbc.py)、表单处理 (aes_cbc_form.py) 和查询参数处理 (aes_cbc_query.py)。遇到 HTTP 参数加密时,可依据上述模板修改。

核心围绕四个 Hook 方法:

  1. hookRequestToBurp:客户端到 Burp 时触发,用于解密请求报文。
  2. hookRequestToServer:Burp 发送到 Server 时触发,用于加密请求报文。
  3. hookResponseToBurp:Server 到 Burp 时触发,用于解密响应报文。
  4. hookResponseToClient:Burp 返回 Client 时触发,用于加密响应报文。

autoDecoder

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

AES 固定 Key

使用火狐浏览器的'栈跟踪'功能查看调用的 JS 代码。定位到 sendDataAes 函数,可以看到它使用了 AES 加密用户名和密码。

调试栈跟踪

如果是 Chrome 浏览器,只能看发起时的 JS 文件。继续调试 app.js,代码经过混淆,可以在点击处打断点。

断点调试

点击登录后,自动定位到 sendDataAes 函数。分析可知:

  • 算法:AES-CBC
  • 密钥 (Key):固定 16 位字符串 1234567890123456 (Utf8 编码)
  • 偏移量 (IV):固定 16 位字符串 1234567890123456 (Utf8 编码)
  • 填充:PKCS7
  • 输出:Base64 编码

传输方式为 application/x-www-form-urlencoded,参数名为 encryptedData。

接下来编写 Galaxy 脚本进行解密。复制 aes_cbc_form.py 模板,修改 KEY、IV 的值,并将参数名改为 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):
    # 获取需要解密的数据
    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):
    # 获取被解密的数据
    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 请求中尝试解密。注意不勾选 Hook Response,因为响应内容是明文。request.host 填入靶机 IP。

Galaxy 配置

解密后可见明文。这里弹出了 URL 编码后的结果,注意 X-Galaxy-Http-Hook: HookedRequest 标识是 Galaxy 插件识别的关键。

解密结果

如果觉得手动解码麻烦,可以将请求发送到 Repeater 模块,利用 Inspector 功能自动解码。

Repeater 解码

修改输入明文,观察插件是否自动加密发送。可以看到 hookRequestToServer 将明文加密后发送给服务端。

自动加密

后续爆破步骤与普通爆破一致,将解密后端请求添加到 Intruder 模块即可。

AES 服务端获取 Key

此关卡的 Key 和 IV 不是固定的,而是从服务端动态获取。多次请求可以看到这两个值是固定的 Base64 编码。

获取 Key

发送加密请求后,响应存在 Unicode 编码,使用 Python print 解码可得错误提示。

通过分析栈跟踪,确定加密方式:

  • 请求格式:POST + application/json + encryptedData 的 JSON 体
  • 加密方式:AES-CBC + PKCS7 填充 + Base64 输出
  • 加密参数:Key/IV 从后端动态获取(Base64 解码后使用),长度均为 16 字节

复制模板中的 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):
    # 获取需要解密的数据
    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):
    # 获取被解密的数据
    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 模块进行解密,成功解密后修改密码请求即可发送成功。

RSA 加密

请求方式为 POST + 表单格式。明文是账号密码 JSON 串,加密后为 Base64 格式的 RSA 密文。使用 RSA 非对称加密,PKCS#1 v1.5 填充,公钥硬编码在代码中。

Galaxy 方案

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

  • 本题不知道解密的私钥,只能尝试进行请求的加密。
  • 需要对加密后的结果进行 URL 编码。
  • 注意公钥书写的格式, 需手动换行。
  • 提取请求的参数 JSON_KEY 是 data。
  • 需要对 BurpSuite 请求添加请求头 X-Galaxy-Http-Hook: HookedRequest。
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):
    # 获取请求内容
    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。

autoDecoder 方案

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

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

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRvA7giwinEkaTYllDYCkzujvi
NH+up0XAKXQot8RixKGpB7nr8AdidEvuo+wVCxZwDK3hlcRGrrqt0Gxqwc11btlM
DSj92Mr3xSaJcshZU8kfj325L8DRh9jpruphHBfh955ihvbednGAvOHOrz3Qy3Cb
ocDbsNeCwNpRxwjIdQIDAQAB

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

AES+RSA 加密

此关卡结合了 AES 和 RSA。结构如下:

{
"encryptedData":"AES 加密后的用户名 + 密码 JSON 字符串",
"encryptedKey":"RSA 加密后的 AES key(Base64 格式)",
"encryptedIv":"RSA 加密后的 AES iv(Base64 格式)"
}

思路是替换 encryptedData 的内容,因此需要进行 AES 解密。但 AES 的 key 和 iv 被 RSA 公钥加密了,无法直接获取。解决方案是利用 Chrome 浏览器的 Override Content 功能,将 app.js 下载到本地,修改代码中随机生成的 key 和 iv 为固定值(例如 1234567890123456),然后保存。

修改后的代码片段:

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

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

Galaxy 方案

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

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())
        # 只修改 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"},实战中可以对这里进行爆破。

DES 规律 Key

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

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

一句话总结:通过用户名获取 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):
    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):
    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
    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 工具只能爆破固定用户名的密码。

明文加签

核心代码分析如下:

  • 签名算法: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):
    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。

加签 Key 在服务器端

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

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

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

禁止重放

请求的核心在于生成的 random 参数的值。

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

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

-----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):
    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

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. 环境搭建
  3. 内容示例
  4. 老版本 Docker-compose
  5. 新版本 Docker (内置 compose)
  6. 插件配置
  7. Galaxy 插件
  8. autoDecoder
  9. AES 固定 Key
  10. AES 服务端获取 Key
  11. RSA 加密
  12. Galaxy 方案
  13. autoDecoder 方案
  14. AES+RSA 加密
  15. Galaxy 方案
  16. autoDecoder 方案
  17. DES 规律 Key
  18. Galaxy 方案
  19. autoDecoder 方案
  20. 明文加签
  21. 加签 Key 在服务器端
  22. 禁止重放

更多推荐文章

查看全部
  • 基于 Web Unlocker 与 n8n 的自动化资讯采集与推送实践
  • C++ 类型转换详解:显式运算符与底层机制
  • PyQT 结合 YOLOv8n 的沥青路面裂缝病害识别系统
  • 本地化部署与使用免费的 LLM 应用工程化平台 Langfuse
  • 19 款网络安全攻防演练与渗透测试在线平台精选
  • Stack-Chan机器人完整入门指南:从零开始构建你的可爱机器人伙伴
  • SpringBoot 低代码 JSON 表单引擎与审批流实现
  • 接入第三方 OpenAI 兼容模型到 GitHub Copilot
  • AI 视频生成实战:使用扣子 SKILL 与 Seedance 2.0 制作产品宣传片
  • 2026 前端跨端框架选型指南
  • MySQL 内置函数实战指南:日期、字符串与数学运算
  • Java WebSocket 核心原理与实战应用
  • 大模型 Agent 开发指南:基于 LangChain 的实战应用
  • 基于 STM32 的智能家居安防系统设计与实现
  • 大模型技术原理详解:从 Transformer 到 RLHF
  • Python vs C++ 极简性能对比
  • Docker 部署 DeskClaw:构建本地人机协同办公平台
  • 深入理解 Agentic AI:概念、架构及与 AIGC 的区别
  • OpenWebUI 集成 SearXNG 实现本地大模型联网搜索
  • RabbitMQ 消费端限流:basicQos 配置实例与经验

相关免费在线工具

  • 加密/解密文本

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