Compare commits

..

6 Commits
3.0 ... 3.0.2

Author SHA1 Message Date
gh0stkey
4da3d3f42d Version: 3.0.2 Update 2024-05-12 19:02:38 +08:00
EvilChen
3363ca25ed Update issue templates 2024-05-11 09:56:23 +08:00
gh0stkey
496d0d2174 Version: 3.0.1 Update 2024-05-11 09:44:19 +08:00
gh0stkey
f387834c4d Version: 3.0.1 Update 2024-05-09 13:34:38 +08:00
gh0stkey
ca773f368b Version: 3.0.1 Update 2024-05-09 13:32:22 +08:00
gh0stkey
a6cd01300b Version: 3.0 Update 2024-05-07 16:08:46 +08:00
22 changed files with 205 additions and 183 deletions

View File

@@ -1,7 +1,7 @@
--- ---
name: 问题反馈 name: 问题反馈
about: 尽可能详细的描述问题并反馈 about: 尽可能详细的描述问题并反馈
title: "[BUG] " title: "[BUG] 问题标题"
labels: bug labels: bug
assignees: '' assignees: ''
@@ -11,10 +11,10 @@ assignees: ''
``` ```
HaE 版本: HaE 版本:
是否有自定义的HaE规则: 有无自定义规则:
BurpSuite 版本: BurpSuite 版本:
JDK版本
操作系统版本: 操作系统版本:
有无仔细阅读README
``` ```
## 问题详情 ## 问题详情

View File

@@ -13,7 +13,9 @@
**注意事项**: **注意事项**:
1. 由于HaE 3.0版本开始采用`Montoya API`进行开发因此使用新版HaE需要升级你的BurpSuite版本>=2023.12.1)。 1. 由于HaE 3.0版本开始采用`Montoya API`进行开发因此使用新版HaE需要升级你的BurpSuite版本>=2023.12.1)。
2. 自定义HaE规则必须用左右括号`()`将所需提取的表达式内容包含,例如你要匹配一个**Shiro应用**的响应报文,正常匹配规则为`rememberMe=delete`在HaE的规则中就需要变成`(rememberMe=delete)` 2. 由于HaE 2.6版本后对规则字段进行了更新,因此无法适配<=2.6版本的规则,请用户自行前往[规则转换页面](https://gh0st.cn/HaE/ConversionRule.html)进行转换
3. HaE官方规则库存放在[Github](https://raw.githubusercontent.com/gh0stkey/HaE/gh-pages/Rules.yml)上因此默认加载HaE官方规则库需使用代理BApp审核不允许使用CDN
4. 自定义HaE规则必须用左右括号`()`将所需提取的表达式内容包含,例如你要匹配一个**Shiro应用**的响应报文,正常匹配规则为`rememberMe=delete`在HaE的规则中就需要变成`(rememberMe=delete)`
## 使用方法 ## 使用方法
@@ -38,7 +40,7 @@ HaE目前的规则一共有8个字段分别是规则名称、规则正则、
| F-Regex | 规则正则主要用于填写正则表达式。在HaE中所需提取匹配的内容需要用`(``)`将正则表达式进行包裹。| | F-Regex | 规则正则主要用于填写正则表达式。在HaE中所需提取匹配的内容需要用`(``)`将正则表达式进行包裹。|
| S-Regex | 规则正则作用及使用同F-Regex。S-Regex为二次正则可以用于对F-Regex匹配的数据结果进行二次的匹配提取如不需要的情况下可以留空。| | S-Regex | 规则正则作用及使用同F-Regex。S-Regex为二次正则可以用于对F-Regex匹配的数据结果进行二次的匹配提取如不需要的情况下可以留空。|
| Format | 格式化输出在NFA引擎的正则表达式中我们可以通过`{0}``{1}``{2}`…的方式进行取分组格式化输出。默认情况下使用`{0}`即可。 | | Format | 格式化输出在NFA引擎的正则表达式中我们可以通过`{0}``{1}``{2}`…的方式进行取分组格式化输出。默认情况下使用`{0}`即可。 |
| Scope | 规则作用域主要用于表示当前规则作用于HTTP报文的哪个部分。 | | Scope | 规则作用域主要用于表示当前规则作用于HTTP报文的哪个部分。支持请求、响应的行、头、体,以及完整的报文。 |
| Engine | 正则引擎,主要用于表示当前规则的正则表达式所使用的引擎。**DFA引擎**:对于文本串里的每一个字符只需扫描一次,速度快、特性少;**NFA引擎**:要翻来覆去标注字符、取消标注字符,速度慢,但是特性(如:分组、替换、分割)丰富。 | | Engine | 正则引擎,主要用于表示当前规则的正则表达式所使用的引擎。**DFA引擎**:对于文本串里的每一个字符只需扫描一次,速度快、特性少;**NFA引擎**:要翻来覆去标注字符、取消标注字符,速度慢,但是特性(如:分组、替换、分割)丰富。 |
| Color | 规则匹配颜色主要用于表示当前规则匹配到对应HTTP报文时所需标记的高亮颜色。在HaE中具备颜色升级算法当出现相同颜色时会自动向上升级一个颜色进行标记。 | | Color | 规则匹配颜色主要用于表示当前规则匹配到对应HTTP报文时所需标记的高亮颜色。在HaE中具备颜色升级算法当出现相同颜色时会自动向上升级一个颜色进行标记。 |
| Sensitive | 规则敏感性,主要用于表示当前规则对于大小写字母是否敏感,敏感(`True`)则严格按照大小写要求匹配,不敏感(`False`)则反之。 | | Sensitive | 规则敏感性,主要用于表示当前规则对于大小写字母是否敏感,敏感(`True`)则严格按照大小写要求匹配,不敏感(`False`)则反之。 |

View File

@@ -13,9 +13,11 @@ public class Config {
"any header", "any header",
"any body", "any body",
"response", "response",
"response line",
"response header", "response header",
"response body", "response body",
"request", "request",
"request line",
"request header", "request header",
"request body" "request body"
}; };

View File

@@ -16,7 +16,7 @@ public class HaE implements BurpExtension {
@Override @Override
public void initialize(MontoyaApi api) { public void initialize(MontoyaApi api) {
// 设置扩展名称 // 设置扩展名称
String version = "3.0"; String version = "3.0.2";
api.extension().setName(String.format("HaE (%s) - Highlighter and Extractor", version)); api.extension().setName(String.format("HaE (%s) - Highlighter and Extractor", version));
// 加载扩展后输出的项目信息 // 加载扩展后输出的项目信息

View File

@@ -1,6 +1,7 @@
package hae.cache; package hae.cache;
import java.util.*; import java.util.HashMap;
import java.util.Map;
public class CachePool { public class CachePool {
private static final Map<String, Map<String, Map<String, Object>>> cache = new HashMap<>(); private static final Map<String, Map<String, Map<String, Object>>> cache = new HashMap<>();

View File

@@ -3,20 +3,21 @@ package hae.component.board;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import hae.Config; import hae.Config;
import hae.component.board.message.MessageTableModel; import hae.component.board.message.MessageTableModel;
import hae.utils.string.StringProcessor;
import hae.utils.config.ConfigLoader;
import hae.component.board.message.MessageTableModel.MessageTable; import hae.component.board.message.MessageTableModel.MessageTable;
import hae.utils.config.ConfigLoader;
import hae.utils.string.StringProcessor;
import java.util.*; import javax.swing.*;
import java.util.concurrent.ConcurrentHashMap; import javax.swing.event.DocumentEvent;
import javax.swing.event.*; import javax.swing.event.DocumentListener;
import javax.swing.table.TableColumnModel; import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter; import javax.swing.table.TableRowSorter;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import java.util.List; import java.util.List;
import javax.swing.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class Databoard extends JPanel { public class Databoard extends JPanel {
private final MontoyaApi api; private final MontoyaApi api;
@@ -28,8 +29,8 @@ public class Databoard extends JPanel {
private MessageTable messageTable; private MessageTable messageTable;
private static Boolean isMatchHost = false; private static Boolean isMatchHost = false;
private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(); private final DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
private JComboBox hostComboBox = new JComboBox(comboBoxModel); private final JComboBox hostComboBox = new JComboBox(comboBoxModel);
public Databoard(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) { public Databoard(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) {
this.api = api; this.api = api;

View File

@@ -5,17 +5,21 @@ import hae.component.board.message.MessageTableModel;
import jregex.Pattern; import jregex.Pattern;
import jregex.REFlags; import jregex.REFlags;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
import java.awt.*; import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.FocusEvent; import java.awt.event.FocusEvent;
import java.awt.event.FocusListener; import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.*; import java.util.Comparator;
import java.util.List; import java.util.List;
import javax.swing.*;
import java.awt.datatransfer.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class Datatable extends JPanel { public class Datatable extends JPanel {
private final MontoyaApi api; private final MontoyaApi api;
@@ -30,7 +34,6 @@ public class Datatable extends JPanel {
this.api = api; this.api = api;
this.tabName = tabName; this.tabName = tabName;
String[] columnNames = {"#", "Information"}; String[] columnNames = {"#", "Information"};
dataTableModel = new DefaultTableModel(columnNames, 0); dataTableModel = new DefaultTableModel(columnNames, 0);
@@ -114,19 +117,6 @@ public class Datatable extends JPanel {
optionsPanel.add(Box.createHorizontalStrut(5)); optionsPanel.add(Box.createHorizontalStrut(5));
optionsPanel.add(searchField); optionsPanel.add(searchField);
dataTable.setTransferHandler(new TransferHandler() {
@Override
public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException {
if (comp instanceof JTable) {
StringSelection stringSelection = new StringSelection(getSelectedData(
(JTable) comp));
clip.setContents(stringSelection, null);
} else {
super.exportToClipboard(comp, clip, action);
}
}
});
add(scrollPane, BorderLayout.CENTER); add(scrollPane, BorderLayout.CENTER);
add(optionsPanel, BorderLayout.SOUTH); add(optionsPanel, BorderLayout.SOUTH);
} }
@@ -186,26 +176,20 @@ public class Datatable extends JPanel {
} }
} }
public static String getSelectedData(JTable table) {
int[] selectRows = table.getSelectedRows();
StringBuilder selectData = new StringBuilder();
for (int row : selectRows) {
selectData.append(table.getValueAt(row, 1).toString()).append("\n");
}
// 便于单行复制,去除最后一个换行符
if (!selectData.isEmpty()){
selectData.deleteCharAt(selectData.length() - 1);
}
return selectData.toString();
}
public JTable getDataTable() {
return this.dataTable;
}
public void setTableListener(MessageTableModel messagePanel) { public void setTableListener(MessageTableModel messagePanel) {
// 表格复制功能
dataTable.setTransferHandler(new TransferHandler() {
@Override
public void exportToClipboard(JComponent comp, Clipboard clip, int action) throws IllegalStateException {
if (comp instanceof JTable) {
StringSelection stringSelection = new StringSelection(getSelectedDataAtTable((JTable) comp));
clip.setContents(stringSelection, null);
} else {
super.exportToClipboard(comp, clip, action);
}
}
});
dataTable.setDefaultEditor(Object.class, null); dataTable.setDefaultEditor(Object.class, null);
// 表格内容双击事件 // 表格内容双击事件
@@ -222,5 +206,26 @@ public class Datatable extends JPanel {
} }
}); });
} }
public String getSelectedDataAtTable(JTable table) {
int[] selectRows = table.getSelectedRows();
StringBuilder selectData = new StringBuilder();
for (int row : selectRows) {
selectData.append(table.getValueAt(row, 1).toString()).append("\n");
}
// 便于单行复制,去除最后一个换行符
if (!selectData.isEmpty()) {
selectData.deleteCharAt(selectData.length() - 1);
return selectData.toString();
} else {
return "";
}
}
public JTable getDataTable() {
return this.dataTable;
}
} }

View File

@@ -1,18 +1,17 @@
package hae.component.board.message; package hae.component.board.message;
import java.awt.Color; import javax.swing.*;
import java.awt.Component; import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class MessageRenderer extends DefaultTableCellRenderer { public class MessageRenderer extends DefaultTableCellRenderer {
private List<MessageEntry> log; private final List<MessageEntry> log;
private Map<String, Color> colorMap = new HashMap<>(); private final Map<String, Color> colorMap = new HashMap<>();
private JTable table; // 保存对表格的引用 private final JTable table; // 保存对表格的引用
public MessageRenderer(List<MessageEntry> log, JTable table) { public MessageRenderer(List<MessageEntry> log, JTable table) {
this.log = log; this.log = log;

View File

@@ -14,18 +14,14 @@ import hae.cache.CachePool;
import hae.utils.string.HashCalculator; import hae.utils.string.HashCalculator;
import hae.utils.string.StringProcessor; import hae.utils.string.StringProcessor;
import java.nio.charset.StandardCharsets; import javax.swing.*;
import java.text.MessageFormat;
import java.util.*;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel; import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter; import javax.swing.table.TableRowSorter;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -37,7 +33,7 @@ public class MessageTableModel extends AbstractTableModel {
private final JTabbedPane messageTab; private final JTabbedPane messageTab;
private final JSplitPane splitPane; private final JSplitPane splitPane;
private final List<MessageEntry> log = new ArrayList<MessageEntry>(); private final List<MessageEntry> log = new ArrayList<MessageEntry>();
private LinkedList<MessageEntry> filteredLog; private final LinkedList<MessageEntry> filteredLog;
public MessageTableModel(MontoyaApi api) { public MessageTableModel(MontoyaApi api) {
this.filteredLog = new LinkedList<>(); this.filteredLog = new LinkedList<>();
@@ -74,6 +70,7 @@ public class MessageTableModel extends AbstractTableModel {
int index2 = getIndex(s2); int index2 = getIndex(s2);
return Integer.compare(index1, index2); return Integer.compare(index1, index2);
} }
private int getIndex(String color) { private int getIndex(String color) {
for (int i = 0; i < Config.color.length; i++) { for (int i = 0; i < Config.color.length; i++) {
if (Config.color[i].equals(color)) { if (Config.color[i].equals(color)) {
@@ -120,7 +117,7 @@ public class MessageTableModel extends AbstractTableModel {
byte[] resByteB = reqResMessage.response().toByteArray().getBytes(); byte[] resByteB = reqResMessage.response().toByteArray().getBytes();
try { try {
// 通过URL、请求和响应报文、匹配数据内容多维度进行对比 // 通过URL、请求和响应报文、匹配数据内容多维度进行对比
if ((entry.getUrl().toString().equals(url.toString()) || (Arrays.equals(reqByteB, reqByteA) || Arrays.equals(resByteB, resByteA))) && (areMapsEqual(getCacheData(reqByteB), getCacheData(reqByteA)) && areMapsEqual(getCacheData(resByteB), getCacheData(resByteA)))) { if ((entry.getUrl().equals(url) || (Arrays.equals(reqByteB, reqByteA) || Arrays.equals(resByteB, resByteA))) && (areMapsEqual(getCacheData(reqByteB), getCacheData(reqByteA)) && areMapsEqual(getCacheData(resByteB), getCacheData(resByteA)))) {
isDuplicate = true; isDuplicate = true;
break; break;
} }
@@ -243,6 +240,14 @@ public class MessageTableModel extends AbstractTableModel {
case "response body": case "response body":
isMatch = matchingString(format, filterText, responseBody); isMatch = matchingString(format, filterText, responseBody);
break; break;
case "request line":
String requestLine = requestString.split("\\r?\\n", 2)[0];
isMatch = matchingString(format, filterText, requestLine);
break;
case "response line":
String responseLine = responseString.split("\\r?\\n", 2)[0];
isMatch = matchingString(format, filterText, responseLine);
break;
default: default:
break; break;
} }
@@ -334,13 +339,11 @@ public class MessageTableModel extends AbstractTableModel {
} }
public JSplitPane getSplitPane() public JSplitPane getSplitPane() {
{
return splitPane; return splitPane;
} }
public MessageTable getMessageTable() public MessageTable getMessageTable() {
{
return messageTable; return messageTable;
} }
@@ -360,8 +363,7 @@ public class MessageTableModel extends AbstractTableModel {
} }
@Override @Override
public Object getValueAt(int rowIndex, int columnIndex) public Object getValueAt(int rowIndex, int columnIndex) {
{
if (filteredLog.isEmpty()) { if (filteredLog.isEmpty()) {
return ""; return "";
} }
@@ -379,8 +381,7 @@ public class MessageTableModel extends AbstractTableModel {
} }
@Override @Override
public String getColumnName(int columnIndex) public String getColumnName(int columnIndex) {
{
return switch (columnIndex) { return switch (columnIndex) {
case 0 -> "Method"; case 0 -> "Method";
case 1 -> "URL"; case 1 -> "URL";
@@ -443,8 +444,7 @@ public class MessageTableModel extends AbstractTableModel {
ByteArray[] result = (ByteArray[]) get(); ByteArray[] result = (ByteArray[]) get();
requestEditor.setRequest(HttpRequest.httpRequest(MessageEntry.getRequestResponse().httpService(), result[0])); requestEditor.setRequest(HttpRequest.httpRequest(MessageEntry.getRequestResponse().httpService(), result[0]));
responseEditor.setResponse(HttpResponse.httpResponse(result[1])); responseEditor.setResponse(HttpResponse.httpResponse(result[1]));
} catch (Exception e) { } catch (Exception ignored) {
e.printStackTrace();
} }
} }
} }

View File

@@ -1,18 +1,17 @@
package hae.component.rule; package hae.component.rule;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.table.TableRowSorter;
import java.util.Vector;
import hae.Config; import hae.Config;
import hae.utils.config.ConfigLoader; import hae.utils.config.ConfigLoader;
import hae.utils.rule.RuleProcessor; import hae.utils.rule.RuleProcessor;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Vector;
import static javax.swing.JOptionPane.YES_OPTION; import static javax.swing.JOptionPane.YES_OPTION;
public class Rule extends JPanel { public class Rule extends JPanel {

View File

@@ -11,7 +11,7 @@ import java.awt.event.*;
public class Rules extends JTabbedPane { public class Rules extends JTabbedPane {
private final MontoyaApi api; private final MontoyaApi api;
private final ConfigLoader configLoader; private ConfigLoader configLoader;
private final RuleProcessor ruleProcessor; private final RuleProcessor ruleProcessor;
private final JTextField ruleGroupNameTextField; private final JTextField ruleGroupNameTextField;
@@ -101,6 +101,8 @@ public class Rules extends JTabbedPane {
public void reloadRuleGroup() { public void reloadRuleGroup() {
removeAll(); removeAll();
this.configLoader = new ConfigLoader(api);
Config.globalRules.keySet().forEach(i -> addTab(i, new Rule(api, configLoader, hae.Config.globalRules.get(i), this))); Config.globalRules.keySet().forEach(i -> addTab(i, new Rule(api, configLoader, hae.Config.globalRules.get(i), this)));
addTab("...", null); addTab("...", null);
} }
@@ -118,7 +120,7 @@ public class Rules extends JTabbedPane {
} }
} }
private Action renameTitleActionPerformed = new AbstractAction() { private final Action renameTitleActionPerformed = new AbstractAction() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String title = ruleGroupNameTextField.getText(); String title = ruleGroupNameTextField.getText();
@@ -134,7 +136,7 @@ public class Rules extends JTabbedPane {
} }
}; };
private Action cancelActionPerformed = new AbstractAction() { private final Action cancelActionPerformed = new AbstractAction() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (selectedIndex >= 0) { if (selectedIndex >= 0) {

View File

@@ -1,14 +1,14 @@
package hae.instances.editor; package hae.instances.editor;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import burp.api.montoya.ui.editor.extension.EditorCreationContext;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor;
import burp.api.montoya.ui.editor.extension.HttpRequestEditorProvider;
import burp.api.montoya.core.ByteArray; import burp.api.montoya.core.ByteArray;
import burp.api.montoya.core.Range; import burp.api.montoya.core.Range;
import burp.api.montoya.http.message.HttpRequestResponse; import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest; import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.ui.Selection; import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.editor.extension.EditorCreationContext;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor;
import burp.api.montoya.ui.editor.extension.HttpRequestEditorProvider;
import hae.component.board.Datatable; import hae.component.board.Datatable;
import hae.instances.http.utils.MessageProcessor; import hae.instances.http.utils.MessageProcessor;
@@ -36,10 +36,9 @@ public class RequestEditor implements HttpRequestEditorProvider {
private final MessageProcessor messageProcessor; private final MessageProcessor messageProcessor;
private HttpRequestResponse requestResponse; private HttpRequestResponse requestResponse;
private JTabbedPane jTabbedPane = new JTabbedPane(); private final JTabbedPane jTabbedPane = new JTabbedPane();
public Editor(MontoyaApi api, EditorCreationContext creationContext) public Editor(MontoyaApi api, EditorCreationContext creationContext) {
{
this.api = api; this.api = api;
this.creationContext = creationContext; this.creationContext = creationContext;
this.messageProcessor = new MessageProcessor(api); this.messageProcessor = new MessageProcessor(api);
@@ -60,7 +59,7 @@ public class RequestEditor implements HttpRequestEditorProvider {
HttpRequest request = requestResponse.request(); HttpRequest request = requestResponse.request();
if (request != null && !request.bodyToString().equals("Loading...")) { if (request != null && !request.bodyToString().equals("Loading...")) {
List<Map<String, String>> result = messageProcessor.processRequest("", request, false); List<Map<String, String>> result = messageProcessor.processRequest("", request, false);
jTabbedPane = generateTabbedPaneFromResultMap(api, result); generateTabbedPaneFromResultMap(api, jTabbedPane, result);
return jTabbedPane.getTabCount() > 0; return jTabbedPane.getTabCount() > 0;
} }
return false; return false;
@@ -81,7 +80,8 @@ public class RequestEditor implements HttpRequestEditorProvider {
return new Selection() { return new Selection() {
@Override @Override
public ByteArray contents() { public ByteArray contents() {
return ByteArray.byteArray(Datatable.getSelectedData(((Datatable) jTabbedPane.getSelectedComponent()).getDataTable())); Datatable dataTable = (Datatable) jTabbedPane.getSelectedComponent();
return ByteArray.byteArray(dataTable.getSelectedDataAtTable(dataTable.getDataTable()));
} }
@Override @Override
@@ -97,8 +97,8 @@ public class RequestEditor implements HttpRequestEditorProvider {
} }
} }
public static JTabbedPane generateTabbedPaneFromResultMap(MontoyaApi api, List<Map<String, String>> result) { public static void generateTabbedPaneFromResultMap(MontoyaApi api, JTabbedPane tabbedPane, List<Map<String, String>> result) {
JTabbedPane tabbedPane = new JTabbedPane(); tabbedPane.removeAll();
if (result != null && !result.isEmpty() && result.size() > 0) { if (result != null && !result.isEmpty() && result.size() > 0) {
Map<String, String> dataMap = result.get(0); Map<String, String> dataMap = result.get(0);
if (dataMap != null && !dataMap.isEmpty() && dataMap.size() > 0) { if (dataMap != null && !dataMap.isEmpty() && dataMap.size() > 0) {
@@ -109,7 +109,5 @@ public class RequestEditor implements HttpRequestEditorProvider {
}); });
} }
} }
return tabbedPane;
} }
} }

View File

@@ -1,14 +1,14 @@
package hae.instances.editor; package hae.instances.editor;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.ByteArray;
import burp.api.montoya.core.Range;
import burp.api.montoya.http.message.HttpRequestResponse; import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.responses.HttpResponse; import burp.api.montoya.http.message.responses.HttpResponse;
import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.editor.extension.EditorCreationContext; import burp.api.montoya.ui.editor.extension.EditorCreationContext;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpResponseEditor; import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpResponseEditor;
import burp.api.montoya.ui.editor.extension.HttpResponseEditorProvider; import burp.api.montoya.ui.editor.extension.HttpResponseEditorProvider;
import burp.api.montoya.core.ByteArray;
import burp.api.montoya.core.Range;
import burp.api.montoya.ui.Selection;
import hae.component.board.Datatable; import hae.component.board.Datatable;
import hae.instances.http.utils.MessageProcessor; import hae.instances.http.utils.MessageProcessor;
@@ -35,10 +35,9 @@ public class ResponseEditor implements HttpResponseEditorProvider {
private final MessageProcessor messageProcessor; private final MessageProcessor messageProcessor;
private HttpRequestResponse requestResponse; private HttpRequestResponse requestResponse;
private JTabbedPane jTabbedPane = new JTabbedPane(); private final JTabbedPane jTabbedPane = new JTabbedPane();
public Editor(MontoyaApi api, EditorCreationContext creationContext) public Editor(MontoyaApi api, EditorCreationContext creationContext) {
{
this.api = api; this.api = api;
this.creationContext = creationContext; this.creationContext = creationContext;
this.messageProcessor = new MessageProcessor(api); this.messageProcessor = new MessageProcessor(api);
@@ -59,7 +58,7 @@ public class ResponseEditor implements HttpResponseEditorProvider {
HttpResponse request = requestResponse.response(); HttpResponse request = requestResponse.response();
if (request != null && !request.bodyToString().equals("Loading...")) { if (request != null && !request.bodyToString().equals("Loading...")) {
List<Map<String, String>> result = messageProcessor.processResponse("", request, false); List<Map<String, String>> result = messageProcessor.processResponse("", request, false);
jTabbedPane = RequestEditor.generateTabbedPaneFromResultMap(api, result); RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, result);
return jTabbedPane.getTabCount() > 0; return jTabbedPane.getTabCount() > 0;
} }
return false; return false;
@@ -80,7 +79,8 @@ public class ResponseEditor implements HttpResponseEditorProvider {
return new Selection() { return new Selection() {
@Override @Override
public ByteArray contents() { public ByteArray contents() {
return ByteArray.byteArray(Datatable.getSelectedData(((Datatable) jTabbedPane.getSelectedComponent()).getDataTable())); Datatable dataTable = (Datatable) jTabbedPane.getSelectedComponent();
return ByteArray.byteArray(dataTable.getSelectedDataAtTable(dataTable.getDataTable()));
} }
@Override @Override

View File

@@ -5,7 +5,9 @@ import burp.api.montoya.core.ByteArray;
import burp.api.montoya.core.Range; import burp.api.montoya.core.Range;
import burp.api.montoya.ui.Selection; import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.contextmenu.WebSocketMessage; import burp.api.montoya.ui.contextmenu.WebSocketMessage;
import burp.api.montoya.ui.editor.extension.*; import burp.api.montoya.ui.editor.extension.EditorCreationContext;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedWebSocketMessageEditor;
import burp.api.montoya.ui.editor.extension.WebSocketMessageEditorProvider;
import hae.component.board.Datatable; import hae.component.board.Datatable;
import hae.instances.http.utils.MessageProcessor; import hae.instances.http.utils.MessageProcessor;
@@ -32,7 +34,7 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider {
private final MessageProcessor messageProcessor; private final MessageProcessor messageProcessor;
private ByteArray message; private ByteArray message;
private JTabbedPane jTabbedPane = new JTabbedPane(); private final JTabbedPane jTabbedPane = new JTabbedPane();
public Editor(MontoyaApi api, EditorCreationContext creationContext) { public Editor(MontoyaApi api, EditorCreationContext creationContext) {
this.api = api; this.api = api;
@@ -55,7 +57,7 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider {
String websocketMessage = webSocketMessage.payload().toString(); String websocketMessage = webSocketMessage.payload().toString();
if (!websocketMessage.isEmpty()) { if (!websocketMessage.isEmpty()) {
List<Map<String, String>> result = messageProcessor.processMessage("", websocketMessage, false); List<Map<String, String>> result = messageProcessor.processMessage("", websocketMessage, false);
jTabbedPane = RequestEditor.generateTabbedPaneFromResultMap(api, result); RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, result);
return jTabbedPane.getTabCount() > 0; return jTabbedPane.getTabCount() > 0;
} }
return false; return false;
@@ -76,7 +78,8 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider {
return new Selection() { return new Selection() {
@Override @Override
public ByteArray contents() { public ByteArray contents() {
return ByteArray.byteArray(Datatable.getSelectedData(((Datatable) jTabbedPane.getSelectedComponent()).getDataTable())); Datatable dataTable = (Datatable) jTabbedPane.getSelectedComponent();
return ByteArray.byteArray(dataTable.getSelectedDataAtTable(dataTable.getDataTable()));
} }
@Override @Override

View File

@@ -11,16 +11,19 @@ import hae.component.board.message.MessageTableModel;
import hae.instances.http.utils.MessageProcessor; import hae.instances.http.utils.MessageProcessor;
import hae.utils.string.StringProcessor; import hae.utils.string.StringProcessor;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class HttpMessageHandler implements HttpHandler { public class HttpMessageHandler implements HttpHandler {
private final MontoyaApi api; private final MontoyaApi api;
private MessageTableModel messageTableModel; private final MessageTableModel messageTableModel;
private final MessageProcessor messageProcessor; private final MessageProcessor messageProcessor;
private String host;
// Montoya API对HTTP消息的处理分为了请求和响应因此此处设置高亮和标记需要使用全局变量的方式以此兼顾请求和响应 // Montoya API对HTTP消息的处理分为了请求和响应因此此处设置高亮和标记需要使用全局变量的方式以此兼顾请求和响应
// 同时采用 ThreadLocal 来保证多线程并发的情况下全局变量的安全性 // 同时采用 ThreadLocal 来保证多线程并发的情况下全局变量的安全性
private final ThreadLocal<String> host = ThreadLocal.withInitial(() -> "");
private final ThreadLocal<List<String>> colorList = ThreadLocal.withInitial(ArrayList::new); private final ThreadLocal<List<String>> colorList = ThreadLocal.withInitial(ArrayList::new);
private final ThreadLocal<List<String>> commentList = ThreadLocal.withInitial(ArrayList::new); private final ThreadLocal<List<String>> commentList = ThreadLocal.withInitial(ArrayList::new);
private final ThreadLocal<Boolean> matches = ThreadLocal.withInitial(() -> false); private final ThreadLocal<Boolean> matches = ThreadLocal.withInitial(() -> false);
@@ -41,13 +44,13 @@ public class HttpMessageHandler implements HttpHandler {
httpRequest.set(httpRequestToBeSent); httpRequest.set(httpRequestToBeSent);
host = StringProcessor.getHostByUrl(httpRequestToBeSent.url()); host.set(StringProcessor.getHostByUrl(httpRequestToBeSent.url()));
List<String> suffixList = Arrays.asList(Config.suffix.split("\\|")); List<String> suffixList = Arrays.asList(Config.suffix.split("\\|"));
matches.set(suffixList.contains(httpRequestToBeSent.fileExtension())); matches.set(suffixList.contains(httpRequestToBeSent.fileExtension()));
if (!matches.get()) { if (!matches.get()) {
List<Map<String, String>> result = messageProcessor.processRequest(host, httpRequestToBeSent, true); List<Map<String, String>> result = messageProcessor.processRequest(host.get(), httpRequestToBeSent, true);
setColorAndCommentList(result); setColorAndCommentList(result);
} }
@@ -59,7 +62,7 @@ public class HttpMessageHandler implements HttpHandler {
Annotations annotations = httpResponseReceived.annotations(); Annotations annotations = httpResponseReceived.annotations();
if (!matches.get()) { if (!matches.get()) {
List<Map<String, String>> result = messageProcessor.processResponse(host, httpResponseReceived, true); List<Map<String, String>> result = messageProcessor.processResponse(host.get(), httpResponseReceived, true);
setColorAndCommentList(result); setColorAndCommentList(result);
// 设置高亮颜色和注释 // 设置高亮颜色和注释
if (!colorList.get().isEmpty() && !commentList.get().isEmpty()) { if (!colorList.get().isEmpty() && !commentList.get().isEmpty()) {

View File

@@ -24,6 +24,7 @@ public class MessageProcessor {
public List<Map<String, String>> processMessage(String host, String message, boolean flag) { public List<Map<String, String>> processMessage(String host, String message, boolean flag) {
Map<String, Map<String, Object>> obj = null; Map<String, Map<String, Object>> obj = null;
try { try {
obj = regularMatcher.match(host, "any", message, message, message); obj = regularMatcher.match(host, "any", message, message, message);
} catch (Exception ignored) { } catch (Exception ignored) {
@@ -34,6 +35,7 @@ public class MessageProcessor {
public List<Map<String, String>> processResponse(String host, HttpResponse httpResponse, boolean flag) { public List<Map<String, String>> processResponse(String host, HttpResponse httpResponse, boolean flag) {
Map<String, Map<String, Object>> obj = null; Map<String, Map<String, Object>> obj = null;
try { try {
String response = new String(httpResponse.toByteArray().getBytes(), StandardCharsets.UTF_8); String response = new String(httpResponse.toByteArray().getBytes(), StandardCharsets.UTF_8);
String body = new String(httpResponse.body().getBytes(), StandardCharsets.UTF_8); String body = new String(httpResponse.body().getBytes(), StandardCharsets.UTF_8);
@@ -57,6 +59,7 @@ public class MessageProcessor {
String header = httpRequest.headers().stream() String header = httpRequest.headers().stream()
.map(HttpHeader::toString) .map(HttpHeader::toString)
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
obj = regularMatcher.match(host, "request", request, header, body); obj = regularMatcher.match(host, "request", request, header, body);
} catch (Exception ignored) { } catch (Exception ignored) {
} }
@@ -99,6 +102,7 @@ public class MessageProcessor {
String data = tempMap.get("data").toString(); String data = tempMap.get("data").toString();
extractedData.put(key, data); extractedData.put(key, data);
}); });
return extractedData; return extractedData;
} }
@@ -114,6 +118,7 @@ public class MessageProcessor {
List<List<String>> result = new ArrayList<>(); List<List<String>> result = new ArrayList<>();
result.add(colorList); result.add(colorList);
result.add(commentList); result.add(commentList);
return result; return result;
} }
@@ -129,6 +134,7 @@ public class MessageProcessor {
} }
} }
} }
return indices; return indices;
} }

View File

@@ -69,6 +69,10 @@ public class RegularMatcher {
case "response body": case "response body":
matchContent = body; matchContent = body;
break; break;
case "request line":
case "response line":
matchContent = message.split("\\r?\\n", 2)[0];
break;
default: default:
break; break;
} }

View File

@@ -1,15 +1,5 @@
package hae.utils.config; package hae.utils.config;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.message.HttpRequestResponse; import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest; import burp.api.montoya.http.message.requests.HttpRequest;
@@ -18,6 +8,12 @@ import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer; import org.yaml.snakeyaml.representer.Representer;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
public class ConfigLoader { public class ConfigLoader {
private final MontoyaApi api; private final MontoyaApi api;
private final Yaml yaml; private final Yaml yaml;

View File

@@ -2,11 +2,11 @@ package hae.utils.rule;
import burp.api.montoya.MontoyaApi; import burp.api.montoya.MontoyaApi;
import hae.Config; import hae.Config;
import hae.utils.config.ConfigLoader;
import hae.utils.rule.model.Group; import hae.utils.rule.model.Group;
import hae.utils.rule.model.Info; import hae.utils.rule.model.Info;
import hae.utils.config.ConfigLoader;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.representer.Representer; import org.yaml.snakeyaml.representer.Representer;
import java.io.File; import java.io.File;
@@ -75,6 +75,7 @@ public class RuleProcessor {
Config.globalRules.put(type, x.toArray(new Object[x.size()][])); Config.globalRules.put(type, x.toArray(new Object[x.size()][]));
this.rulesFormatAndSave(); this.rulesFormatAndSave();
} }
public void removeRule(int select, String type) { public void removeRule(int select, String type) {
ArrayList<Object[]> x = new ArrayList<>(Arrays.asList(Config.globalRules.get(type))); ArrayList<Object[]> x = new ArrayList<>(Arrays.asList(Config.globalRules.get(type)));
x.remove(select); x.remove(select);