Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c795af101 | ||
|
|
5977e82ca6 | ||
|
|
452f297f55 | ||
|
|
a06ef8e25e | ||
|
|
7e53e250af | ||
|
|
b686b5e75e |
@@ -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<>();
|
||||||
|
|||||||
@@ -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.1";
|
|
||||||
api.extension().setName("HaE - Highlighter and Extractor");
|
api.extension().setName("HaE - Highlighter and Extractor");
|
||||||
|
String version = "4.0.5";
|
||||||
|
|
||||||
// 加载扩展后输出的项目信息
|
// 加载扩展后输出的项目信息
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加进日志
|
// 添加进日志
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ public class DataManager {
|
|||||||
persistence.extensionData().deleteChildObject(dataName);
|
persistence.extensionData().deleteChildObject(dataName);
|
||||||
}
|
}
|
||||||
persistence.extensionData().setChildObject(dataName, persistedObject);
|
persistence.extensionData().setChildObject(dataName, persistedObject);
|
||||||
|
|
||||||
saveIndex(dataType, dataName);
|
saveIndex(dataType, dataName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadData(MessageTableModel messageTableModel) {
|
public synchronized void loadData(MessageTableModel messageTableModel) {
|
||||||
// 1. 获取索引
|
// 1. 获取索引
|
||||||
PersistedList<String> dataIndex = persistence.extensionData().getStringList("data"); // 数据索引
|
PersistedList<String> dataIndex = persistence.extensionData().getStringList("data"); // 数据索引
|
||||||
PersistedList<String> messageIndex = persistence.extensionData().getStringList("message"); // 消息索引
|
PersistedList<String> messageIndex = persistence.extensionData().getStringList("message"); // 消息索引
|
||||||
@@ -42,7 +43,7 @@ public class DataManager {
|
|||||||
|
|
||||||
if (indexList != null && !indexList.isEmpty()) {
|
if (indexList != null && !indexList.isEmpty()) {
|
||||||
persistence.extensionData().deleteStringList(indexName);
|
persistence.extensionData().deleteStringList(indexName);
|
||||||
} else {
|
} else if (indexList == null) {
|
||||||
indexList = PersistedList.persistedStringList();
|
indexList = PersistedList.persistedStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,18 +56,21 @@ public class DataManager {
|
|||||||
|
|
||||||
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.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 ignored) {
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessageData(PersistedList<String> messageIndex, MessageTableModel messageTableModel) {
|
private void loadMessageData(PersistedList<String> messageIndex, MessageTableModel messageTableModel) {
|
||||||
if (messageIndex != null && !messageIndex.isEmpty()) {
|
if (messageIndex != null && !messageIndex.isEmpty()) {
|
||||||
messageIndex.parallelStream().forEach(index -> {
|
messageIndex.forEach(index -> {
|
||||||
PersistedObject dataObj = persistence.extensionData().getChildObject(index);
|
PersistedObject dataObj = persistence.extensionData().getChildObject(index);
|
||||||
if (dataObj != null) {
|
if (dataObj != null) {
|
||||||
HttpRequestResponse messageInfo = dataObj.getHttpRequestResponse("messageInfo");
|
HttpRequestResponse messageInfo = dataObj.getHttpRequestResponse("messageInfo");
|
||||||
|
|||||||
Reference in New Issue
Block a user