Galaxy插件实战:Burpsuite加密流量自动化测试与Hook脚本编写指南
1. 项目概述:为什么你需要Galaxy这个“解密翻译官”
如果你在渗透测试或者安全审计中遇到过这样的场景:打开Burpsuite,拦截到的请求和响应全是看不懂的密文,像天书一样,常规的SQL注入、XSS测试根本无从下手,那你一定明白那种抓耳挠腮的无力感。现代Web应用,尤其是金融、电商、游戏类应用,为了对抗中间人攻击和流量分析,普遍会对关键业务接口的通信数据进行加密。这就像给目标穿上了一层厚厚的盔甲,你的扫描器和手动测试工具都成了“睁眼瞎”。
Galaxy插件就是为了解决这个痛点而生的。你可以把它理解成Burpsuite和加密流量之间的“实时翻译官”。它的核心目标,就是让你测试加密流量像测试明文一样简单高效。你不再需要手动复制密文到外部脚本解密,再手动加密回填;Galaxy能自动在Burpsuite内部完成这个加解密过程,让你看到的、操作的,始终是明文的请求和响应。这对于提升渗透测试效率,尤其是面对复杂加密逻辑的应用时,是革命性的。
2. Galaxy核心工作原理与架构拆解
要玩转Galaxy,不能只停留在“点一下就用”的层面。理解它的工作原理,能帮助你在遇到复杂场景时,自己定位问题,甚至写出更强大的Hook脚本。
2.1 核心工作流:插件如何“劫持”Burpsuite的数据流
Galaxy本质上是一个Burpsuite Extender插件,它通过实现Burp的IHttpListener、IScannerCheck等接口,深度嵌入了Burpsuite的数据处理流程。其核心工作流可以概括为以下几个步骤:
- 流量拦截:当HTTP/HTTPS流量经过Burpsuite的Proxy模块时,Galaxy会首先拦截到原始的请求和响应数据。
- Hook脚本执行:Galaxy会调用你预先编写并配置好的JavaScript Hook脚本。这个脚本是你定义加解密逻辑的地方。
- 请求解密/响应加密:对于从客户端发往服务器的请求,Hook脚本执行
beforeRequest函数,将拦截到的密文请求体解密为明文。Galaxy会用这个明文替换掉原始的密文,再转发给Burpsuite的后续模块(如Scanner、Intruder)或目标服务器。对于从服务器返回的响应,Hook脚本执行beforeResponse函数,将服务器返回的明文响应体,按照约定加密成密文,再返回给客户端浏览器或APP。 - 双向透明化处理:经过上述步骤,在Burpsuite的界面(如Proxy history、Repeater)里,你看到和编辑的始终是明文。而实际网络上流动的,以及客户端和服务器收到的,依然是符合预期的密文。整个过程对测试者和被测试应用都是“透明”的。
注意:这里有一个关键点,Galaxy默认处理的是HTTP Body(消息体)。对于URL参数、Cookie、Header的加解密,需要在Hook脚本中特别处理,通常需要操作
request或response对象的完整字节数组。
2.2 Hook脚本:加解密逻辑的“灵魂”
Hook脚本是Galaxy能力的核心,它是一段JavaScript代码,定义了如何解密和加密。Galaxy通过内置的JavaScript引擎(如Nashorn或GraalVM)来执行它。一个最基本的Hook脚本结构如下:
// 定义全局变量或加解密函数,例如一个简单的AES-ECB解密(仅示例,实际算法复杂得多) var CryptoJS = require("crypto-js"); // Galaxy内置了CryptoJS库 function decrypt(data, key) { // 你的解密逻辑,data是Base64编码的密文字符串 var bytes = CryptoJS.AES.decrypt(data, CryptoJS.enc.Utf8.parse(key)); return bytes.toString(CryptoJS.enc.Utf8); } function encrypt(data, key) { // 你的加密逻辑 var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(data), CryptoJS.enc.Utf8.parse(key)); return encrypted.toString(); } // Galaxy约定的入口函数 function beforeRequest(plainRequest) { // plainRequest 是Galaxy提供的工具对象,包含请求信息 var body = plainRequest.getBodyAsString(); // 获取请求体(此时已是Galaxy处理后的状态,初次可能是密文) // 判断是否需要解密,例如通过URL路径或Content-Type if (plainRequest.getUrl().contains("/api/secure")) { var decryptedBody = decrypt(body, "your-secret-key-here"); plainRequest.setBody(decryptedBody); // 设置解密后的明文请求体 // 有时解密后需要更新Content-Length头 plainRequest.getHeaders().removeHeader("Content-Length"); plainRequest.getHeaders().addHeader("Content-Length: " + decryptedBody.length); } return plainRequest; // 返回修改后的请求对象 } function beforeResponse(plainResponse) { var body = plainResponse.getBodyAsString(); // 获取响应体(服务器返回的明文) if (plainResponse.getUrl().contains("/api/secure")) { var encryptedBody = encrypt(body, "your-secret-key-here"); plainResponse.setBody(encryptedBody); plainResponse.getHeaders().removeHeader("Content-Length"); plainResponse.getHeaders().addHeader("Content-Length: " + encryptedBody.length); } return plainResponse; }关键理解:beforeRequest和beforeResponse函数的参数(plainRequest,plainResponse)是Galaxy封装的对象,它已经对原始HTTP报文进行了解析。你可以通过它们的方法(getUrl(),getHeaders(),getBodyAsString())获取信息,并通过setBody()等方法进行修改。你的加解密逻辑就作用在这些Body字符串上。
3. 实战部署:从安装到第一个Hook的完整流程
理论懂了,我们动手把它装起来,并配置一个最简单的Hook来感受一下。
3.1 环境准备与插件安装
首先,确保你的环境符合要求:
- Burpsuite版本:这是最重要的。Galaxy官方推荐使用Burp Suite Professional 2023.10.3.7 或更高版本。社区版由于功能限制,部分高级特性(如与Scanner模块的深度集成)可能无法正常工作。建议使用官方正版或确保你的版本兼容。
- Java环境:Burpsuite本身基于Java,确保系统有合适的JRE(Java 8或更高版本,推荐JDK 11+)。在终端输入
java -version检查。 - 下载Galaxy:访问项目的GitHub Release页面(通常搜索“Galaxy Burp plugin release”即可找到),下载最新的
.jar文件。不要从不明来源下载,以防植入后门。
安装步骤非常简单:
- 打开Burpsuite,进入Extender标签页。
- 点击Extensions子标签下的Add按钮。
- 在弹窗中,将Extension type选择为Java。
- 点击Select file...,找到你下载的
Galaxy-xxx.jar文件并选中。 - 点击Next,Burpsuite会加载插件。如果一切正常,你会看到输出区域显示加载成功,并且在Extender的“Loaded”列表中出现“Galaxy”,同时顶部菜单栏会多出一个Galaxy菜单项。
实操心得:安装后如果Burpsuite卡住或报错,首先检查Burp版本是否过低。其次,尝试重启Burpsuite。如果问题依旧,可以去项目的GitHub Issues页面搜索相关错误信息,大概率已有解决方案。
3.2 编写你的第一个Hook脚本:以Base64编码为例
我们从一个最简单的“加解密”场景开始:目标网站对请求体和响应体做了Base64编码。虽然Base64不是加密,但Galaxy的处理流程完全一致,非常适合入门。
启用Galaxy并新建Hook:
- 点击顶部菜单栏的Galaxy->Config(或直接在Extender标签页点击Galaxy插件的Output或Errors标签旁的Config按钮)。
- 这会打开Galaxy的主配置界面。点击下方的“+”号按钮,新建一个Hook配置。
- 给它起个名字,比如
Demo_Base64。
编写Hook脚本:
- 在配置界面的大文本框中,输入以下JavaScript代码:
// 简单的Base64“加解密”Hook function beforeRequest(plainRequest) { var body = plainRequest.getBodyAsString(); // 假设我们对 /api/data 接口的请求体进行Base64解码 if (plainRequest.getUrl().contains("/api/data") && body) { try { // 将Base64编码的请求体解码为明文 var decodedBody = java.util.Base64.getDecoder().decode(body); plainRequest.setBody(String(new java.lang.String(decodedBody, "UTF-8"))); // 更新Content-Length plainRequest.getHeaders().removeHeader("Content-Length"); plainRequest.getHeaders().addHeader("Content-Length: " + plainRequest.getBody().length); } catch(e) { // 解码失败,可能不是Base64,原样返回 print("[Galaxy Demo] Base64 decode error: " + e); } } return plainRequest; } function beforeResponse(plainResponse) { var body = plainResponse.getBodyAsString(); if (plainResponse.getUrl().contains("/api/data") && body) { // 将明文的响应体重新编码为Base64 var encodedBody = java.util.Base64.getEncoder().encodeToString(body.getBytes("UTF-8")); plainResponse.setBody(encodedBody); plainResponse.getHeaders().removeHeader("Content-Length"); plainResponse.getHeaders().addHeader("Content-Length: " + encodedBody.length); } return plainResponse; }- 这段代码做了两件事:当请求URL包含
/api/data时,将请求体从Base64解码为明文;将服务器的明文响应重新编码为Base64后返回给客户端。
配置作用域(Scope):
- 光有脚本还不够,你需要告诉Galaxy这个Hook对哪些流量生效。在配置界面的Scope部分,你可以选择“All traffic”或“Custom scope”。
- 对于这个Demo,建议先选择“Custom scope”,并在包含规则中添加你目标测试站点的域名或URL,例如
*.example.com。这样可以避免插件处理所有流量,减少不必要的性能开销和潜在错误。
保存并启用:
- 点击Save保存配置。
- 确保配置前面的复选框是勾选状态,表示启用此Hook。
- 关闭配置窗口。
3.3 验证Hook是否生效
现在,你可以进行测试了。
- 将浏览器或APP的代理设置为Burpsuite。
- 访问目标网站触发一个
/api/data的请求(你可以用Burp的Repeater手动构造一个)。 - 在Burpsuite的Proxy -> HTTP history中,找到那条请求。
- 观察Request和Response面板。如果配置正确,你在这里看到的应该是解码后的明文。而通过点击“原始数据” (Raw)标签,你看到的才是实际在网络上传输的Base64编码数据。
恭喜你,至此你已经完成了Galaxy最核心的闭环操作!你成功地在Burpsuite内部建立了一条加解密通道。
4. 进阶实战:处理复杂加密与联动扫描器
真实的加密远不止Base64。常见的可能是AES、RSA,或是自定义的混淆算法。此外,Galaxy的强大之处在于能让你的明文流量无缝对接其他安全工具。
4.1 逆向加密算法并编写复杂Hook
面对未知加密,第一步是逆向。通常需要借助浏览器开发者工具(F12)的“源代码”(Sources)和“网络”(Network)标签,或者使用Frida、Xposed等框架对移动端APP进行Hook,定位到加密函数。
假设通过逆向,你发现目标使用AES-CBC模式加密,密钥是固定的"1234567890123456",IV向量是"abcdefghijklmnop",并且数据在加密后还做了Hex编码。
你的Hook脚本就需要升级:
// 引入Galaxy内置的CryptoJS库 var CryptoJS = require("crypto-js"); function decryptComplex(data) { // 假设原始数据是Hex编码的,先Hex解码 var encryptedHex = CryptoJS.enc.Hex.parse(data); // 转换为CryptoJS可识别的密文对象 var encryptedBase64 = encryptedHex.toString(CryptoJS.enc.Base64); // AES-CBC解密参数 var key = CryptoJS.enc.Utf8.parse("1234567890123456"); // 16字节密钥 var iv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop"); // 16字节IV // 解密 var decrypted = CryptoJS.AES.decrypt(encryptedBase64, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 // 常见的填充方式 }); // 将解密结果转为UTF-8字符串 return decrypted.toString(CryptoJS.enc.Utf8); } function encryptComplex(data) { var key = CryptoJS.enc.Utf8.parse("1234567890123456"); var iv = CryptoJS.enc.Utf8.parse("abcdefghijklmnop"); // 加密 var encrypted = CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); // 将密文从Base64格式转为Hex格式输出 return encrypted.ciphertext.toString(CryptoJS.enc.Hex); } function beforeRequest(plainRequest) { var body = plainRequest.getBodyAsString(); if (isTargetApi(plainRequest.getUrl())) { // isTargetApi是你自己定义的判断函数 try { var decryptedBody = decryptComplex(body); plainRequest.setBody(decryptedBody); updateContentLength(plainRequest); // 更新头部的辅助函数 } catch(e) { print("[Galaxy] 请求解密失败: " + e); } } return plainRequest; } function beforeResponse(plainResponse) { var body = plainResponse.getBodyAsString(); if (isTargetApi(plainResponse.getUrl())) { try { var encryptedBody = encryptComplex(body); plainResponse.setBody(encryptedBody); updateContentLength(plainResponse); } catch(e) { print("[Galaxy] 响应加密失败: " + e); } } return plainResponse; } // 辅助函数:判断是否为需要处理的API function isTargetApi(url) { return url && url.indexOf("/secure/") > -1; } // 辅助函数:更新Content-Length头 function updateContentLength(message) { message.getHeaders().removeHeader("Content-Length"); message.getHeaders().addHeader("Content-Length: " + message.getBody().length); }4.2 与Sqlmap联动进行自动化SQL注入测试
这是Galaxy的杀手级功能之一。当流量被解密成明文后,你可以直接将这个明文请求交给Sqlmap进行自动化漏洞扫描。
配置Sqlmap路径:
- 在Galaxy的配置界面(Galaxy -> Config),找到或新建一个Hook配置。
- 在配置底部,通常会有“Sqlmap Path”的设置项。点击浏览,选择你本地Sqlmap可执行文件的路径(例如
python /path/to/sqlmap.py或 Windows下的sqlmap.exe绝对路径)。
发送请求到Sqlmap:
- 在Burpsuite的任意界面(如Proxy history, Repeater),右键点击一条已经被Galaxy解密为明文的HTTP请求。
- 在右键菜单中,找到Galaxy或Extensions子菜单,选择“Send to Sqlmap”或类似选项。
- Galaxy会自动将当前请求的详细信息(URL、Headers、Cookie、明文Body)构造成一个Sqlmap可识别的命令,并弹出一个终端窗口(或调用你系统的命令行)来运行Sqlmap。
关键优势:
- 无需手动处理加密:Sqlmap接收到的就是明文,它可以直接进行各种注入测试。
- 自动处理响应:Sqlmap发出的测试请求,其响应在返回过程中会经过Galaxy的
beforeResponse函数自动加密,再传回给Sqlmap分析。Sqlmap看到的是解密后的明文响应,从而能正确判断注入是否成功。 - 保持会话:通过Burpsuite的代理,Sqlmap的测试请求能自动携带正确的Cookie等会话信息。
4.3 与Xray联动进行全方位漏洞扫描
与Sqlmap类似,Galaxy也可以和长亭科技的Xray漏洞扫描器联动。
配置Xray监听地址:
- 首先,你需要启动Xray,并让它以被动扫描模式运行,监听一个端口(例如
127.0.0.1:7777)。 - 在Galaxy的Hook配置中,找到“Xray Server”设置项,填入Xray的监听地址,如
127.0.0.1:7777。
- 首先,你需要启动Xray,并让它以被动扫描模式运行,监听一个端口(例如
发送请求到Xray:
- 同样,在Burpsuite中右键一条明文请求,选择“Send to Xray”。
- Galaxy会将这个请求通过HTTP协议转发到你配置的Xray服务器地址。
- Xray接收到这个请求后,会将其加入扫描队列,并开始进行包括SQL注入、XSS、命令执行、路径遍历等在内的全方位漏洞检测。
联动工作流:
- 你可以配置Burpsuite的代理将全部流量转发给Xray(在Xray中配置上游代理为Burp),但这样会产生大量流量。
- 更高效的方式是,在测试过程中,只将你认为重要的、功能性的接口请求手动右键发送给Xray进行深度扫描。Galaxy的右键菜单提供了这种精准触发的便捷性。
5. 调试技巧与常见问题排坑实录
在实际使用中,你肯定会遇到各种问题。下面是我踩过坑后总结的一些经验和常见问题的解决方法。
5.1 Hook脚本调试技巧
使用
print()函数输出日志:- 在Hook脚本中,
print()函数输出的内容会显示在Burpsuite的Extender -> Galaxy -> Output标签页中。这是最重要的调试手段。 - 在关键步骤,如获取到Body后、解密前、解密后,都打印一下信息,可以清晰看到数据处理流程。
function beforeRequest(plainRequest) { print("[DEBUG] URL: " + plainRequest.getUrl()); var originalBody = plainRequest.getBodyAsString(); print("[DEBUG] Original Body (first 100 chars): " + originalBody.substring(0, Math.min(100, originalBody.length))); // ... 你的解密逻辑 print("[DEBUG] Decrypted Body: " + decryptedBody); return plainRequest; }- 在Hook脚本中,
利用Burpsuite的Repeater手动测试:
- 将一条加密的请求发送到Repeater。
- 在Repeater中,你可以手动修改请求,并观察Galaxy处理前后的变化。结合Output标签的打印日志,能精准定位是解密逻辑错误,还是加密逻辑错误,亦或是Header处理有问题。
分阶段验证算法:
- 先将加解密逻辑单独写在一个
.js文件里,用Node.js或浏览器的控制台测试,确保算法本身正确无误。 - 再将验证过的函数移植到Galaxy的Hook脚本中。
- 先将加解密逻辑单独写在一个
5.2 常见问题与解决方案速查表
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| Galaxy插件加载失败 | 1. Burp版本过低。 2. Java版本不兼容。 3. 下载的Jar文件损坏。 | 1. 升级Burpsuite到2023.10.3.7或更高。 2. 尝试使用JDK 11或17。 3. 重新从GitHub Release页面下载。检查Extender的Errors标签页看具体错误。 |
| Hook已启用但流量未解密 | 1. Scope配置不正确,未包含目标URL。 2. Hook脚本中的URL判断逻辑有误。 3. 加解密函数本身报错,被try-catch静默处理。 | 1. 检查Hook配置的Scope,确保包含目标域名/IP。 2. 在Hook开头用 print()打印URL,确认函数被触发。3. 检查Output标签页是否有JavaScript错误打印。在可能出错的地方注释掉try-catch,让错误暴露出来。 |
| 解密后请求乱码或报错 | 1. 字符编码问题。解密后的字节数组转为字符串时用了错误的编码。 2. 加密算法模式或填充方式不对。 3. 密钥或IV错误。 | 1. 尝试使用new java.lang.String(decryptedBytes, "UTF-8")或"GBK"等不同编码。2. 确认逆向出的算法细节:是AES-CBC还是ECB?是PKCS7填充还是ZeroPadding? 3. 核对密钥和IV的值和格式(是否是字符串,是否需要Hex解码)。 |
| Content-Length不正确导致服务器拒收 | Hook中修改了Body,但没有更新Content-Length请求头。 | 在beforeRequest和beforeResponse函数中,修改Body后,必须调用更新Content-Length的辅助函数(见上文示例代码)。 |
| 联动Sqlmap/Xray失败 | 1. Sqlmap/Xray路径配置错误。 2. 系统环境变量问题(如python命令找不到)。 3. 发送的请求本身不完整或格式不对。 | 1. 在Galaxy配置中填写绝对路径。对于Sqlmap,可以填python /absolute/path/to/sqlmap.py。2. 尝试在系统命令行中直接运行你配置的命令,看是否成功。 3. 确保你右键发送的请求是一个完整的、有效的HTTP请求(最好从Proxy history中发送,而非Repeater中未发送的)。 |
| 性能问题,Burp变卡 | 1. Hook脚本逻辑过于复杂或低效。 2. Scope配置过宽,处理了所有流量。 3. 同时启用了多个重型Hook。 | 1. 优化JavaScript代码,避免在Hook中进行复杂的循环或同步网络请求。 2. 将Scope精确到需要测试的域名和URL路径。 3. 非必要时禁用其他插件或Hook。 |
5.3 高级场景:处理动态密钥与签名
最棘手的情况是密钥动态生成,或者请求体包含基于内容计算的签名(如HMAC-SHA256)。这要求Hook脚本不仅能加解密,还要能复现客户端的密钥生成和签名逻辑。
思路:
- 逆向密钥生成逻辑:通过Hook客户端(浏览器JS或移动端APP),找到密钥是如何产生的。可能来源于一个固定的种子加上时间戳,或者是一次登录会话中服务器下发的Token。
- 在Hook中实现该逻辑:将逆向出的密钥生成算法用JavaScript重写。可能需要用到
Date.now()获取时间戳,并进行一些运算。 - 处理签名:
- 在
beforeRequest中,先解密Body得到明文P。 - 根据明文P和动态密钥,计算签名S。
- 将签名S以某种形式(如放在Header的
X-Signature字段)添加到请求中。 - 注意:计算签名用的明文,必须是最终要发送的明文。有时签名会涵盖URL参数、特定Header和Body的组合,需要完全模拟客户端行为。
- 在
这部分的Hook脚本会非常复杂,且高度定制化,是Galaxy使用的最高阶形态。它要求测试者具备较强的逆向工程和代码能力。当成功实现时,你将能完全自动化地测试这类安全性极高的接口,这是手动测试无法想象的效率提升。