目前项目测试中总会遇到很多的加解密相关的请求和响应,由于早期的加解密插件不太好用,且目前加解密请求响应越来越普遍,因此就尝试自己写一个简单的burp加解密插件
环境基础
本次编写用到软件及平台有:Windows10+burpsuite_community24.5.3+IntelliJ IDEA Community Edition 2023.2.3+Visual Studio Code+nodejs1.18
本次涉及相关参考插件:xia.SQL.3.3.jdk16.jar+Galaxy加解密插件
IDEA配置
01 新建maven项目
02 maven配置pom.xml
<dependencies>
<!-- https://mvnrepository.com/artifact/net.portswigger.burp.extensions/montoya-api -->
<dependency>
<groupId>net.portswigger.burp.extensions</groupId>
<artifactId>montoya-api</artifactId>
<version>2023.12.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.51</version>
</dependency>
</dependencies>
新增对应的文件夹,并新增对应的初始化调用类:BurpExtender类
测试问题
测试发现的问题:对应的程序,默认请求全局加密,密钥放在请求头sign中,密钥和当前时间组合后做RSA加密,响应为json报文部分加密,具体如下
默认解决方法
测试发现对应的加解密使用了通用型加解密算法:AES/ECB/PKCS5Padding和RSA算法
具体实现脚本可以在对应的js脚本中找到
想要运行对应的js代码,需要使用Visual Studio Code和NodeJS进行联动才能运行指定的js代码
加解密算法
依据对应的加解密算法,尝试在网上找到对应的Java实现代码
AES-ECB算法
public class Encryptor {
private static final String AES_ECB = "AES/ECB/PKCS5Padding";
private static final Integer IV_LENGTH = 16;
public static SecretKeySpec getSecretKeySpec(String key) {
SecretKeySpec secretKeySpec = new SecretKeySpec(getBytes(key), "AES");
return secretKeySpec;
}
public static byte[] getBytes(String str) {
if (isEmpty(str)) {
return null;
}
try {
return str.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static boolean isEmpty(Object str) {
return null == str || "".equals(str);
}
public static String getIV() {
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < IV_LENGTH.intValue(); i++) {
int number = random.nextInt("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".length());
sb.append("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".charAt(number));
}
return sb.toString();
}
public static String encrypt(String text, String key) {
if (isEmpty(text) || isEmpty(key)) {
return null;
}
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(1, secretKeySpec);
byte[] encryptedBytes = cipher.doFinal(getBytes(text));
return Base64.getEncoder().encodeToString(encryptedBytes);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static String decrypt(String text, String key) {
if (isEmpty(text) || isEmpty(key)) {
return null;
}
byte[] textBytes = Base64.getDecoder().decode(text);
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
SecretKeySpec secretKeySpec = getSecretKeySpec(key);
cipher.init(2, secretKeySpec);
byte[] decryptedBytes = cipher.doFinal(textBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
String key = "8****a";
String test = "7***********=";
String dff = decrypt(test, key);
System.out.println(dff);
}
}
RSA签名算法
public class RSACrypto {
public static PublicKey getPublicKeyFromString(String publicKeyStr) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(publicKeyStr);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
public static String encryptWithPublicKey(String publicKeyStr, String data) throws Exception {
PublicKey publicKey = getPublicKeyFromString(publicKeyStr);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static void main(String[] args) {
try {
// 示例公钥,实际使用时需要替换为有效的公钥
String publicKeyStr = "M************B";
// 待加密的数据
String data_time = String.valueOf(System.currentTimeMillis());
String data = "b****t0_"+data_time;
System.out.println("Date: " + data_time);
String encryptedData = encryptWithPublicKey(publicKeyStr, data);
System.out.println("Encrypted Data: " + encryptedData);
} catch (Exception e) {
e.printStackTrace();
}
}
}
基于对应的算法,尝试开发burpsuite插件以便于测试
burp插件开发流程
开发需求
主要涉及如下信息:
burpsuite插件,需要有新的可输入内容的页面,在对应的页面中可以输入host白名单,输入aes_ecb对应的密钥
开发代码
拟定最终效果页面如下:
需要有对应的key输入位置,和设置白名单位置
初始化代码
初始化代码中使用本次涉及的三个类:burp使用三处核心类:registerRequestHandler,registerResponseHandler,registerHttpHandler
Package burp.api.montoya.proxy
registerRequestHandler,registerResponseHandler
Package burp.api.montoya.http
registerHttpHandler
montoyaApi.proxy().registerRequestHandler(new MyProxyRequestHandler(montoyaApi));
montoyaApi.proxy().registerResponseHandler(new MyProxyResponseHandler(montoyaApi));
montoyaApi.http().registerHttpHandler(new MyHttpHandler(montoyaApi));
设置对应的页面显示
在初始化代码中可以配置对应的页面及相关设置
对应的三个类使用了各自的构造方法
MyProxyRequestHandler类
MyProxyRequestHandler类对应的位置为浏览器到proxy和proxy到http之间
配置初始数据点
如果修改对应的请求数据,则会改变burpsuite-proxy-history对应的原始请求数据,一般不需要在这边对请求数据进行修改,但是可以在handleRequestReceived做一些初始化操作,如获取key数据,获取请求的ID值等操作,Proxy_Req_In
请求解密点
handleRequestToBeSent对应burpsuite-proxy-history-edited请求的修改页面,该处可以修改相关加密数据为对应的明文数据,Proxy_Req_Out(解密)
MyHttpHandler类
MyHttpHandler类对应的位置为burp到服务器和服务器返回的响应之间
包含两个方法handleHttpRequestToBeSent(发往服务器)类和handleHttpResponseReceived(服务器返回响应)类
发往服务器请求加密点
handleHttpRequestToBeSent类可以发送原始数据到服务器中,默认需要使用修改后的请求数据进行加密后发送到服务器(如果直接使用原始数据,会导致在repeater中无法使用),Http_Req_Out
服务器返回响应解密点(该处需要记录原始响应到公共池中)
handleHttpResponseReceived类,如果对对应的响应进行修改,显示到burp就是对应的原始响应,该处需要记录原始响应到公共池中,用于最终返回到前端或浏览器,Http_Resp_In
MyProxyResponseHandler类
MyProxyResponseHandler类对应的位置http响应和浏览器之间
包含两个方法handleResponseReceived类和handleResponseToBeSent类
handleResponseReceived类(一般不用修改),Proxy_Resp_In
返回前端原始响应数据
handleResponseToBeSent类(如果在http类中修改了原始响应)该类就需要换成对应的原始响应了,Proxy_Resp_Out
对应burpsuite位置
01 Proxy-HTTP history
02 Repeater对应的为Http相关配置信息
三大类对应流程图
burp插件开发对应的流程图示:
感谢:
目前比较完善的burpsuite加解密插件Galaxy:GitHub - outlaws-bai/Galaxy: Burp插件,自动解密被加密的报文,让你像测试明文一样简单。A Burp plugin that automatically decrypts encrypted messages, making it as simple as testing plaintext.
Galaxy插件示例:GitHub - outlaws-bai/GalaxyDemo: HTTP报文二次加密的具体实现,用于测试 https://github.com/outlaws-bai/Galaxy 中的示例
Galaxy插件使用学习(对应版本2.2.8):[工具推荐]前端加解密之Burp插件Galaxy_burp自动解密数据-优快云博客
本次使用的代码相关:xia SQL(瞎注) burp插件(www.nmd5.com)GitHub - smxiazi/xia_sql: xia SQL (瞎注) burp 插件 ,在每个参数后面填加一个单引号,两个单引号,一个简单的判断注入小插件。
AES加解密代码:Java实现AES加密和解密方式完整示例_java_脚本之家
RSA加解密代码:通过Java实现RSA加密与验证的方法详解_java_脚本之家