三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

BurpSuite Galaxy插件实战:破解Web应用自定义加密,提升安全测试效率

BurpSuite Galaxy插件实战:破解Web应用自定义加密,提升安全测试效率

1. 项目概述:为什么我们需要Galaxy这样的加解密插件?

在Web应用安全测试的日常工作中,我们经常会遇到一个让人头疼的“拦路虎”:应用层加密。想象一下,你正兴致勃勃地准备对一个登录接口进行密码爆破,或者想修改一个订单的金额,却发现Burpsuite拦截到的请求体是一串毫无规律的、类似aBcDeFg123==这样的密文。你无法直接修改其中的usernameamount参数,因为任何微小的改动都会破坏整个加密结构,导致服务器返回一个冷冰冰的“解密失败”。这就是应用层自定义加密带来的挑战,它像一层坚固的铠甲,保护着核心业务逻辑,也让安全测试人员无从下手。

Galaxy插件就是为了击穿这层铠甲而生的利器。它不是Burpsuite自带的某个隐藏功能,而是一款由社区开发者贡献的、功能强大的扩展插件。它的核心价值在于“透明化”处理加解密过程。简单来说,Galaxy允许你定义JavaScript脚本,在Burpsuite的代理层,对进出浏览器的HTTP/HTTPS流量进行自动化的加密和解密。对于你(测试者)而言,你在Burpsuite的Proxy -> Intercept标签页里看到的,将是已经解密后的、清晰明了的明文参数,你可以像操作普通请求一样随意修改它们。当你点击“Forward”发送时,Galaxy又会悄无声息地按照你定义的规则,将修改后的明文重新加密,再发送给服务器。整个过程对测试者是透明的,极大地提升了测试效率。

我最初接触Galaxy是因为测试一个金融类App,其所有敏感请求都使用了非标准的AES加密。手动解密、修改、再加密,一个测试用例就要耗费十几分钟,且极易出错。在配置好Galaxy后,整个测试流程变得行云流水,Intruder爆破、Repeater重放等高级功能得以充分发挥威力。因此,无论你是面对简单的Base64变形,还是复杂的RSA+AES混合加密,掌握Galaxy都能让你在安全测试中拥有“透视”和“变形”的能力。

2. 环境搭建:避开OpenJDK的“坑”,构建稳定Burpsuite运行环境

工欲善其事,必先利其器。Galaxy插件的运行依赖于Burpsuite的Extender API,而Burpsuite本身对Java运行环境(JRE)有特定的版本要求。很多新手在第一步就折戟沉沙,问题大多出在Java环境上。

2.1 Java环境选择与安装

Burpsuite(尤其是专业版)目前与最新的OpenJDK 21或17存在一些已知的兼容性问题,可能导致启动崩溃或插件加载失败。经过多次实测,最稳定的选择是Oracle JDK 8OpenJDK 11(LTS版本)

注意:强烈建议不要使用系统自带的或通过某些包管理器安装的最新版Java。为Burpsuite单独配置一个专用的JRE环境是避免后续各种诡异问题的最佳实践。

操作步骤:

  1. 卸载冲突版本:如果你电脑上已有其他Java版本,可以先通过java -version查看。如果版本高于11,建议为Burpsuite单独指定JRE路径,而不是替换系统默认版本。
  2. 下载JDK 11:前往Adoptium(原AdoptOpenJDK)官网,下载适用于你操作系统(Windows/macOS/Linux)的OpenJDK 11 LTS版本(例如Temurin-11),选择JRE或JDK均可,JRE更轻量。
  3. 安装与配置:在Windows上,建议将JDK解压或安装到一个没有中文和空格的路径,例如D:\DevTools\Java\jdk-11。然后,你需要将Burpsuite的启动脚本指向这个JRE。
    • Windows(使用批处理文件启动):创建一个start_burp.bat文件,内容如下:
      @echo off SET JAVA_HOME=D:\DevTools\Java\jdk-11 SET PATH=%JAVA_HOME%\bin;%PATH% start javaw -jar -Xmx2048m "D:\BurpSuite\burpsuite_pro_v2024.1.jar"
      这里-Xmx2048m表示分配2GB最大堆内存,对于大型项目测试很有帮助。双击此bat文件即可用指定JDK 11启动Burpsuite。
    • macOS/Linux:在终端中,使用类似命令启动:/path/to/your/jdk-11/bin/java -jar -Xmx2048m /path/to/burpsuite_pro.jar

实操心得:我曾经因为图省事,直接用系统已存在的JDK 17启动Burpsuite,结果在加载某些复杂插件时频繁出现内存错误或界面卡死。切换到JDK 11后,一切运行如丝般顺滑。这个“坑”值得所有初学者优先避开。

2.2 Burpsuite的安装与基础配置

确保你从官方渠道下载了Burpsuite。社区版功能有限,对于Galaxy插件的完整使用(特别是与Intruder模块的联动),专业版是更好的选择。

  1. 首次启动与代理配置:启动后,首先在Proxy -> Options中,确保Proxy Listeners正在运行(默认127.0.0.1:8080)。这是Burpsuite接收流量的入口。
  2. 浏览器代理设置:将你的浏览器(推荐使用Chrome或Firefox,并安装SwitchyOmega等代理管理插件)的HTTP/HTTPS代理设置为127.0.0.1:8080
  3. 安装CA证书:这是拦截HTTPS流量的关键。在浏览器中访问http://burpsuite,点击“CA Certificate”下载证书文件。然后,你需要将证书导入到系统的受信任根证书颁发机构存储中(具体步骤因操作系统而异)。只有完成这一步,Burpsuite才能解密HTTPS流量,Galaxy也才能在此基础上进行应用层的加解密。

2.3 Galaxy插件的获取与安装

Galaxy是一个开源项目,你可以在GitHub上搜索“Burpsuite Galaxy Plugin”找到它的源码和发布页面。通常,你需要下载其编译好的Jar文件(例如galaxy-1.0.x.jar)。

安装步骤非常简单:

  1. 在Burpsuite中,切换到Extender标签页。
  2. 选择Extensions子标签,点击Add按钮。
  3. 在弹窗中,Extension type选择Java
  4. 点击Select file...,找到你下载的galaxy.jar文件,然后点击Next
  5. 如果一切顺利,你会看到输出窗口显示“Galaxy extension loaded successfully”,并且在Extensions列表中出现“Galaxy”,其状态为“Enabled”。

提示:如果加载失败,请首先检查Burpsuite的Java版本是否符合要求(JDK 8或11)。其次,检查Jar文件是否完整。有时,网络下载的文件可能损坏,可以尝试重新下载。

至此,你的“武器库”已经准备就绪。Burpsuite作为拦截平台,Galaxy作为加解密处理器,Java环境作为稳定基石。接下来,我们将深入Galaxy的核心——脚本编写。

3. 核心原理与脚本编写:理解Galaxy的工作流与JavaScript引擎

Galaxy插件本身并不包含任何具体的加解密算法。它扮演的是一个“脚本执行器”和“流量处理器”的角色。它的强大之处在于,将加解密的逻辑定义完全交给了用户编写的JavaScript代码。这意味着,无论目标应用使用多么冷门或自定义的加密方式,只要你能用JavaScript实现其算法,Galaxy就能帮你自动化处理。

3.1 Galaxy的工作流程

理解以下流程对编写和调试脚本至关重要:

  1. 请求阶段(Client to Server)
    • 浏览器发出一个明文请求(但可能已被前端JS加密)。
    • 该请求被Burpsuite代理拦截。
    • Galaxy介入:Galaxy调用你编写的processRequestMessage函数,传入拦截到的请求(此时可能是前端加密后的密文)。你在这个函数里编写解密逻辑,将密文请求体解密为明文。
    • Burpsuite界面(如Proxy history, Repeater)显示的是解密后的明文。你可以修改它。
    • 当你发送修改后的请求时,Galaxy再次调用processRequestMessage(或相关的加密函数),将你修改过的明文重新加密成服务器可接受的格式,然后发出。
  2. 响应阶段(Server to Client)
    • 服务器返回一个加密的响应。
    • Burpsuite拦截到该响应。
    • Galaxy介入:Galaxy调用你编写的processResponseMessage函数,传入加密的响应。你在这个函数里编写解密逻辑,将密文响应体解密为明文。
    • Burpsuite界面(如Response标签页)显示的是解密后的明文内容。

整个过程中,Burpsuite的LoggerIntruderScanner等所有工具看到的都是解密后的明文,但实际网络上传输的始终是密文。这实现了测试的“透明化”。

3.2 脚本结构与关键函数

一个完整的Galaxy脚本通常包含以下几个部分:

// 1. 元数据声明 (非必需,但建议) var metadata = { name: "My Target App Crypto", author: "Your Name", description: "Handles AES encryption for XXX app" }; // 2. 全局变量或辅助函数 var CryptoJS = require("crypto-js"); // 假设我们使用CryptoJS库 var secretKey = "my-secret-key-123"; function customDecrypt(cipherText) { // 你的解密逻辑 // 例如使用CryptoJS.AES.decrypt var bytes = CryptoJS.AES.decrypt(cipherText, secretKey); return bytes.toString(CryptoJS.enc.Utf8); } function customEncrypt(plainText) { // 你的加密逻辑 return CryptoJS.AES.encrypt(plainText, secretKey).toString(); } // 3. 核心处理函数 - 必须实现 function processRequestMessage(utils, message) { // utils: 提供工具方法,如获取请求体、设置请求体等 // message: 当前HTTP请求消息对象 var requestInfo = utils.getRequestInfo(message); // 获取请求详情 var body = requestInfo.getBody(); // 获取请求体字节数组 if (body != null && body.length > 0) { var bodyStr = String.fromCharCode.apply(null, body); // 字节数组转字符串 // 判断是否需要处理(例如根据URL或Content-Type) if (requestInfo.getUrl().contains("/api/login")) { try { var decryptedStr = customDecrypt(bodyStr); // 调用解密函数 utils.setRequestBody(message, decryptedStr); // 将解密后的明文设回请求体 utils.addComment(message, "Galaxy: Request Decrypted"); // 添加注释,便于追踪 } catch (e) { utils.addComment(message, "Galaxy: Decrypt Failed - " + e.message); } } } return message; // 返回处理后的消息 } function processResponseMessage(utils, message) { // 处理响应,逻辑类似 var responseInfo = utils.getResponseInfo(message); var body = responseInfo.getBody(); if (body != null && body.length > 0) { var bodyStr = String.fromCharCode.apply(null, body); // 判断是否需要解密响应 if (message.getUrl().contains("/api/data")) { try { var decryptedStr = customDecrypt(bodyStr); utils.setResponseBody(message, decryptedStr); utils.addComment(message, "Galaxy: Response Decrypted"); } catch (e) { // 处理错误 } } } return message; }

关键点解析:

  • utils.getRequestInfo(message)/utils.getResponseInfo(message):这是你与HTTP消息交互的入口,可以获取URL、Headers、Body等信息。
  • utils.setRequestBody/utils.setResponseBody:这是修改消息体的关键方法。Galaxy正是通过调用这些方法,将解密后的明文“替换”回去,供Burpsuite界面显示和编辑。
  • utils.addComment:这是一个非常实用的调试功能。它会在Burpsuite的Proxy历史记录或Logger中为该条记录添加一个注释,让你一眼就能看出哪些请求被Galaxy处理过,是成功还是失败。

3.3 引入外部加密库(如CryptoJS)

JavaScript内置的加密能力有限。对于常见的AES、DES、RSA等算法,我们通常需要引入CryptoJS这个强大的库。Galaxy的JavaScript引擎支持require语法。

如何引入CryptoJS:

  1. 你需要下载CryptoJS的完整源码(一个单独的crypto-js.js文件),而不是使用其通过npm分发的模块化版本。
  2. 在Galaxy脚本的开头,使用var CryptoJS = require("/full/path/to/crypto-js.js");来加载。注意,这里的路径必须是文件系统的绝对路径。
  3. 加载成功后,你就可以使用CryptoJS.AESCryptoJS.MD5等对象了。

实操心得:路径问题是新手常遇到的坑。在Windows上,路径可能是C:\\Users\\Name\\tools\\crypto-js.js(注意双反斜杠或单正斜杠)。一个更稳健的做法是,将CryptoJS.js文件放在Burpsuite的安装目录或你的脚本目录下,使用相对路径(但需要确认Galaxy的当前工作目录)。最省事的方法是,直接将CryptoJS的源码复制粘贴到你的Galaxy脚本文件中,作为一个巨大的字符串变量或直接内联编写,这样就完全避免了路径依赖问题。虽然这会让脚本文件变大,但对于需要分发的脚本来说,一体性更强。

4. 实战入门:编写你的第一条解密脚本

理论说得再多,不如动手一试。我们以一个最常见的场景为例:目标网站使用AES-CBC模式对JSON请求体进行整体加密,加密后的数据以Base64字符串形式放在POST body中。

假设目标:

  • URL:https://target.com/api/submit
  • 请求体(加密后):"U2FsdGVkX1+o5x...(很长一串Base64)"
  • 加密方式:AES-256-CBC,PKCS7填充,密钥mySuperSecretKey1234567890123456,IV向量为1234567890123456

4.1 步骤一:分析并还原加密逻辑

首先,你需要通过前端代码分析或逆向工程,确定准确的加密参数。这里我们假设已获知上述信息。我们选择使用CryptoJS库。

4.2 步骤二:编写完整的Galaxy脚本

我们将内联CryptoJS的核心代码(简化版),并编写处理函数。

// Galaxy Script for AES-256-CBC Decryption/Encryption var metadata = { name: "AES-256-CBC Demo", author: "Security Tester", description: "Handles AES-256-CBC encryption for /api/submit" }; // --- 内联的CryptoJS核心部分 (极度简化版,仅用于演示) --- // 在实际使用中,你应该引入完整的crypto-js.js文件 var CryptoJS = (function() { // 这里本应是庞大的CryptoJS库代码 // 为了示例,我们假设它已正确加载,并提供了AES.decrypt/encrypt方法 // 实际脚本中,请使用 require("/path/to/crypto-js.js") return window.CryptoJS || {}; // 假设在Galaxy环境中可用 })(); // 配置密钥和IV (应与前端一致) var SECRET_KEY = CryptoJS.enc.Utf8.parse("mySuperSecretKey1234567890123456"); // 32字节 var IV = CryptoJS.enc.Utf8.parse("1234567890123456"); // 16字节 /** * 解密函数 * @param {string} ciphertextBase64 - Base64编码的密文 * @return {string} 解密后的明文 */ function decrypt(ciphertextBase64) { try { // CryptoJS 期望的密文格式可能是特殊的OpenSSL格式,这里假设是直接的AES-CBC密文 // 实际中需要根据前端具体实现调整 var encryptedData = CryptoJS.enc.Base64.parse(ciphertextBase64); var decrypted = CryptoJS.AES.decrypt( { ciphertext: encryptedData }, // 或直接传Base64字符串,取决于库版本 SECRET_KEY, { iv: IV, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ); return decrypted.toString(CryptoJS.enc.Utf8); } catch (e) { return "Decryption Error: " + e.message; } } /** * 加密函数 * @param {string} plaintext - 明文 * @return {string} Base64编码的密文 */ function encrypt(plaintext) { try { var encrypted = CryptoJS.AES.encrypt( plaintext, SECRET_KEY, { iv: IV, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 } ); // 获取密文的Base64字符串表示 return encrypted.ciphertext.toString(CryptoJS.enc.Base64); } catch (e) { return "Encryption Error: " + e.message; } } // --- Galaxy 核心处理函数 --- function processRequestMessage(utils, message) { var requestInfo = utils.getRequestInfo(message); var url = requestInfo.getUrl().toString(); // 只处理特定接口 if (url.indexOf("/api/submit") !== -1) { var bodyBytes = requestInfo.getBody(); if (bodyBytes != null && bodyBytes.length > 0) { var rawBody = String.fromCharCode.apply(null, bodyBytes); // 假设请求体就是直接的Base64字符串,没有额外的JSON包装 var decryptedBody = decrypt(rawBody.trim()); // 解密 if (!decryptedBody.startsWith("Decryption Error")) { // 成功解密,将明文设置回请求体 utils.setRequestBody(message, decryptedBody); utils.addComment(message, "[Galaxy] Request Decrypted to JSON"); // 你可以在这里打印解密内容到Burpsuite的Extender输出窗口,用于调试 // utils.printOutput("Decrypted: " + decryptedBody.substring(0, 100) + "..."); } else { utils.addComment(message, "[Galaxy] Decrypt FAILED"); } } } // 注意:我们不在这个函数里重新加密。Galaxy通常有独立的流程处理出站加密。 // 但Galaxy插件通常通过“双向处理”自动完成。有些配置下,需要在另一个钩子或同一函数判断方向。 // 更常见的做法是:解密入站请求供查看/修改,加密出站请求供发送。 // 这里为简化,假设Galaxy配置了双向处理,且encrypt函数会被自动调用。 return message; } // 一个用于出站请求加密的处理器(如果Galaxy支持) function processOutgoingRequest(utils, message) { var requestInfo = utils.getRequestInfo(message); var url = requestInfo.getUrl().toString(); if (url.indexOf("/api/submit") !== -1) { var bodyBytes = requestInfo.getBody(); if (bodyBytes != null && bodyBytes.length > 0) { var plainBody = String.fromCharCode.apply(null, bodyBytes); // 检查是否是JSON(即我们修改过的明文),如果是则加密 try { JSON.parse(plainBody); // 简单验证是否为JSON var encryptedBody = encrypt(plainBody); if (!encryptedBody.startsWith("Encryption Error")) { utils.setRequestBody(message, encryptedBody); utils.addComment(message, "[Galaxy] Request Encrypted for sending"); } } catch (e) { // 不是JSON,可能是其他状态,不处理 } } } return message; } // 响应解密 function processResponseMessage(utils, message) { var responseInfo = utils.getResponseInfo(message); var url = message.getUrl().toString(); if (url.indexOf("/api/submit") !== -1 && responseInfo.getStatusCode() == 200) { var bodyBytes = responseInfo.getBody(); if (bodyBytes != null && bodyBytes.length > 0) { var rawBody = String.fromCharCode.apply(null, bodyBytes); var decryptedBody = decrypt(rawBody.trim()); if (!decryptedBody.startsWith("Decryption Error")) { utils.setResponseBody(message, decryptedBody); utils.addComment(message, "[Galaxy] Response Decrypted"); } } } return message; }

4.3 步骤三:在Galaxy插件中配置脚本

  1. 在Burpsuite的Extender -> Extensions中找到已加载的Galaxy插件,点击其下方的Galaxy标签(或类似名称,具体取决于插件版本)。
  2. 你应该能看到一个界面,允许你添加、编辑、启用/禁用脚本。
  3. 点击AddNew Script,将上面的代码粘贴进去。为脚本起一个名字,例如AES-256-CBC Demo
  4. 确保脚本状态为Enabled

4.4 步骤四:测试你的第一条解密请求

  1. 确保浏览器代理设置正确,指向Burpsuite。
  2. 访问目标网站,进行触发/api/submit请求的操作(例如点击提交按钮)。
  3. 切换到Burpsuite的Proxy -> HTTP history
  4. 找到指向/api/submit的请求。如果配置成功,你应该能看到:
    • 请求体(Raw视图):从一串Base64密文,变成了可读的JSON明文,例如{"user":"admin","action":"login"}
    • 注释栏:可能显示有[Galaxy] Request Decrypted to JSON
  5. 你可以在Repeater中右键发送该请求到Repeater,然后修改JSON中的参数(如将user改为test),点击发送。Galaxy会自动将你修改后的明文重新加密,然后发送给服务器。在Response中,你看到的也应该是解密后的明文。

恭喜!至此,你已经完成了从环境搭建到编写、配置并成功运行第一条解密脚本的全过程。你成功地在Burpsuite和加密的Web应用之间架起了一座透明的桥梁。

5. 高级技巧与深度调试:让Galaxy成为你的得力助手

掌握了基础用法后,下面这些技巧能让你更高效地利用Galaxy应对复杂场景。

5.1 处理多种加密模式或动态密钥

现实中的加密往往更复杂。密钥可能不是硬编码的,而是通过某个接口动态获取(如登录后返回一个sessionKey)。或者,不同的接口使用不同的加密算法。

解决方案:

  • 状态管理:Galaxy脚本的变量在同一个请求-响应会话中通常是保持的。你可以定义一个全局对象来存储状态,例如:
    var cryptoState = { currentKey: null, keyExpiry: 0, algorithm: 'AES-128' }; // 在processResponseMessage中,监听登录响应,从中提取密钥并存入cryptoState
  • URL路由:在processRequestMessageprocessResponseMessage函数中,使用if-elseswitch语句,根据utils.getRequestInfo(message).getUrl()的不同路径,调用不同的加解密函数。
  • 外部配置:对于需要频繁修改的密钥或参数,可以将它们写在脚本开头的配置变量中,甚至通过Burpsuite的Extension Settings界面来动态配置(这需要插件支持更高级的API)。

5.2 利用Burpsuite工具链进行联动测试

Galaxy解密的真正威力在于解放了Burpsuite的其他工具。

  1. Intruder(入侵者):这是最经典的用例。当你需要对一个加密的参数进行爆破时(如密码、验证码),无需再手动加密每个Payload。在Intruder中,直接针对解密后的明文参数(如password)设置Payload位置。Galaxy会在每次请求发送前,自动将你设置的明文Payload加密。你可以轻松进行字典攻击、模糊测试等。
  2. Repeater(重放器):方便地修改单个请求,观察响应变化。解密后,你可以直观地修改JSON或表单数据,无需关心底层加密。
  3. Scanner(扫描器):Burpsuite的主动扫描器也能受益。虽然Scanner本身有处理简单编码的能力,但对于自定义加密无能为力。配置好Galaxy后,Scanner发送的测试Payload会被自动加密,从而能够对加密接口进行漏洞扫描。
  4. Logger(日志记录器):所有经过Galaxy处理的请求和响应,都会留下注释。你可以在Logger中过滤出这些记录,方便回溯和分析测试流程。

5.3 调试脚本:当解密失败时怎么办?

脚本不工作是最常见的情况。别慌,按以下步骤排查:

  1. 检查Extender输出:首先查看Burpsuite的Extender -> Output标签页。Galaxy插件和你的脚本运行时抛出的任何JavaScript错误都会在这里打印。这是最重要的调试信息源。
  2. 使用utils.printOutput():在你的脚本中关键位置插入utils.printOutput("Debug: " + someVariable)。这会将信息打印到上述Output窗口,帮助你跟踪变量状态和执行流程。
  3. 验证加解密函数本身:在脚本之外,先用一个简单的Node.js或浏览器环境,用相同的密钥和IV测试你的encryptdecrypt函数,确保它们能正确互逆。确保你使用的CryptoJS版本和模式(CBC/ECB)、填充(Pkcs7/ZeroPadding)等与前端完全一致。一个常见的坑是IV的处理:前端可能将IV拼接在密文前,或者使用固定的IV,你的解密函数需要以同样的方式提取或使用IV。
  4. 检查请求/响应判断条件:确保你的if (url.indexOf("/api/submit") !== -1)条件能正确匹配到目标请求。有时URL包含查询参数,需要更精确的匹配。可以使用utils.getRequestInfo(message).getUrl().getPath()来获取纯路径部分。
  5. 查看原始流量:在Burpsuite的Proxy历史中,右键请求,选择Send to Comparer,然后选择Compare with original。这能帮你确认,Galaxy是否真的修改了请求体。如果比较结果显示无变化,说明你的脚本没有被执行,或者执行路径没有匹配上。
  6. 注意编码问题:HTTP请求体是字节数组。在将字节数组转为字符串(String.fromCharCode.apply(null, bodyBytes))时,假设了它是UTF-8编码。如果实际是其他编码(如GBK),会导致乱码和解密失败。同样,设置回去时也要确保编码一致。

5.4 性能与稳定性考量

  • 脚本复杂度:过于复杂的JavaScript脚本可能会影响Burpsuite处理请求的速度,尤其是在高并发(如Intruder攻击)时。尽量保持加解密函数高效,避免在脚本中进行耗时的网络请求或复杂计算。
  • 错误处理:务必用try-catch包裹你的加解密逻辑,并在出错时通过utils.addComment添加明确的错误信息。一个未捕获的异常可能导致整个请求处理链中断。
  • 作用域隔离:Galaxy的每个脚本可能运行在独立的JavaScript引擎中,但要注意全局变量污染。尽量使用函数封装你的逻辑,减少全局变量的使用。

6. 常见问题与排查技巧实录

在这一部分,我汇总了在过去几年使用Galaxy插件过程中,自己和同事们踩过的坑以及对应的解决方案。希望这份“避坑指南”能帮你节省大量调试时间。

问题现象可能原因排查步骤与解决方案
Galaxy插件加载失败1. Burpsuite Java版本不兼容(如JDK 17+)。
2. Jar文件损坏或版本不对。
3. 与其他插件冲突。
1. 降级到JDK 8或11启动Burpsuite。
2. 重新下载插件,检查文件完整性。
3. 禁用其他插件,逐一排查。
脚本已启用,但请求/响应无变化1. URL匹配条件错误。
2. 脚本逻辑错误,未进入加解密分支。
3. 加解密函数本身抛出异常被静默处理。
4. 脚本未正确保存或启用。
1. 使用utils.printOutput打印URL,确认匹配逻辑。
2. 在processRequestMessage开始处添加打印,确认函数被调用。
3. 检查Extender Output窗口有无JavaScript错误。
4. 在Galaxy管理界面确认脚本状态为“Enabled”。
解密后是乱码或错误信息1. 密钥或IV错误。
2. 加密模式或填充方式不匹配。
3. 密文格式问题(如包含非Base64字符、有JSON包装)。
4. 字符串与字节数组转换编码问题。
1. 核对前端加密代码,确保所有参数一致。
2. 使用独立的CryptoJS环境验证加解密函数。
3. 打印原始请求体,确认其确切格式。可能需要先进行JSON.parse提取密文字段。
4. 尝试使用CryptoJS.enc.HexCryptoJS.enc.Latin1进行解析。
修改明文后发送,服务器返回解密失败1. 加密函数错误,生成的密文格式不对。
2. 修改明文时破坏了结构(如JSON格式错误)。
3. 请求头(如Content-Length)未更新。
1. 用加密函数加密一个已知明文,与前端生成的密文对比。
2. 使用JSON.stringify()确保修改后的JSON格式正确。
3.关键点:Galaxy通常会自动更新Content-Length,但某些自定义头可能需要手动处理。检查请求头。
仅部分请求被处理1. 脚本中的URL匹配规则不全面。
2. 请求方法(GET/POST)或Content-Type被忽略。
1. 使用更宽泛的匹配(如url.indexOf('/api/') > -1)或正则表达式。
2. 在条件中增加对requestInfo.getMethod()requestInfo.getHeader('Content-Type')的判断。
使用Intruder时速度极慢1. 脚本中加解密逻辑过于复杂或效率低下。
2. 在脚本中进行了同步的、耗时的操作。
1. 优化JavaScript代码,避免在循环中重复初始化大型对象。
2. 确保加解密是纯内存计算,无I/O操作。对于RSA等慢速算法,考虑性能影响。
无法引入外部JS库(如CryptoJS)1.require路径错误。
2. Galaxy的JS引擎不支持该库的某些特性。
1. 使用绝对路径,或直接将库源码内联到脚本中(推荐)。
2. 尝试寻找更轻量级或兼容性更好的加密库实现,或手动实现核心算法(对于简单算法如XOR、Base64变种可行)。

独家避坑技巧

  • “先分离,后集成”:永远不要在Galaxy脚本里直接编写和调试复杂的加密算法。先在浏览器控制台或Node.js脚本中,用JavaScript完美复现目标的前端加密和解密过程。确保这个独立的脚本能正常工作后,再把代码移植到Galaxy脚本中。这能隔离90%的算法相关问题。
  • 善用注释和日志:在脚本的每个关键决策点(如进入某个URL判断、调用解密前、解密后)都加上utils.addComment。这样在Burpsuite的历史记录里,你能像看流程图一样看到脚本的执行路径,快速定位问题发生在哪一步。
  • 从简单到复杂:不要一开始就试图处理整个应用的所有加密接口。先针对一个最简单的、你最确定的加密请求(比如一个登录请求)编写脚本。成功解密/加密这一个请求后,再逐步扩展脚本的功能,处理更多接口和更复杂的逻辑。这种渐进式的方法能帮你建立信心,并更容易定位新增功能引入的问题。

Galaxy插件的学习曲线初期可能有些陡峭,尤其是需要与JavaScript加密代码打交道时。但一旦你成功配置好第一个脚本,并看到加密流量在Burpsuite中变得清晰可见,那种成就感是无与伦比的。它不仅仅是解放了双手,更是打开了深入测试加密Web应用的大门。记住,核心在于精确还原前端的加密逻辑,而Galaxy提供了一个强大且灵活的舞台来部署你的还原成果。多练习,多调试,你很快就能将它运用自如,成为你Web安全测试工具箱中不可或缺的神器。

← 返回列表