Compare commits

...

6 Commits
4.0 ... 4.0.4

Author SHA1 Message Date
gh0stkey
5977e82ca6 Version: 4.0.4 Update 2025-01-17 17:56:35 +08:00
gh0stkey
452f297f55 Version: 4.0.3 Update 2025-01-10 17:45:59 +08:00
gh0stkey
a06ef8e25e Version: 4.0.2 Update 2025-01-08 13:49:12 +08:00
EvilChen
7e53e250af Merge pull request #235 from 0Chencc/master
修复了社区版会无法正常使用HaE的问题
2025-01-08 13:47:38 +08:00
林晨
b686b5e75e 修复了社区版会无法正常使用HaE的问题
社区版由于Scanner的问题无法使用HaE,加入了一处版本判断。
2025-01-02 05:50:14 +08:00
gh0stkey
e83a6a1478 Version: 4.0.1 Update 2024-12-31 15:40:05 +08:00
8 changed files with 112 additions and 104 deletions

View File

@@ -61,6 +61,8 @@ public class Config {
"gray" "gray"
}; };
public static Boolean proVersionStatus = true;
public static Map<String, Object[][]> globalRules = new HashMap<>(); public static Map<String, Object[][]> globalRules = new HashMap<>();
public static ConcurrentHashMap<String, Map<String, List<String>>> globalDataMap = new ConcurrentHashMap<>(); public static ConcurrentHashMap<String, Map<String, List<String>>> globalDataMap = new ConcurrentHashMap<>();

View File

@@ -10,6 +10,7 @@ import hae.component.board.message.MessageTableModel;
import hae.instances.editor.RequestEditor; import hae.instances.editor.RequestEditor;
import hae.instances.editor.ResponseEditor; import hae.instances.editor.ResponseEditor;
import hae.instances.editor.WebSocketEditor; import hae.instances.editor.WebSocketEditor;
import hae.instances.http.HttpMessagePassiveHandler;
import hae.instances.websocket.WebSocketMessageHandler; import hae.instances.websocket.WebSocketMessageHandler;
import hae.utils.ConfigLoader; import hae.utils.ConfigLoader;
import hae.utils.DataManager; import hae.utils.DataManager;
@@ -18,8 +19,8 @@ public class HaE implements BurpExtension {
@Override @Override
public void initialize(MontoyaApi api) { public void initialize(MontoyaApi api) {
// 设置扩展名称 // 设置扩展名称
String version = "4.0";
api.extension().setName("HaE - Highlighter and Extractor"); api.extension().setName("HaE - Highlighter and Extractor");
String version = "4.0.4";
// 加载扩展后输出的项目信息 // 加载扩展后输出的项目信息
Logging logging = api.logging(); Logging logging = api.logging();
@@ -33,6 +34,9 @@ public class HaE implements BurpExtension {
MessageTableModel messageTableModel = new MessageTableModel(api, configLoader); MessageTableModel messageTableModel = new MessageTableModel(api, configLoader);
// 设置BurpSuite专业版状态
Config.proVersionStatus = getBurpSuiteProStatus(api, configLoader, messageTableModel);
// 注册Tab页用于查询数据 // 注册Tab页用于查询数据
api.userInterface().registerSuiteTab("HaE", new Main(api, configLoader, messageTableModel)); api.userInterface().registerSuiteTab("HaE", new Main(api, configLoader, messageTableModel));
@@ -48,6 +52,7 @@ public class HaE implements BurpExtension {
DataManager dataManager = new DataManager(api); DataManager dataManager = new DataManager(api);
dataManager.loadData(messageTableModel); dataManager.loadData(messageTableModel);
api.extension().registerUnloadingHandler(new ExtensionUnloadingHandler() { api.extension().registerUnloadingHandler(new ExtensionUnloadingHandler() {
@Override @Override
public void extensionUnloaded() { public void extensionUnloaded() {
@@ -57,4 +62,19 @@ public class HaE implements BurpExtension {
} }
}); });
} }
private Boolean getBurpSuiteProStatus(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) {
boolean burpSuiteProStatus = false;
try {
burpSuiteProStatus = api.burpSuite().version().name().contains("Professional");
} catch (Exception e) {
try {
api.scanner().registerScanCheck(new HttpMessagePassiveHandler(api, configLoader, messageTableModel)).deregister();
burpSuiteProStatus = true;
} catch (Exception ignored) {
}
}
return burpSuiteProStatus;
}
} }

View File

@@ -135,6 +135,7 @@ public class Config extends JPanel {
modePanel.setLayout(new BoxLayout(modePanel, BoxLayout.X_AXIS)); modePanel.setLayout(new BoxLayout(modePanel, BoxLayout.X_AXIS));
JCheckBox checkBox = new JCheckBox("Enable active http message handler"); JCheckBox checkBox = new JCheckBox("Enable active http message handler");
checkBox.setEnabled(hae.Config.proVersionStatus);
modePanel.add(checkBox); modePanel.add(checkBox);
checkBox.addActionListener(e -> updateModeStatus(checkBox)); checkBox.addActionListener(e -> updateModeStatus(checkBox));
checkBox.setSelected(configLoader.getMode()); checkBox.setSelected(configLoader.getMode());
@@ -379,7 +380,7 @@ public class Config extends JPanel {
configLoader.setMode(selected ? "true" : "false"); configLoader.setMode(selected ? "true" : "false");
if (checkBox.isSelected()) { if (checkBox.isSelected()) {
if (passiveHandler.isRegistered()) { if (hae.Config.proVersionStatus && passiveHandler.isRegistered()) {
passiveHandler.deregister(); passiveHandler.deregister();
} }
@@ -387,7 +388,7 @@ public class Config extends JPanel {
activeHandler = api.http().registerHttpHandler(new HttpMessageActiveHandler(api, configLoader, messageTableModel)); activeHandler = api.http().registerHttpHandler(new HttpMessageActiveHandler(api, configLoader, messageTableModel));
} }
} else { } else {
if (!passiveHandler.isRegistered()) { if (hae.Config.proVersionStatus && !passiveHandler.isRegistered()) {
passiveHandler = api.scanner().registerScanCheck(new HttpMessagePassiveHandler(api, configLoader, messageTableModel)); passiveHandler = api.scanner().registerScanCheck(new HttpMessagePassiveHandler(api, configLoader, messageTableModel));
} }

View File

@@ -136,14 +136,18 @@ public class MessageTableModel extends AbstractTableModel {
if (!isDuplicate) { if (!isDuplicate) {
if (flag) { if (flag) {
DataManager dataManager = new DataManager(api); try {
// 数据存储在BurpSuite空间内 DataManager dataManager = new DataManager(api);
PersistedObject persistedObject = PersistedObject.persistedObject(); // 数据存储在BurpSuite空间内
persistedObject.setHttpRequestResponse("messageInfo", messageInfo); PersistedObject persistedObject = PersistedObject.persistedObject();
persistedObject.setString("comment", comment); persistedObject.setHttpRequestResponse("messageInfo", messageInfo);
persistedObject.setString("color", color); persistedObject.setString("comment", comment);
String uuidIndex = StringProcessor.getRandomUUID(); persistedObject.setString("color", color);
dataManager.putData("message", uuidIndex, persistedObject); String uuidIndex = StringProcessor.getRandomUUID();
dataManager.putData("message", uuidIndex, persistedObject);
} catch (Exception ignored) {
}
} }
// 添加进日志 // 添加进日志

View File

@@ -30,6 +30,7 @@ public class Datatable extends JPanel {
private final JTextField secondSearchField; private final JTextField secondSearchField;
private final TableRowSorter<DefaultTableModel> sorter; private final TableRowSorter<DefaultTableModel> sorter;
private final JCheckBox searchMode = new JCheckBox("Reverse search"); private final JCheckBox searchMode = new JCheckBox("Reverse search");
private final JCheckBox regexMode = new JCheckBox("Regex mode");
private final String tabName; private final String tabName;
private final JPanel footerPanel; private final JPanel footerPanel;
@@ -51,6 +52,8 @@ public class Datatable extends JPanel {
} }
private void initComponents(List<String> dataList) { private void initComponents(List<String> dataList) {
dataTable.setRowSorter(sorter);
// 设置ID排序 // 设置ID排序
sorter.setComparator(0, new Comparator<Integer>() { sorter.setComparator(0, new Comparator<Integer>() {
@Override @Override
@@ -107,7 +110,6 @@ public class Datatable extends JPanel {
JScrollPane scrollPane = new JScrollPane(dataTable); JScrollPane scrollPane = new JScrollPane(dataTable);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
dataTable.setRowSorter(sorter);
TableColumn idColumn = dataTable.getColumnModel().getColumn(0); TableColumn idColumn = dataTable.getColumnModel().getColumn(0);
idColumn.setPreferredWidth(50); idColumn.setPreferredWidth(50);
idColumn.setMaxWidth(100); idColumn.setMaxWidth(100);
@@ -118,10 +120,12 @@ public class Datatable extends JPanel {
optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.X_AXIS)); optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.X_AXIS));
// Settings按钮 // Settings按钮
JPanel settingMenuPanel = new JPanel(new GridLayout(1, 1)); JPanel settingMenuPanel = new JPanel(new GridLayout(2, 1));
settingMenuPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); settingMenuPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
JPopupMenu settingMenu = new JPopupMenu(); JPopupMenu settingMenu = new JPopupMenu();
settingMenuPanel.add(searchMode); settingMenuPanel.add(searchMode);
settingMenuPanel.add(regexMode);
regexMode.setSelected(true);
searchMode.addItemListener(e -> performSearch()); searchMode.addItemListener(e -> performSearch());
settingMenu.add(settingMenuPanel); settingMenu.add(settingMenuPanel);
@@ -162,8 +166,8 @@ public class Datatable extends JPanel {
} }
private void performSearch() { private void performSearch() {
RowFilter<Object, Object> firstRowFilter = applyFirstSearchFilter(); RowFilter<Object, Object> firstRowFilter = getObjectObjectRowFilter(searchField, true);
RowFilter<Object, Object> secondRowFilter = applySecondFilter(); RowFilter<Object, Object> secondRowFilter = getObjectObjectRowFilter(secondSearchField, false);
if (searchField.getForeground().equals(Color.BLACK)) { if (searchField.getForeground().equals(Color.BLACK)) {
sorter.setRowFilter(firstRowFilter); sorter.setRowFilter(firstRowFilter);
if (secondSearchField.getForeground().equals(Color.BLACK)) { if (secondSearchField.getForeground().equals(Color.BLACK)) {
@@ -175,44 +179,29 @@ public class Datatable extends JPanel {
} }
} }
private RowFilter<Object, Object> applyFirstSearchFilter() { private RowFilter<Object, Object> getObjectObjectRowFilter(JTextField searchField, boolean firstFlag) {
return new RowFilter<Object, Object>() { return new RowFilter<Object, Object>() {
public boolean include(Entry<?, ?> entry) { public boolean include(Entry<?, ?> entry) {
String searchFieldTextText = searchField.getText(); String searchFieldTextText = searchField.getText();
Pattern pattern = null;
try {
pattern = Pattern.compile(searchFieldTextText, Pattern.CASE_INSENSITIVE);
} catch (Exception ignored) {
}
String entryValue = ((String) entry.getValue(1)).toLowerCase();
searchFieldTextText = searchFieldTextText.toLowerCase(); searchFieldTextText = searchFieldTextText.toLowerCase();
if (pattern != null) {
return searchFieldTextText.isEmpty() || pattern.matcher(entryValue).find() != searchMode.isSelected();
} else {
return searchFieldTextText.isEmpty() || entryValue.contains(searchFieldTextText) != searchMode.isSelected();
}
}
};
}
private RowFilter<Object, Object> applySecondFilter() {
return new RowFilter<Object, Object>() {
public boolean include(Entry<?, ?> entry) {
String searchFieldTextText = secondSearchField.getText();
Pattern pattern = null;
try {
pattern = Pattern.compile(searchFieldTextText, Pattern.CASE_INSENSITIVE);
} catch (Exception ignored) {
}
String entryValue = ((String) entry.getValue(1)).toLowerCase(); String entryValue = ((String) entry.getValue(1)).toLowerCase();
searchFieldTextText = searchFieldTextText.toLowerCase(); boolean filterReturn = searchFieldTextText.isEmpty();
if (pattern != null) { boolean firstFlagReturn = searchMode.isSelected() && firstFlag;
return searchFieldTextText.isEmpty() || pattern.matcher(entryValue).find(); if (regexMode.isSelected()) {
Pattern pattern = null;
try {
pattern = Pattern.compile(searchFieldTextText, Pattern.CASE_INSENSITIVE);
} catch (Exception ignored) {
}
if (pattern != null) {
filterReturn = filterReturn || pattern.matcher(entryValue).find() != firstFlagReturn;
}
} else { } else {
return searchFieldTextText.isEmpty() || entryValue.contains(searchFieldTextText); filterReturn = filterReturn || entryValue.contains(searchFieldTextText) != firstFlagReturn;
} }
return filterReturn;
} }
}; };
} }
@@ -248,22 +237,6 @@ public class Datatable extends JPanel {
}); });
} }
private String getTableData(JTable table) {
StringBuilder selectData = new StringBuilder();
int rowCount = table.getRowCount();
for (int i = 0; i < rowCount; i++) {
selectData.append(table.getValueAt(i, 1).toString()).append("\r\n");
}
if (!selectData.isEmpty()) {
selectData.delete(selectData.length() - 2, selectData.length());
} else {
return "";
}
return selectData.toString();
}
public String getSelectedDataAtTable(JTable table) { public String getSelectedDataAtTable(JTable table) {
int[] selectRows = table.getSelectedRows(); int[] selectRows = table.getSelectedRows();
StringBuilder selectData = new StringBuilder(); StringBuilder selectData = new StringBuilder();

View File

@@ -111,7 +111,7 @@ public class RegularMatcher {
} }
} }
public static void putDataToGlobalMap(MontoyaApi api, String host, String name, List<String> dataList, boolean flag) { public synchronized static void putDataToGlobalMap(MontoyaApi api, String host, String name, List<String> dataList, boolean flag) {
// 添加到全局变量中便于Databoard检索 // 添加到全局变量中便于Databoard检索
if (!Objects.equals(host, "") && host != null) { if (!Objects.equals(host, "") && host != null) {
Config.globalDataMap.compute(host, (existingHost, existingMap) -> { Config.globalDataMap.compute(host, (existingHost, existingMap) -> {
@@ -125,14 +125,17 @@ public class RegularMatcher {
if (flag) { if (flag) {
// 数据存储在BurpSuite空间内 // 数据存储在BurpSuite空间内
DataManager dataManager = new DataManager(api); try {
PersistedObject persistedObject = PersistedObject.persistedObject(); DataManager dataManager = new DataManager(api);
gRuleMap.forEach((kName, vList) -> { PersistedObject persistedObject = PersistedObject.persistedObject();
PersistedList<String> persistedList = PersistedList.persistedStringList(); gRuleMap.forEach((kName, vList) -> {
persistedList.addAll(vList); PersistedList<String> persistedList = PersistedList.persistedStringList();
persistedObject.setStringList(kName, persistedList); persistedList.addAll(vList);
}); persistedObject.setStringList(kName, persistedList);
dataManager.putData("data", host, persistedObject); });
dataManager.putData("data", host, persistedObject);
} catch (Exception ignored) {
}
} }
return gRuleMap; return gRuleMap;

View File

@@ -19,6 +19,24 @@ public class DataManager {
this.persistence = api.persistence(); this.persistence = api.persistence();
} }
public synchronized void putData(String dataType, String dataName, PersistedObject persistedObject) {
if (persistence.extensionData().getChildObject(dataName) != null) {
persistence.extensionData().deleteChildObject(dataName);
}
persistence.extensionData().setChildObject(dataName, persistedObject);
saveIndex(dataType, dataName);
}
public void loadData(MessageTableModel messageTableModel) {
// 1. 获取索引
PersistedList<String> dataIndex = persistence.extensionData().getStringList("data"); // 数据索引
PersistedList<String> messageIndex = persistence.extensionData().getStringList("message"); // 消息索引
// 2. 从索引获取数据
loadHaEData(dataIndex);
loadMessageData(messageIndex, messageTableModel);
}
private void saveIndex(String indexName, String indexValue) { private void saveIndex(String indexName, String indexValue) {
PersistedList<String> indexList = persistence.extensionData().getStringList(indexName); PersistedList<String> indexList = persistence.extensionData().getStringList(indexName);
@@ -35,32 +53,17 @@ public class DataManager {
persistence.extensionData().setStringList(indexName, indexList); persistence.extensionData().setStringList(indexName, indexList);
} }
public void putData(String dataType, String dataName, PersistedObject persistedObject) {
if (persistence.extensionData().getChildObject(dataName) != null) {
persistence.extensionData().deleteChildObject(dataName);
}
persistence.extensionData().setChildObject(dataName, persistedObject);
saveIndex(dataType, dataName);
}
public void loadData(MessageTableModel messageTableModel) {
// 1. 获取索引
PersistedList<String> dataIndex = persistence.extensionData().getStringList("data"); // 数据索引
PersistedList<String> messageIndex = persistence.extensionData().getStringList("message"); // 消息索引
// 2. 从索引获取数据
loadHaEData(dataIndex);
loadMessageData(messageIndex, messageTableModel);
}
private void loadHaEData(PersistedList<String> dataIndex) { private void loadHaEData(PersistedList<String> dataIndex) {
if (dataIndex != null && !dataIndex.isEmpty()) { if (dataIndex != null && !dataIndex.isEmpty()) {
dataIndex.parallelStream().forEach(index -> { dataIndex.parallelStream().forEach(index -> {
PersistedObject dataObj = persistence.extensionData().getChildObject(index); PersistedObject dataObj = persistence.extensionData().getChildObject(index);
dataObj.stringListKeys().forEach(dataKey -> { try {
RegularMatcher.putDataToGlobalMap(api, index, dataKey, dataObj.getStringList(dataKey).stream().toList(), false); dataObj.stringListKeys().forEach(dataKey -> {
}); RegularMatcher.putDataToGlobalMap(api, index, dataKey, dataObj.getStringList(dataKey).stream().toList(), false);
});
} catch (Exception e) {
// api.logging().logToOutput("loadHaEData:" + e.getMessage());
}
}); });
} }
} }
@@ -69,16 +72,18 @@ public class DataManager {
if (messageIndex != null && !messageIndex.isEmpty()) { if (messageIndex != null && !messageIndex.isEmpty()) {
messageIndex.parallelStream().forEach(index -> { messageIndex.parallelStream().forEach(index -> {
PersistedObject dataObj = persistence.extensionData().getChildObject(index); PersistedObject dataObj = persistence.extensionData().getChildObject(index);
HttpRequestResponse messageInfo = dataObj.getHttpRequestResponse("messageInfo"); if (dataObj != null) {
String comment = dataObj.getString("comment"); HttpRequestResponse messageInfo = dataObj.getHttpRequestResponse("messageInfo");
String color = dataObj.getString("color"); String comment = dataObj.getString("comment");
HttpRequest request = messageInfo.request(); String color = dataObj.getString("color");
HttpResponse response = messageInfo.response(); HttpRequest request = messageInfo.request();
String method = request.method(); HttpResponse response = messageInfo.response();
String url = request.url(); String method = request.method();
String status = String.valueOf(response.statusCode()); String url = request.url();
String length = String.valueOf(response.toByteArray().length()); String status = String.valueOf(response.statusCode());
messageTableModel.add(messageInfo, url, method, status, length, comment, color, false); String length = String.valueOf(response.toByteArray().length());
messageTableModel.add(messageInfo, url, method, status, length, comment, color, false);
}
}); });
} }
} }

View File

@@ -231,7 +231,7 @@ rules:
rule: rule:
- name: Linkfinder - name: Linkfinder
loaded: true loaded: true
f_regex: (?:"|')(((?:[a-zA-Z]{1,10}://|//)[^"'/]{1,}\.[a-zA-Z]{2,}[^"']{0,})|((?:/|\.\./|\./)[^"'><,;|*()(%%$^/\\\[\]][^"'><,;|()]{1,})|([a-zA-Z0-9_\-/]{1,}/[a-zA-Z0-9_\-/]{1,}\.(?:[a-zA-Z]{1,4}|action)(?:[\?|#][^"|']{0,}|))|([a-zA-Z0-9_\-/]{1,}/[a-zA-Z0-9_\-/]{3,}(?:[\?|#][^"|']{0,}|))|([a-zA-Z0-9_\-]{1,}\.(?:\w)(?:[\?|#][^"|']{0,}|)))(?:"|') f_regex: (?:"|')((?:(?:[a-zA-Z]{1,10}://|//)[^"'/]{1,}\.[a-zA-Z]{2,}[^"']{0,})|(?:(?:(?:/|\.\./|\./)?[^"'><,;|*()(%%$^/\\\[\]][^"'><,;|()]{1,}\.[a-zA-Z]{1,4})|(?:(?:/|\.\./|\./)?[^"'><,;|*()(%%$^/\\\[\]][^"'><,;|()]{1,}/[^"'><,;|()]{1,}(?:\.[a-zA-Z]{1,4}|action)?)))(?:[\?|#][^"|']{0,})?(?:"|')
s_regex: '' s_regex: ''
format: '{0}' format: '{0}'
color: gray color: gray