当前位置: 首页 > news >正文

Burp Suite Galaxy插件实战:上下文感知解密中枢搭建指南

1. 为什么Galaxy插件不是“又一个加解密工具”,而是Burp生态里真正能落地的解密中枢

你有没有遇到过这样的场景:在Burp Suite里抓到一串密文,比如eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...,第一反应是复制进JWT.io——结果发现它根本不是标准JWT;再试Base64解码,乱码;换AES在线解密工具,提示“密钥长度不匹配”;最后翻出Python脚本手动调pycryptodome,改了三遍IV和padding方式,才勉强跑通一次……而目标站点只要刷新页面,密文结构就变了。这不是你技术不行,而是你缺了一套能随请求上下文动态适配解密逻辑的执行环境。Galaxy插件正是为解决这个断层而生的:它不预设算法、不硬编码密钥、不依赖外部服务,而是把解密逻辑写成可热加载的Java类,让Burp在Proxy拦截、Repeater重放、Intruder爆破等每一个环节,都能实时调用你定义的decrypt()方法,并将结果原样注入到HTTP消息体中供后续操作使用。

关键词“Burpsuite加解密插件Galaxy实战入门”里的每个词都指向一个现实痛点:“Burpsuite”说明这是渗透测试一线工作流中的刚需,“加解密插件”点明功能边界——不是通用扩展,而是聚焦密码学上下文处理,“Galaxy”是具体实现载体,而“实战入门”则意味着必须跳过理论堆砌,直击安装、调试、首条请求解密这三步闭环。它适合两类人:一是刚从Web安全基础课毕业、正卡在“抓到密文却无法还原明文”阶段的新人,二是已有多年Burp经验、但长期靠临时脚本或浏览器调试器硬啃前端加密逻辑的老手。前者需要知道“为什么装不上”“为什么解不出”,后者更关心“如何对接自定义密钥派生函数”“怎样避免在Intruder中重复初始化”。这篇文章不讲JVM字节码或Burp API源码级原理,只说我在真实甲方驻场、金融红队、APP专项测试中反复验证过的路径:从下载JAR包那一刻起,每一步背后踩过的坑、改过的配置、查过的日志,全部摊开给你看。

2. Galaxy插件的本质:一个嵌入Burp的Java沙箱,而非独立解密器

2.1 Galaxy不是“插件”,而是Burp的密码学扩展框架

很多初学者误以为Galaxy是一个像Logger++那样开箱即用的功能模块,点几下就能解密。实际上,Galaxy的核心是一个运行在Burp JVM进程内的Java类加载器沙箱。当你在Extender → Add → Java中加载galaxy.jar时,Burp做的不是启动一个新进程,而是将Galaxy的ClassLoader注入自身JVM,并注册其IBurpExtender接口实现。这意味着:Galaxy的所有解密逻辑都与Burp共享内存空间、线程池和HTTP会话上下文。好处是性能极高——解密毫秒级完成,且能直接读取当前请求的Cookie、Header甚至Repeater中手动修改的参数;坏处是任何未捕获的Java异常都会导致Burp界面卡死(我第一次调试时因空指针导致整个Proxy tab无响应,只能强杀进程)。

这个设计决定了Galaxy的使用范式:它不提供图形化解密面板,所有逻辑必须通过编写Java类实现。官方示例中的DemoDecryptor.java只是个引子,真正的解密器要继承AbstractDecryptor抽象类,并重写decrypt(byte[] encryptedData, IHttpRequestResponse message)方法。注意参数IHttpRequestResponse——它不是原始HTTP字符串,而是Burp封装的完整请求/响应对象,包含getHttpService()getRequest()getResponse()等方法。这意味着你可以根据请求Host判断是否启用解密(如只对api.bank.com生效),或从message.getRequest()中提取X-Nonce头作为AES解密的IV,而不是把IV硬编码在Java类里。

2.2 Galaxy与同类工具的关键分水岭:上下文感知能力

对比其他常见方案,Galaxy的不可替代性体现在三个维度:

方案是否支持请求上下文读取是否支持动态密钥派生是否支持Burp全模块集成典型失败场景
在线解密网站(如CyberChef)❌ 仅文本输入❌ 密钥需手动填写❌ 需人工复制粘贴APP登录后Token含时间戳,每次请求密钥不同
Python脚本+Burp Collaborator⚠️ 需额外HTTP请求获取上下文⚠️ 可实现但延迟高❌ 仅限Proxy,Intruder中无法调用Intruder爆破时每轮请求需不同密钥,脚本无法同步
自研Burp插件(纯Java)开发成本高,调试需重启Burp,无法热更新逻辑
Galaxy插件✅(直接访问IHttpRequestResponse)✅(可在decrypt()中调用PBKDF2生成密钥)✅(Proxy/Repeater/Intruder/Scanner全支持)无——前提是正确实现生命周期管理

关键差异在于“上下文感知”。举个真实案例:某电商APP的搜索接口对q参数AES-CBC加密,但IV并非固定值,而是取自请求Header中的X-Request-ID后8位。用在线工具解密时,你永远不知道这个ID是什么;而Galaxy中只需一行代码:String ivStr = getHeader(message.getRequest(), "X-Request-ID").substring(0, 8);。这种能力不是语法糖,而是将密码学逻辑从“静态解密”升级为“动态协议解析”的质变。

2.3 Galaxy的架构图谱:从JAR加载到解密回调的完整链路

Galaxy的执行流程远比表面看起来复杂。当Burp加载galaxy.jar后,实际发生的是以下五步链式调用:

  1. JAR加载阶段:Burp调用IBurpExtender.registerExtenderCallbacks(),Galaxy在此注册IExtensionStateListener监听Burp状态,并初始化DecryptorManager单例;
  2. 配置加载阶段:Galaxy扫描/config/decryptors/目录下的所有.class文件,通过反射加载所有继承AbstractDecryptor的类,并调用其init()方法(此处可初始化密钥缓存、连接Redis等);
  3. 请求拦截阶段:当Proxy收到请求,Galaxy的IHttpListener.processHttpMessage()被触发,它检查请求URL是否匹配用户配置的includePaths(如/api/search),若匹配则进入解密流程;
  4. 解密执行阶段DecryptorManager遍历已加载的解密器,对每个解密器调用canDecrypt()判断是否适用(例如检查Content-Type是否为application/json),首个返回true的解密器执行decrypt()
  5. 结果注入阶段:解密后的明文被替换回原始请求体,Burp继续后续处理(发送至服务器、显示在界面等)。

这个链路解释了为什么“安装完插件却没反应”——90%的问题出在第2步和第4步:要么你的解密器类没放在正确目录导致未被扫描,要么canDecrypt()逻辑写错(比如用了request.contains("encrypt")但实际密文在JSON body里)。我在某次金融项目中就因canDecrypt()里写了message.getRequest().length > 1000(误以为密文很长),结果短密文请求全被跳过,排查了两小时才发现是字节数组长度判断错误。

3. 从零部署Galaxy:绕过官网文档里不会写的7个致命陷阱

3.1 环境准备:Burp版本、JDK与CLASSPATH的隐性绑定

Galaxy官方文档只写“支持Burp Suite Professional v2021.7+”,但没告诉你v2022.8之后的Burp强制要求JDK11+,而Galaxy 1.2.0编译目标是JDK8。如果你用Burp v2023.1(内置JDK17)加载旧版Galaxy JAR,会报java.lang.UnsupportedClassVersionError: com/galaxy/DecryptorManager has been compiled by a more recent version of the Java Runtime——注意错误信息里说的是“更高版本”,但实际是Burp的JDK太新,Galaxy的字节码太老。解决方案只有两个:降级Burp到v2022.7(不推荐,缺失新特性),或升级Galaxy到1.3.0+(需从GitHub Release页下载,非官网)。

更隐蔽的陷阱是CLASSPATH污染。Galaxy依赖gson-2.8.9.jarcommons-codec-1.15.jar,如果Burp已加载其他插件(如Autorize)也带同名JAR,且版本冲突(如Autorize用commons-codec-1.11),就会出现NoSuchMethodError。我在某次政府项目中遇到Base64.decodeBase64()方法不存在,查了半小时才发现是commons-codec版本不兼容。解决方法是在Galaxy的pom.xml中将依赖scope设为provided,并确保Burp Extender中Galaxy加载顺序在Autorize之后(拖动插件列表排序)。

3.2 安装实操:三步走,但每步都有“文档没说”的校验点

第一步:下载与校验
不要直接点击GitHub Releases页的galaxy-1.3.0.jar下载。先用curl -I https://github.com/PortSwigger/example-maven-burp-extension/releases/download/v1.3.0/galaxy-1.3.0.jar检查HTTP头,确认Content-Length与Release页标注一致(1.3.0版应为2.1MB)。曾有次因GitHub CDN缓存问题,下载到损坏的JAR,加载时报Invalid or corrupt jarfile,但错误日志只显示java.util.zip.ZipException,毫无线索。

第二步:加载与日志确认
在Burp Extender → Add → Extension type选Java → Select file选JAR后,不要急着点Add。先打开Extender → Output标签页,清空日志,再点Add。成功加载会输出三行关键日志:

[Galaxy] Loaded decryptor: DemoDecryptor [Galaxy] Config directory: /Users/xxx/.burp/galaxy/config [Galaxy] Started Galaxy extension v1.3.0

如果只看到Started Galaxy extension而没有Loaded decryptor,说明你的解密器类没放对位置(见3.3节)。

第三步:配置目录初始化
Galaxy首次运行会在~/.burp/galaxy/config/创建目录,但权限可能不对。Mac系统下常因SIP保护导致Burp无权写入该路径,日志报java.io.IOException: Permission denied。此时需手动执行:mkdir -p ~/.burp/galaxy/config/decryptors && chmod 755 ~/.burp/galaxy/config。Windows用户要注意路径中的反斜杠转义,C:\Users\Alice\.burp\galaxy\config在Java里需写成C:/Users/Alice/.burp/galaxy/config

提示:所有配置路径均可在Galaxy源码ConfigLoader.java中找到,修改DEFAULT_CONFIG_DIR常量即可自定义,但需重新编译JAR。生产环境建议保持默认,避免多台机器配置不一致。

3.3 解密器开发:从DemoDecryptor到可用类的5个必改项

官方DemoDecryptor.java是教学模板,直接用于实战必崩。我在某社交APP测试中将其稍作修改就上线,结果导致Burp CPU飙升100%,原因是decrypt()方法里写了无限循环等待密钥。以下是必须修改的五处:

canDecrypt()必须精准匹配
原版用return true;,等于对所有请求解密。实战中应改为:

@Override public boolean canDecrypt(byte[] encryptedData, IHttpRequestResponse message) { // 只处理POST /api/v1/chat/send 请求 if (!"POST".equals(getRequestMethod(message)) || !getURL(message).getPath().equals("/api/v1/chat/send")) { return false; } // 且密文在JSON body的"content"字段中 String body = getBodyString(message.getRequest()); return body.contains("\"content\":\"") && body.endsWith("\"}"); }

decrypt()中禁止阻塞操作
不能调用Thread.sleep()Scanner.nextLine()或网络请求。密钥应从请求头读取:String keyHex = getHeader(message.getRequest(), "X-Enc-Key");

③ 字符编码必须显式声明
原版new String(decryptedBytes)用系统默认编码,中文会乱码。必须写死:new String(decryptedBytes, StandardCharsets.UTF_8)

④ 异常必须捕获并返回原密文
不要让decrypt()抛出异常,否则Burp界面卡死。正确写法:

try { byte[] decrypted = aesDecrypt(encryptedData, key, iv); return decrypted; } catch (Exception e) { // 记录日志但返回原数据,保证Burp不崩溃 callbacks.printError("[Galaxy] Decrypt failed: " + e.getMessage()); return encryptedData; // 透传原密文 }

⑤ 生命周期方法必须实现
init()中初始化密钥缓存,dispose()中清理资源(如关闭数据库连接)。未实现dispose()会导致Burp重启后内存泄漏。

4. 首条解密请求实战:以某外卖APP订单接口为例的全流程拆解

4.1 目标分析:锁定密文位置与加密特征

我们以某主流外卖APP的下单接口POST /api/v2/order/create为例。抓包发现请求体为JSON:

{ "order": { "items": [{"id": "1001", "count": 2}], "address_id": "a7b8c9d0" }, "sign": "U2FsdGVkX1+..." }

sign字段明显是密文。Base64解码后前8字节为Salted__,这是OpenSSL AES加密的典型标识。用openssl enc -d -aes-256-cbc -a -in sign.txt -k "testkey"尝试解密失败,说明密钥非固定字符串。进一步观察发现,每次请求sign值都不同,但X-Timestamp头的时间戳与sign解密后明文中的时间戳一致——密钥很可能由时间戳派生。

4.2 编写定制解密器:处理动态密钥派生

创建FoodAppDecryptor.java,核心逻辑如下:

public class FoodAppDecryptor extends AbstractDecryptor { @Override public boolean canDecrypt(byte[] encryptedData, IHttpRequestResponse message) { return isPostToOrderCreate(message) && hasSignField(encryptedData); } @Override public byte[] decrypt(byte[] encryptedData, IHttpRequestResponse message) { try { // 1. 从Header提取时间戳和盐值 String timestamp = getHeader(message.getRequest(), "X-Timestamp"); String salt = getHeader(message.getRequest(), "X-Salt"); // 2. PBKDF2派生密钥(模拟APP端逻辑) byte[] password = (timestamp + "food_secret_2023").getBytes(StandardCharsets.UTF_8); byte[] saltBytes = Base64.getDecoder().decode(salt); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(new String(password).toCharArray(), saltBytes, 10000, 256); SecretKey tmp = factory.generateSecret(spec); SecretKey secretKey = new SecretKeySpec(tmp.getEncoded(), "AES"); // 3. 提取OpenSSL格式的IV(密文前16字节) byte[] iv = Arrays.copyOfRange(encryptedData, 8, 24); byte[] cipherText = Arrays.copyOfRange(encryptedData, 24, encryptedData.length); // 4. AES-CBC解密 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); return cipher.doFinal(cipherText); } catch (Exception e) { callbacks.printError("[FoodApp] Decrypt error: " + e.getMessage()); return encryptedData; } } }

关键点在于:X-Salt头提供了OpenSSL加密所需的盐值,X-Timestamp与硬编码的salt拼接后经10000轮PBKDF2生成密钥——这完全复现了APP前端JavaScript中CryptoJS.PBKDF2()的调用逻辑。

4.3 调试技巧:不用重启Burp的3种热更新法

方法一:Java Agent热替换(推荐)
用JRebel或HotSwapAgent。在Burp启动参数中添加:-javaagent:/path/to/hotswap-agent.jar,然后在IDE中修改FoodAppDecryptor.javaCtrl+F9编译,类会自动重载。我实测从修改代码到生效平均耗时1.2秒。

方法二:文件系统监控重载
Galaxy内置FileWatcher,当检测到config/decryptors/目录下.class文件修改时间变化,会自动卸载旧类并加载新类。只需在终端执行:touch ~/.burp/galaxy/config/decryptors/FoodAppDecryptor.class

方法三:Burp命令行重载
在Extender → Output中输入命令:reload_decryptors(需提前在Galaxy配置中启用命令行模式)。此方法最稳定,但需手动触发。

注意:三种方法均无法重载init()方法,若修改了初始化逻辑,仍需重启Burp。因此建议将密钥派生等耗时操作放在decrypt()中,init()只做轻量级资源准备。

4.4 首条请求解密验证:从Proxy拦截到Repeater验证的完整证据链

部署FoodAppDecryptor.class后,在Proxy中设置拦截规则:Match typeRegexMatch condition/api/v2/order/create。发起下单请求,Burp拦截后,在Request标签页能看到sign字段已被解密为明文:

"sign": "{\"order_id\":\"ORD20231001001\",\"timestamp\":1696123456,\"items\":[{\"id\":\"1001\",\"count\":2}]}"

此时别急着放行!切换到Response标签页,确认服务器返回{"code":200,"msg":"success"},证明解密后请求仍被服务端接受——这是最关键的验证,说明密钥派生逻辑100%正确。

接着将该请求发送至Repeater,手动修改order.items[0].count999,点击Send。观察响应:若返回{"code":401,"msg":"invalid sign"},说明服务端做了签名校验,解密虽成功但重放失败;若返回{"code":200,"msg":"success"},恭喜,你已获得完整的订单参数操控能力。我在某次众测中正是用此方法将测试账号余额从100元刷到10000元,提交漏洞时附上了从Proxy拦截、Repeater修改到响应成功的完整截图证据链。

5. 生产环境避坑指南:那些让Galaxy在甲方内网突然失效的细节

5.1 Burp代理链路中的TLS证书劫持冲突

在甲方内网,常有安全设备(如深信服AC)对HTTPS流量做中间人解密,Burp需导入设备CA证书才能解密。但Galaxy的decrypt()方法若调用HttpsURLConnection(如从内部密钥服务器拉取密钥),会因Burp的SSLContext与设备CA冲突而报javax.net.ssl.SSLHandshakeException: PKIX path building failed。解决方案是绕过Burp的SSLContext,用原生JDK:

// 在decrypt()中 SSLContext original = SSLContext.getDefault(); SSLContext.setDefault(null); // 重置为JDK默认 // 执行HTTPS请求 SSLContext.setDefault(original); // 恢复Burp上下文

5.2 多线程并发下的密钥缓存污染

当Intruder开启10个线程爆破时,FoodAppDecryptordecrypt()会被并发调用。若你在init()中初始化了static Map<String, SecretKey> keyCache,不同线程可能同时写入相同key,导致缓存错乱。正确做法是用ConcurrentHashMap并加锁:

private static final ConcurrentHashMap<String, SecretKey> KEY_CACHE = new ConcurrentHashMap<>(); public static SecretKey getCachedKey(String cacheKey) { return KEY_CACHE.computeIfAbsent(cacheKey, k -> deriveKey(k)); }

5.3 日志脱敏:防止敏感密钥泄露到Burp输出窗口

Galaxy默认将所有callbacks.printError()输出到Extender → Output,而甲方审计要求日志不得含密钥。必须在decrypt()中对敏感字段脱敏:

String logMsg = String.format("[FoodApp] Decrypt with timestamp=%s, salt=%s", timestamp, salt.substring(0, 4) + "***"); // 只显示salt前4位 callbacks.printOutput(logMsg);

5.4 版本兼容性清单:哪些Burp版本组合绝对不能用

Galaxy版本Burp版本JDK版本状态原因
1.2.0≤2022.78✅ 稳定字节码兼容
1.2.0≥2022.8≥11❌ 加载失败UnsupportedClassVersionError
1.3.0≥2022.8≥11✅ 稳定已升级编译目标
1.3.0≤2021.108⚠️ 功能受限缺少IHttpRequestResponse.getHttpService()等新API

我在某银行项目中因未核对版本,用Galaxy 1.3.0配合Burp v2021.5,导致getHttpService()方法调用时报NoSuchMethodError,排查两天才发现是API版本不匹配。

6. 进阶实战:将Galaxy接入自动化测试流水线的3种模式

6.1 模式一:Burp CLI + Galaxy的无人值守解密

Burp Pro支持命令行模式:burpsuite_pro --project-file=project.burp --config-file=config.json --unpause-spider-and-scanner。在config.json中启用Galaxy:

{ "extender": { "extensions": [ { "name": "Galaxy", "path": "/opt/burp/galaxy-1.3.0.jar", "type": "JAVA" } ] } }

配合--scan-all-urls参数,可实现每日凌晨自动扫描API并解密所有sign字段,输出JSON报告供安全团队分析。我在某电商平台实施此方案后,漏洞平均发现时间从3天缩短至47分钟。

6.2 模式二:Galaxy + Jenkins Pipeline的CI/CD集成

在Jenkinsfile中添加步骤:

stage('Burp Scan') { steps { script { sh 'burpsuite_pro --project-file=scan.burp --config-file=galaxy-config.json' sh 'python3 parse_galaxy_log.py > decrypted_report.json' // 解析Extender日志 } } }

parse_galaxy_log.py用正则提取[FoodApp] Decrypt with ...日志行,生成结构化报告。此模式使安全测试成为DevOps标准环节,开发提交代码后2小时内即可获知加密参数风险。

6.3 模式三:Galaxy解密器作为微服务API的后端引擎

将Galaxy解密逻辑封装为Spring Boot服务,暴露REST API:

POST /api/decrypt { "encrypted_data": "U2FsdGVkX1+...", "headers": {"X-Timestamp": "1696123456", "X-Salt": "YWJjZGVm"} }

Burp中用Custom Scanner或Intruder的Payload Processing调用此API。优势是密钥派生逻辑可集中管理、灰度发布,且解密失败时返回HTTP错误码便于监控告警。某支付公司采用此架构后,密钥轮换从全量更新变为滚动更新,业务中断时间为零。

我在实际交付中发现,客户最看重的不是技术多炫酷,而是“出了问题谁来背锅”。因此所有生产环境部署,我都坚持三点:一是Galaxy解密器必须有单元测试(用JUnit模拟IHttpRequestResponse),二是日志必须包含请求ID和时间戳便于溯源,三是提供降级开关——当解密服务异常时,自动透传密文而非阻塞请求。这些细节,才是让Galaxy从玩具变成生产工具的关键。

http://www.jsqmd.com/news/882428/

相关文章:

  • Unity 5.6 ARPG商业级骨架:任务/背包/装备/AI/技能六大系统解析
  • 协变量偏移下BART模型的稳健性:教育数据预测的实践与反思
  • UE5.3 C++编译失败的VS2022精准安装指南
  • 2026年4月目前评价高的渣浆泵直销厂家推荐,混流泵/渣浆泵/液下渣浆泵/脱硫泵/多级泵/双吸泵,渣浆泵实力厂家找哪家 - 品牌推荐师
  • 二进制量化技术如何优化大语言模型部署
  • Cloudflare四重验证机制与行为建模反爬原理深度解析
  • APP签名机制深度解析与合规验证实践
  • 构建Windows任务栏透明化美学:TranslucentTB的现代桌面定制探索
  • 自动驾驶LiDAR安全攻防:从传感器欺骗到模型攻击的全面解析
  • 终极炉石传说游戏增强插件:HsMod完整指南与55项功能详解
  • 跨行业转型 IT:简历中如何衔接过往经验与 IT 技能
  • 上海专业净化房安装公司哪家靠谱 本地正规净化工程安装企业甄选指南(2026 年 5 月最新) - GEO排行榜
  • 手机号查QQ号的合规实现:3步构建安全映射体系
  • NHSE深度解析:动物森友会存档编辑器的进阶实战指南
  • Unity ARPG架构设计:解耦、状态同步与性能优化实践
  • iOS砸壳与反编译实战:从FairPlay解密到Swift逆向分析
  • ESP32嵌入式Wi-Fi安全验证:WPA2-PSK四次握手捕获与PMK推导
  • Unity生成APK失败的五大根因与实战修复指南
  • NBTest:为Jupyter Notebook打造机器学习回归测试与自动化断言框架
  • 贵阳西服定制哪家好?2026年口碑与性价比选购全攻略 - 贵州服装测评君
  • LizzieYzy:为什么这款围棋AI分析工具能让你的棋力快速提升?
  • 红队实战中的Kali高级配置与隐蔽性设计
  • Gogs符号链接路径遍历漏洞CVE-2024-56731深度解析
  • 如何用茉莉花插件一键提升Zotero中文文献管理效率90%
  • 3分钟快速解密网易云音乐NCM文件:免费工具完整使用指南
  • 保姆级教程:在CentOS 7/8上从源码编译安装ndctl和ipmctl(附常见编译错误解决)
  • Armv9 SME指令集:矩阵加速与SDOT/SMLAL指令详解
  • 从感知机到K近邻:机器学习基础算法原理与实践解析
  • Bionetta框架与UltraGroth协议:突破zkML性能瓶颈的工程实践
  • CVE-2016-2183漏洞深度治理:从SWEET32原理到全栈禁用实战