找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4908

积分

0

好友

676

主题
发表于 昨天 03:13 | 查看: 12| 回复: 0

最近,我主导实现了一套请求加解密机制,虽然提升了安全性,但也给团队排查问题时的抓包分析带来了障碍。为了让后续工作更顺畅,我决定在Burp Suite上找到一个方案,能够像以前一样直接查看明文返回结果。

我主要使用Burp Suite,它支持插件扩展。理论上,自己写一个插件也是可行的,但本着效率优先的原则,我决定在现有的优秀插件中进行选型。

一、插件选型:为什么是Galaxy?

在评估了市面上几款主流插件后,我制作了下面的对比表格:

插件名称 特点与适用场景 获取方式
MITM Decryption (Galaxy) 功能最全面,支持多种语言编写解密逻辑,内置大量加解密算法示例,适合应对复杂的加密场景。 BApp Store / GitHub
autoDecoder 灵活的自定义解密插件,可配置外部脚本或程序来处理数据包,适合需要自定义解密逻辑的渗透测试场景。 GitHub
Burpy 专注于 JS 逆向场景,支持调用 Python 和 Java 脚本,特别适合处理前端加密的 Web 应用。 GitHub
iCrypto 轻量级的自定义加解密插件,通过调用外部脚本来实现请求和响应的解密,易于上手。 GitHub
PyCript 灵活性高,支持使用 Python、Node.js 等多种语言编写解密逻辑,能自动处理请求头和 Body 中的密钥。 GitHub
AES-Killer 专为 AES-CBC 模式流量设计的“傻瓜式”解密插件,只需填入密钥和 IV,适合目标明确的场景。 GitHub

我的原则是,要么不用,要用就用最好的。在查看了上述项目后,发现好几个项目已多年未更新。最终,我选择了 MITM Decryption (Galaxy)

为什么是 Galaxy?

对于大部分需要处理加密流量的场景,Galaxy 堪称一站式解决方案。它直接上架了 Burp 官方的 BApp Store,在 Extender 标签页中就能搜索安装,非常便捷。

它的优点非常突出:

  • 功能强大:支持 AES、DES、RSA、SM2、SM4 等多种算法,并能处理动态密钥等复杂情况。
  • 语言灵活:你可以用 Java、Python、JavaScript 这三种语言来编写自己的解密逻辑(官方称之为 “Hook”),灵活度极高。
  • 无缝集成:解密过程是全自动的,对 Repeater、Intruder 等核心模块透明。你在 Burp 中看到的是解密后的明文,修改后发送时,Galaxy 会自动帮你重新加密,不影响与服务器的正常交互。

Galaxy 由社区开发者 outlaws-bai 维护,其核心功能包括:

  • 🤖 自动化加解密:一处配置,即可自动处理所有经过代理的流量(Proxy/Repeater/Intruder/Scanner 均支持)。
  • 🛠️ 内置实用工具:包含解析 Swagger API 文档、绕过 Host 检查等辅助功能。
  • 🔗 安全工具联动:可将解密后的请求直接发送给 sqlmap 或 xray 进行扫描。
  • 🎯 支持复杂场景:能应对加密与加签并存、动态密钥、算法组合等复杂逻辑。

二、实战:配置与编写Hook脚本

安装好 Galaxy 插件后,Burp 主界面会出现一个 Galaxy 标签页。

Burp Suite Galaxy插件Http Hook主界面

接下来是关键的实战步骤。

第一步:配置目标范围(关键步骤)

你需要告诉 Galaxy,只对特定的目标流量生效。例如,假设我的目标服务地址是 192.168.0.165:8088

  1. 在 Burp Suite 中,进入 Galaxy -> Http Hook
  2. Expression 输入框中,可以配置过滤表达式,例如 request.host='192.168.0.165' && request.port=8088。更精确的配置可以在 Filter 子标签页中设置目标主机和端口。

第二步:编写自定义AES解密Hook脚本

Galaxy 的强大之处在于其四个核心 Hook 函数,它们允许你精准控制流量的加解密流程:

  • hookRequestToBurp:请求刚到达 Burp 时调用,用于解密请求
  • hookRequestToServer:请求将发往服务器时调用,用于加密请求
  • hookResponseToBurp:响应刚到达 Burp 时调用,用于解密响应
  • hookResponseToClient:响应将发回客户端时调用,用于加密响应

在我的实际场景中,请求需要附加签名头,而整个响应体是一个经过 Base64 编码的 AES/ECB 密文。下面是我修改后的 AesEcb.java 脚本,核心逻辑仅约30行代码。

import org.m2sec.core.models.*;
import org.m2sec.shaded.slf4j.Logger;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class AesEcb {

    private static final String ALGORITHM = "AES/ECB/PKCS5Padding";
    private static final byte[] SECRET = "你的key".getBytes();

    private Logger log;

    public AesEcb(Logger log) {
        this.log = log;
    }

    // ==================== 请求方向 ====================
    // 请求到达 Burp:不做任何修改
    public Request hookRequestToBurp(Request request) {
        return request;
    }

    // 请求发送到服务器:生成签名并添加 headers
    public Request hookRequestToServer(Request request) {
        try {
            String method = request.getMethod();
            String path = request.getPath();
            // 去掉 query 参数(如果存在)
            int queryIdx = path.indexOf('?');
            String pathWithoutQuery = (queryIdx == -1) ? path : path.substring(0, queryIdx);

            // 生成时间戳(秒)和随机字符串
            long timestampSec = System.currentTimeMillis() / 1000;
            String timestamp = Long.toString(timestampSec);
            String nonce = generateNonce(16); // 16位随机字符串

            // 构造待签名字符串:method + pathWithoutQuery + timestamp + nonce
            String signString = method + pathWithoutQuery + timestamp + nonce;
            byte[] encrypted = aesEncrypt(signString.getBytes());
            String signature = Base64.getEncoder().encodeToString(encrypted);

            // 添加 headers
            request.getHeaders().put("X-Signature", signature);
            request.getHeaders().put("X-Timestamp", timestamp);
            request.getHeaders().put("X-Nonce", nonce);

        } catch (Exception e) {
            log.error("Request signature generation failed", e);
        }
        return request;
    }

    // ==================== 响应方向:整体解密 ====================
    // 响应从服务器到达 Burp:整个响应体是 Base64 密文 -> 解码 -> AES解密 -> 明文
    public Response hookResponseToBurp(Response response) {
        try {
            byte[] content = response.getContent();
            // 整个响应体当作 Base64 字符串解码
            byte[] encrypted = Base64.getDecoder().decode(content);
            byte[] plain = aesDecrypt(encrypted);
            response.setContent(plain);
        } catch (Exception e) {
            log.error("Response decryption failed (maybe not Base64 or invalid key)", e);
            // 解密失败时保持原样
        }
        return response;
    }

    // 响应从 Burp 发送到客户端:明文 -> AES加密 -> Base64编码 -> 作为整个响应体
    public Response hookResponseToClient(Response response) {
        try {
            byte[] plain = response.getContent();
            byte[] encrypted = aesEncrypt(plain);
            byte[] encryptedB64 = Base64.getEncoder().encode(encrypted);
            response.setContent(encryptedB64);
        } catch (Exception e) {
            log.error("Response encryption failed", e);
        }
        return response;
    }

    // ==================== 辅助方法 ====================
    private String generateNonce(int length) {
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int idx = (int) (Math.random() * chars.length());
            sb.append(chars.charAt(idx));
        }
        return sb.toString();
    }

    private byte[] aesDecrypt(byte[] encryptedData) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(SECRET, "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(encryptedData);
    }

    private byte[] aesEncrypt(byte[] plainData) throws Exception {
        SecretKeySpec keySpec = new SecretKeySpec(SECRET, "AES");
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(plainData);
    }
}

脚本逻辑简述:

  1. hookRequestToServer: 提取请求方法和路径,结合时间戳和随机数生成待签名字符串,用 AES/ECB 加密后生成 X-Signature 等头部。
  2. hookResponseToBurp: 将整个响应体进行 Base64 解码,然后用 AES/ECB 解密,得到明文响应。
  3. hookResponseToClient: 将明文响应加密并 Base64 编码后返回。

第三步:加载并启动Hook

  1. Http Hook 主界面,点击 Add
  2. Hook Type 选择 JavaHook Script 选择或创建你的 .java 文件(例如 AesEcb.java)。
  3. 点击 Start 按钮启动插件。

Galaxy Http Hook配置界面
Galaxy配置Java Hook脚本

启动后,效果立竿见影。原本密文的请求和响应,在 Burp 的 History 或 Repeater 中都已显示为明文。

出参加密效果:请求头包含X-Signature
出参解密效果:响应体显示为明文JSON

三、关键细节与排错指南

上面的流程是理想情况,实际使用中可能会遇到问题。以下是几个必须注意的核心细节和排错方法:

  1. JDK环境:插件(尤其是Java Hook)必须运行在完整的JDK环境下,而非JRE。很多Burp绿色启动器可能使用了精简环境。
  2. 查看完整日志:如果插件不生效,除了检查Burp的 Extender -> Errors 标签页,务必通过命令行启动Burp,因为控制台会输出更详细的错误堆栈信息。
  3. 版本匹配:确保你的JDK版本与插件兼容。

如何通过命令行(macOS/Linux)启动Burp以排查问题?

创建一个启动脚本(例如 start_burp.sh)是确保环境可控的好方法。

#!/bin/bash

# 设置你的 JDK 路径(请修改为你的实际路径)
JAVA_HOME="/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home"

# 设置 Burp Suite JAR 文件路径(请修改为你的实际路径)
BURP_JAR="/Applications/Burp Suite Professional.app/Contents/Resources/app/burpsuite_pro.jar"

# 使用指定的 JDK 启动 Burp Suite
"$JAVA_HOME/bin/java" \
  --add-opens=java.desktop/javax.swing=ALL-UNNAMED \
  --add-opens=java.base/java.lang=ALL-UNNAMED \
  --add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
  --add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \
  --add-opens=java.base/jdk.internal.org.objectweb.asm.Opcodes=ALL-UNNAMED \
  -javaagent:/path/to/your/agent.jar \ # 可选,根据实际情况
  -noverify \
  -jar "$BURP_JAR"

给脚本执行权限后运行:chmod +x start_burp.sh && ./start_burp.sh。通过这种方式启动,可以确保Burp运行在正确的JDK上,并能直接在终端看到类似下图的错误信息,这对于解决JCE cannot authenticate the provider BC这类密码学相关错误至关重要。

命令行启动Burp查看错误日志

四、总结

如果你正在为Burp Suite中复杂的加解密流量分析而头疼,Galaxy (MITM Decryption) 是一个强大而全面的选择。它支持多语言Hook,能够优雅地处理诸如请求签名、响应整体加解密等混合场景。

本文以一次实战为例,分享了如何利用Galaxy和约30行Java代码,实现请求自动生成X-Signature签名头以及响应体Base64解码 + AES/ECB解密的全流程。整个过程严格使用Java标准JCE库,避免了第三方加密Provider可能带来的兼容性问题。

关键点回顾:

  1. 选型:Galaxy功能全面,对Java开发者友好,是处理加密流量的首选插件。
  2. 配置:务必正确设置目标过滤(ExpressionFilter),并确保Burp代理配置正确。
  3. 编码:理解四个Hook函数的调用时机,根据你的加密协议(是整体加密还是JSON内嵌套)编写对应逻辑。
  4. 排错:确保Burp由完整JDK启动,并通过命令行查看完整错误日志。

希望这份结合实战经验的记录,能帮助你在应对加密流量时少走弯路,让安全测试和问题排查更加顺畅。技术交流可以前往云栈社区的相关板块进一步探讨。




上一篇:一键获取58个知名网站设计规范:Awesome DESIGN.md 开源资源库
下一篇:VoxCPM2架构解析:无分词器TTS如何实现高保真声音克隆与应用指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-15 17:01 , Processed in 0.751600 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表