Version: 2.5 Update

This commit is contained in:
gh0stkey
2023-10-12 21:38:27 +08:00
parent dd08ffaaa2
commit e68619d1c2
39 changed files with 1776 additions and 1329 deletions

View File

@@ -0,0 +1,26 @@
package burp.core;
import java.util.HashMap;
import java.util.Map;
/**
* @author EvilChen
*/
public class GlobalCachePool {
// 用于缓存匹配结果,以请求/响应的MD5 Hash作为索引
private static final Map<String, Map<String, Map<String, Object>>> cache = new HashMap<>();
public static void addToCache(String key, Map<String, Map<String, Object>> value) {
cache.put(key, value);
}
public static Map<String, Map<String, Object>> getFromCache(String key) {
return cache.get(key);
}
public static void removeFromCache(String key) {
cache.remove(key);
}
}

View File

@@ -0,0 +1,68 @@
package burp.core.processor;
import burp.config.ConfigEntry;
import java.util.*;
/**
* @author EvilChen
*/
public class ColorProcessor {
private String finalColor = "";
public List<Integer> retrieveColorIndices(List<String> colors){
List<Integer> indices = new ArrayList<>();
String[] colorArray = ConfigEntry.colorArray;
int size = colorArray.length;
for (String color : colors) {
for (int i = 0; i < size; i++) {
if (colorArray[i].equals(color)) {
indices.add(i);
}
}
}
return indices;
}
/**
* 颜色升级递归算法
*/
private void upgradeColors(List<Integer> colorList) {
int colorSize = colorList.size();
String[] colorArray = ConfigEntry.colorArray;
colorList.sort(Comparator.comparingInt(Integer::intValue));
int i = 0;
List<Integer> stack = new ArrayList<>();
while (i < colorSize) {
if (stack.isEmpty()) {
stack.add(colorList.get(i));
} else {
if (!Objects.equals(colorList.get(i), stack.stream().reduce((first, second) -> second).orElse(99999999))) {
stack.add(colorList.get(i));
} else {
stack.set(stack.size() - 1, stack.get(stack.size() - 1) - 1);
}
}
i++;
}
// 利用HashSet删除重复元素
HashSet tmpList = new HashSet(stack);
if (stack.size() == tmpList.size()) {
stack.sort(Comparator.comparingInt(Integer::intValue));
if(stack.get(0) < 0) {
this.finalColor = colorArray[0];
} else {
this.finalColor = colorArray[stack.get(0)];
}
} else {
this.upgradeColors(stack);
}
}
public String retrieveFinalColor(List<Integer> colorList) {
upgradeColors(colorList);
return finalColor;
}
}

View File

@@ -0,0 +1,201 @@
package burp.core.processor;
import burp.core.GlobalCachePool;
import burp.core.utils.HashCalculator;
import burp.core.utils.MatchTool;
import burp.config.ConfigEntry;
import burp.core.utils.StringHelper;
import dk.brics.automaton.Automaton;
import dk.brics.automaton.AutomatonMatcher;
import dk.brics.automaton.RegExp;
import dk.brics.automaton.RunAutomaton;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.ArrayList;
import java.util.List;
import jregex.Matcher;
import jregex.Pattern;
/**
* @author EvilChen
*/
public class DataProcessingUnit {
public Map<String, String> extractDataFromMap(Map<String, Map<String, Object>> inputData) {
Map<String, String> extractedData = new HashMap<>();
inputData.keySet().forEach(key -> {
Map<String, Object> tempMap = inputData.get(key);
String data = tempMap.get("data").toString();
extractedData.put(key, data);
});
return extractedData;
}
public List<List<String>> extractColorsAndComments(Map<String, Map<String, Object>> inputData) {
List<String> colorList = new ArrayList<>();
List<String> commentList = new ArrayList<>();
inputData.keySet().forEach(key -> {
Map<String, Object> tempMap = inputData.get(key);
String color = tempMap.get("color").toString();
colorList.add(color);
commentList.add(key);
});
List<List<String>> result = new ArrayList<>();
result.add(colorList);
result.add(commentList);
return result;
}
public Map<String, Map<String, Object>> matchContentByRegex(byte[] content, String headers, byte[] body, String scopeString, String host)
throws NoSuchAlgorithmException {
// 先从池子里判断是否有已经匹配好的结果
String messageIndex = HashCalculator.calculateHash(content);
Map<String, Map<String, Object>> map = GlobalCachePool.getFromCache(messageIndex);
if (map != null) {
return map;
} else {
// 最终返回的结果
Map<String, Map<String, Object>> finalMap = new HashMap<>();
ConfigEntry.globalRules.keySet().forEach(i -> {
for (Object[] objects : ConfigEntry.globalRules.get(i)) {
// 多线程执行,一定程度上减少阻塞现象
Thread t = new Thread(() -> {
String matchContent = "";
// 遍历获取规则
List<String> result = new ArrayList<>();
Map<String, Object> tmpMap = new HashMap<>();
String name = objects[1].toString();
boolean loaded = (Boolean) objects[0];
String regex = objects[2].toString();
String color = objects[3].toString();
String scope = objects[4].toString();
String engine = objects[5].toString();
boolean sensitive = (Boolean) objects[6];
// 判断规则是否开启与作用域
if (loaded && (scope.contains(scopeString) || scope.contains("any"))) {
switch (scope) {
case "any":
case "request":
case "response":
matchContent = new String(content, StandardCharsets.UTF_8).intern();
break;
case "any header":
case "request header":
case "response header":
matchContent = headers;
break;
case "any body":
case "request body":
case "response body":
matchContent = new String(body, StandardCharsets.UTF_8).intern();
break;
default:
break;
}
if ("nfa".equals(engine)) {
Pattern pattern;
// 判断规则是否大小写敏感
if (sensitive) {
pattern = new Pattern(regex);
} else {
pattern = new Pattern(regex, Pattern.IGNORE_CASE);
}
Matcher matcher = pattern.matcher(matchContent);
while (matcher.find()) {
// 添加匹配数据至list
// 强制用户使用()包裹正则
result.add(matcher.group(1));
}
} else {
RegExp regexp = new RegExp(regex);
Automaton auto = regexp.toAutomaton();
RunAutomaton runAuto = new RunAutomaton(auto, true);
AutomatonMatcher autoMatcher = runAuto.newMatcher(matchContent);
while (autoMatcher.find()) {
// 添加匹配数据至list
// 强制用户使用()包裹正则
result.add(autoMatcher.group());
}
}
// 去除重复内容
HashSet tmpList = new HashSet(result);
result.clear();
result.addAll(tmpList);
String nameAndSize = String.format("%s (%s)", name, result.size());
if (!result.isEmpty()) {
tmpMap.put("color", color);
String dataStr = String.join("\n", result);
tmpMap.put("data", dataStr);
finalMap.put(nameAndSize, tmpMap);
// 添加到全局变量中便于Databoard检索
if (!host.isEmpty()) {
List<String> dataList = Arrays.asList(dataStr.split("\n"));
if (ConfigEntry.globalDataMap.containsKey(host)) {
Map<String, List<String>> gRuleMap = new HashMap<>(ConfigEntry.globalDataMap.get(host));
if (gRuleMap.containsKey(name)) {
// gDataList为不可变列表因此需要重新创建一个列表以便于使用addAll方法
List<String> gDataList = gRuleMap.get(name);
List<String> newDataList = new ArrayList<>(gDataList);
newDataList.addAll(dataList);
newDataList = new ArrayList<>(new HashSet<>(newDataList));
gRuleMap.remove(name);
gRuleMap.put(name, newDataList);
} else {
gRuleMap.put(name, dataList);
}
ConfigEntry.globalDataMap.remove(host);
ConfigEntry.globalDataMap.put(host, gRuleMap);
} else {
Map<String, List<String>> ruleMap = new HashMap<>();
ruleMap.put(name, dataList);
// 添加单一Host
ConfigEntry.globalDataMap.put(host, ruleMap);
}
String[] splitHost = host.split("\\.");
String anyHost = (splitHost.length > 2 && !MatchTool.matchIP(host)) ? StringHelper.replaceFirstOccurrence(host, splitHost[0], "*") : "";
if (!ConfigEntry.globalDataMap.containsKey(anyHost) && anyHost.length() > 0) {
// 添加通配符Host实际数据从查询哪里将所有数据提取
ConfigEntry.globalDataMap.put(anyHost, new HashMap<>());
}
if (!ConfigEntry.globalDataMap.containsKey("*")) {
// 添加通配符全匹配,同上
ConfigEntry.globalDataMap.put("*", new HashMap<>());
}
if (!ConfigEntry.globalDataMap.containsKey("**")) {
// 添加通配符全匹配,同上
ConfigEntry.globalDataMap.put("**", new HashMap<>());
}
}
}
}
});
t.start();
try {
t.join();
} catch (Exception e) {
e.printStackTrace();
}
}
});
GlobalCachePool.addToCache(messageIndex, finalMap);
return finalMap;
}
}
}

View File

@@ -0,0 +1,78 @@
package burp.core.processor;
import burp.IExtensionHelpers;
import burp.core.utils.MatchTool;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MessageProcessor {
MatchTool matcher = new MatchTool();
DataProcessingUnit dataProcessingUnit = new DataProcessingUnit();
ColorProcessor colorProcessor = new ColorProcessor();
public List<Map<String, String>> processMessage(IExtensionHelpers helpers, byte[] content, boolean isRequest, boolean messageInfo, String host)
throws NoSuchAlgorithmException {
List<Map<String, String>> result = new ArrayList<>();
Map<String, Map<String, Object>> obj;
if (isRequest) {
List<String> requestTmpHeaders = helpers.analyzeRequest(content).getHeaders();
String requestHeaders = String.join("\n", requestTmpHeaders);
try {
String urlString = requestTmpHeaders.get(0).split(" ")[1];
urlString = urlString.indexOf("?") > 0 ? urlString.substring(0, urlString.indexOf("?")) : urlString;
if (matcher.matchUrlSuffix(urlString)) {
return result;
}
} catch (Exception e) {
return result;
}
int requestBodyOffset = helpers.analyzeRequest(content).getBodyOffset();
byte[] requestBody = Arrays.copyOfRange(content, requestBodyOffset, content.length);
obj = dataProcessingUnit.matchContentByRegex(content, requestHeaders, requestBody, "request", host);
} else {
try {
String inferredMimeType = String.format("hae.%s", helpers.analyzeResponse(content).getInferredMimeType().toLowerCase());
String statedMimeType = String.format("hae.%s", helpers.analyzeResponse(content).getStatedMimeType().toLowerCase());
if (matcher.matchUrlSuffix(statedMimeType) || matcher.matchUrlSuffix(inferredMimeType)) {
return result;
}
} catch (Exception e) {
return result;
}
List<String> responseTmpHeaders = helpers.analyzeResponse(content).getHeaders();
String responseHeaders = String.join("\n", responseTmpHeaders);
int responseBodyOffset = helpers.analyzeResponse(content).getBodyOffset();
byte[] responseBody = Arrays.copyOfRange(content, responseBodyOffset, content.length);
obj = dataProcessingUnit.matchContentByRegex(content, responseHeaders, responseBody, "response", host);
}
if (obj.size() > 0) {
if (messageInfo) {
List<List<String>> resultList = dataProcessingUnit.extractColorsAndComments(obj);
List<String> colorList = resultList.get(0);
List<String> commentList = resultList.get(1);
if (!colorList.isEmpty() && !commentList.isEmpty()) {
String color = colorProcessor.retrieveFinalColor(colorProcessor.retrieveColorIndices(colorList));
Map<String, String> colorMap = new HashMap<String, String>() {{
put("color", color);
}};
Map<String, String> commentMap = new HashMap<String, String>() {{
put("comment", String.join(", ", commentList));
}};
result.add(colorMap);
result.add(commentMap);
}
} else {
result.add(dataProcessingUnit.extractDataFromMap(obj));
}
}
return result;
}
}

View File

@@ -0,0 +1,28 @@
package burp.core.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author EvilChen
*/
public class HashCalculator {
public static String calculateHash(byte[] bytes) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] hashBytes = digest.digest(bytes);
return bytesToHex(hashBytes);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}

View File

@@ -0,0 +1,24 @@
package burp.core.utils;
import jregex.Pattern;
import jregex.REFlags;
import burp.config.ConfigLoader;
/**
* @author EvilChen
*/
public class MatchTool {
// 匹配后缀
ConfigLoader configLoader = new ConfigLoader();
public boolean matchUrlSuffix(String str) {
Pattern pattern = new Pattern(String.format("[\\w]+[\\.](%s)", configLoader.getExcludeSuffix()), REFlags.IGNORE_CASE);
jregex.Matcher matcher = pattern.matcher(str);
return matcher.find();
}
public static boolean matchIP(String str) {
return str.matches("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b");
}
}

View File

@@ -0,0 +1,30 @@
package burp.core.utils;
public class StringHelper {
public static String replaceFirstOccurrence(String original, String find, String replace) {
int index = original.indexOf(find);
if (index != -1) {
return original.substring(0, index) + replace + original.substring(index + find.length());
}
return original;
}
public static boolean matchFromEnd(String input, String pattern) {
int inputLength = input.length();
int patternLength = pattern.length();
int inputIndex = inputLength - 1;
int patternIndex = patternLength - 1;
while (inputIndex >= 0 && patternIndex >= 0) {
if (input.charAt(inputIndex) != pattern.charAt(patternIndex)) {
return false;
}
inputIndex--;
patternIndex--;
}
// 如果patternIndex为-1表示pattern字符串已经完全匹配
return patternIndex == -1;
}
}