Compare commits

..

10 Commits
3.3 ... 3.3.3

Author SHA1 Message Date
gh0stkey
5419d4a679 Version: 3.3.3 Update 2024-09-19 17:11:55 +08:00
gh0stkey
ae8cb2fd25 Version: 3.3.3 Update 2024-09-19 17:08:46 +08:00
EvilChen
5b6bdbe5b6 Update README.md 2024-08-28 16:19:24 +08:00
EvilChen
ddb08e9a6e Update README.md 2024-08-28 16:18:25 +08:00
EvilChen
6a2f289d57 Update build.gradle 2024-08-26 10:04:57 +08:00
gh0stkey
84746a7089 Version: 3.3.2 Update 2024-08-23 22:03:31 +08:00
gh0stkey
68f0bce619 Version: 3.3.1 Update 2024-08-12 10:41:24 +08:00
gh0stkey
4f0401347c Version: 3.3.1 Update 2024-08-12 10:34:26 +08:00
gh0stkey
a7e0a2a6ce Update 2024-07-31 08:57:17 +08:00
gh0stkey
b7c5a8363d Update 2024-07-31 08:49:53 +08:00
17 changed files with 626 additions and 481 deletions

View File

@@ -12,7 +12,16 @@
> 随着现代化Web应用采用前后端分离的开发模式日常漏洞挖掘的过程中捕获的HTTP请求流量也相应增加。若想全面评估一个Web应用会花费大量时间在无用的报文上。**HaE的出现旨在解决这类情况**借助HaE您能够**有效减少**测试时间,将更多精力集中在**有价值且有意义**的报文上,从而**提高漏洞挖掘效率**。
**注意事项**:
GitHub项目地址https://github.com/gh0stkey/HaE
GitCode项目地址https://gitcode.com/gh0stkey/HaE
**所获荣誉**:
1. [入选2022年KCon兵器谱](https://mp.weixin.qq.com/s/JohMsl1WD29LHCHuLf8mVQ)
2. [入选GitCode G-Star项目](https://gitcode.com/gh0stkey/HaE)
**注意事项**:
1. HaE 3.3版本开启了AI+新功能,该功能目前仅支持阿里的`Qwen-Long`模型(支持超长文本)和月之暗面的`moonshot-v1-128k`模型(支持短文本),请配置和使用时注意。
2. HaE 3.0版本开始采用`Montoya API`进行开发使用新版HaE需要升级你的BurpSuite版本>=2023.12.1)。

View File

@@ -22,6 +22,8 @@ dependencies {
implementation 'org.yaml:snakeyaml:2.0'
implementation 'dk.brics.automaton:automaton:1.11-8'
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}
test {

View File

@@ -10,6 +10,12 @@ public class Config {
public static String host = "gh0st.cn";
public static String status = "404";
public static String size = "0";
public static String boundary = "\n\t\n";
public static String[] scope = new String[]{
"any",
"any header",

View File

@@ -18,7 +18,7 @@ public class HaE implements BurpExtension {
@Override
public void initialize(MontoyaApi api) {
// 设置扩展名称
String version = "3.3";
String version = "3.3.3";
api.extension().setName(String.format("HaE (%s) - Highlighter and Extractor", version));
// 加载扩展后输出的项目信息
@@ -30,7 +30,7 @@ public class HaE implements BurpExtension {
// 配置文件加载
ConfigLoader configLoader = new ConfigLoader(api);
MessageTableModel messageTableModel = new MessageTableModel(api);
MessageTableModel messageTableModel = new MessageTableModel(api, configLoader);
// 注册Tab页用于查询数据
api.userInterface().registerSuiteTab("HaE", new Main(api, configLoader, messageTableModel));

View File

@@ -1,4 +1,4 @@
package hae.component.config;
package hae.component;
import burp.api.montoya.MontoyaApi;
import hae.component.rule.Rules;
@@ -27,24 +27,23 @@ public class Config extends JPanel {
private final MontoyaApi api;
private final ConfigLoader configLoader;
private final Rules rules;
private JTextField addTextField;
private final String defaultText = "Enter a new item";
private final GridBagConstraints constraints = new GridBagConstraints();
public Config(MontoyaApi api, ConfigLoader configLoader, Rules rules) {
this.api = api;
this.configLoader = configLoader;
this.rules = rules;
constraints.weightx = 1.0;
constraints.fill = GridBagConstraints.HORIZONTAL;
initComponents();
}
private void initComponents() {
setLayout(new BorderLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1.0;
constraints.fill = GridBagConstraints.HORIZONTAL;
JPanel ruleInfoPanel = new JPanel(new GridBagLayout());
ruleInfoPanel.setBorder(new EmptyBorder(10, 15, 5, 15));
@@ -67,7 +66,7 @@ public class Config extends JPanel {
constraints.gridx = 1;
JTabbedPane configTabbedPanel = new JTabbedPane();
String[] settingMode = new String[]{"Exclude suffix", "Block host"};
String[] settingMode = new String[]{"Exclude suffix", "Block host", "Exclude status", "Limit size (MB)"};
JPanel settingPanel = createConfigTablePanel(settingMode, "Setting");
JPanel scopePanel = getScopePanel();
JScrollPane scopeScrollPane = new JScrollPane(scopePanel);
@@ -148,6 +147,19 @@ public class Config extends JPanel {
configLoader.setBlockHost(values);
}
}
if (selected.equals("Exclude status")) {
if (!values.equals(configLoader.getExcludeStatus()) && !values.isEmpty()) {
configLoader.setExcludeStatus(values);
}
}
if (selected.contains("Limit size")) {
if (!values.equals(configLoader.getExcludeStatus()) && !values.isEmpty()) {
String[] limit = values.split("\\|");
configLoader.setLimitSize(limit[limit.length - 1]);
}
}
}
};
}
@@ -166,6 +178,14 @@ public class Config extends JPanel {
if (selected.equals("Block host")) {
addDataToTable(configLoader.getBlockHost().replaceAll("\\|", "\r\n"), model);
}
if (selected.equals("Exclude status")) {
addDataToTable(configLoader.getExcludeStatus().replaceAll("\\|", "\r\n"), model);
}
if (selected.contains("Limit size")) {
addDataToTable(configLoader.getLimitSize(), model);
}
}
};
}
@@ -211,6 +231,10 @@ public class Config extends JPanel {
}
private JPanel createConfigTablePanel(String[] mode, String type) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.weightx = 1.0;
constraints.fill = GridBagConstraints.HORIZONTAL;
JPanel settingPanel = new JPanel(new BorderLayout());
DefaultTableModel model = new DefaultTableModel();
@@ -255,7 +279,7 @@ public class Config extends JPanel {
constraints.gridy = 4;
buttonPanel.add(clearButton, constraints);
addTextField = new JTextField();
JTextField addTextField = new JTextField();
UIEnhancer.setTextFieldPlaceholder(addTextField, defaultText);
inputPanelB.add(addTextField, BorderLayout.CENTER);
@@ -266,13 +290,13 @@ public class Config extends JPanel {
settingPanel.add(inputPanel, BorderLayout.CENTER);
addButton.addActionListener(e -> addActionPerformed(e, model));
addButton.addActionListener(e -> addActionPerformed(e, model, addTextField, setTypeComboBox.getSelectedItem().toString()));
addTextField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
addActionPerformed(null, model);
addActionPerformed(null, model, addTextField, setTypeComboBox.getSelectedItem().toString());
}
}
});
@@ -281,7 +305,9 @@ public class Config extends JPanel {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
try {
String data = (String) clipboard.getData(DataFlavor.stringFlavor);
if (setTypeComboBox.getSelectedItem().toString().contains("Limit size")) {
model.setRowCount(0);
}
if (data != null && !data.isEmpty()) {
addDataToTable(data, model);
}
@@ -372,13 +398,16 @@ public class Config extends JPanel {
configLoader.setScope(String.join("|", HaEScope));
}
private void addActionPerformed(ActionEvent e, DefaultTableModel model) {
private void addActionPerformed(ActionEvent e, DefaultTableModel model, JTextField addTextField, String comboBoxSelected) {
String addTextFieldText = addTextField.getText();
if (!addTextFieldText.equals(defaultText)) {
if (addTextField.getForeground().equals(Color.BLACK)) {
if (comboBoxSelected.contains("Limit size")) {
model.setRowCount(0);
}
addDataToTable(addTextFieldText, model);
addTextField.setText("");
addTextField.requestFocusInWindow();
}
addTextField.setText("");
addTextField.requestFocusInWindow();
}
private void onlineUpdateActionPerformed(ActionEvent e) {

View File

@@ -3,7 +3,6 @@ package hae.component;
import burp.api.montoya.MontoyaApi;
import hae.component.board.Databoard;
import hae.component.board.message.MessageTableModel;
import hae.component.config.Config;
import hae.component.rule.Rules;
import hae.utils.ConfigLoader;

View File

@@ -8,14 +8,17 @@ import hae.component.board.message.MessageTableModel.MessageTable;
import hae.component.board.table.Datatable;
import hae.instances.http.utils.RegularMatcher;
import hae.utils.ConfigLoader;
import hae.utils.UIEnhancer;
import hae.utils.project.ProjectProcessor;
import hae.utils.project.model.HaeFileContent;
import hae.utils.string.StringProcessor;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
@@ -49,8 +52,10 @@ public class Databoard extends JPanel {
private SwingWorker<Map<String, List<String>>, Void> handleComboBoxWorker;
private SwingWorker<Void, Void> applyHostFilterWorker;
private SwingWorker<List<String>, Void> exportActionWorker;
private SwingWorker<List<String>, Void> importActionWorker;
private SwingWorker<List<Object[]>, Void> exportActionWorker;
private SwingWorker<List<Object[]>, Void> importActionWorker;
private final String defaultText = "Please enter the host";
public Databoard(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) {
this.api = api;
@@ -83,6 +88,7 @@ public class Databoard extends JPanel {
menu.add(menuPanel);
hostTextField = new JTextField();
UIEnhancer.setTextFieldPlaceholder(hostTextField, defaultText);
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
dataTabbedPane = new JTabbedPane(JTabbedPane.TOP);
@@ -193,11 +199,11 @@ public class Databoard extends JPanel {
private void handleComboBoxAction(ActionEvent e) {
if (!isMatchHost && hostComboBox.getSelectedItem() != null) {
progressBar.setVisible(true);
setProgressBar(true);
String selectedHost = hostComboBox.getSelectedItem().toString();
if (getHostByList().contains(selectedHost)) {
progressBar.setVisible(true);
setProgressBar(true);
hostTextField.setText(selectedHost);
if (handleComboBoxWorker != null && !handleComboBoxWorker.isDone()) {
@@ -385,9 +391,9 @@ public class Databoard extends JPanel {
exportActionWorker.cancel(true);
}
exportActionWorker = new SwingWorker<List<String>, Void>() {
exportActionWorker = new SwingWorker<List<Object[]>, Void>() {
@Override
protected List<String> doInBackground() {
protected List<Object[]> doInBackground() {
ConcurrentHashMap<String, Map<String, List<String>>> dataMap = Config.globalDataMap;
return exportData(selectedHost, exportDir, dataMap);
}
@@ -395,11 +401,9 @@ public class Databoard extends JPanel {
@Override
protected void done() {
try {
List<String> taskStatusList = get();
List<Object[]> taskStatusList = get();
if (!taskStatusList.isEmpty()) {
String exportStatusMessage = String.format("Exported File List Status:\n%s", String.join("\n", taskStatusList));
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(exportStatusMessage), "Info", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(taskStatusList), "Info", JOptionPane.INFORMATION_MESSAGE);
}
} catch (Exception ignored) {
}
@@ -409,17 +413,36 @@ public class Databoard extends JPanel {
exportActionWorker.execute();
}
private JScrollPane generateTaskStatusPane(String message) {
JTextArea textArea = new JTextArea(message);
textArea.setEditable(false);
textArea.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setPreferredSize(new Dimension(400, 200));
private JScrollPane generateTaskStatusPane(List<Object[]> dataList) {
String[] columnNames = {"#", "Filename", "Status"};
DefaultTableModel taskStatusTableModel = new DefaultTableModel(columnNames, 0);
JTable taskStatusTable = new JTable(taskStatusTableModel);
for (Object[] data : dataList) {
int rowCount = taskStatusTableModel.getRowCount();
int id = rowCount > 0 ? (Integer) taskStatusTableModel.getValueAt(rowCount - 1, 0) + 1 : 1;
Object[] rowData = new Object[data.length + 1];
rowData[0] = id;
System.arraycopy(data, 0, rowData, 1, data.length);
taskStatusTableModel.addRow(rowData);
}
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>(taskStatusTableModel);
taskStatusTable.setRowSorter(sorter);
JScrollPane scrollPane = new JScrollPane(taskStatusTable);
scrollPane.setBorder(new TitledBorder("Task status"));
scrollPane.setPreferredSize(new Dimension(500, 300));
int paneWidth = scrollPane.getPreferredSize().width;
taskStatusTable.getColumnModel().getColumn(0).setPreferredWidth((int) (paneWidth * 0.1));
taskStatusTable.getColumnModel().getColumn(1).setPreferredWidth((int) (paneWidth * 0.7));
taskStatusTable.getColumnModel().getColumn(2).setPreferredWidth((int) (paneWidth * 0.2));
return scrollPane;
}
private List<String> exportData(String selectedHost, String exportDir, Map<String, Map<String, List<String>>> dataMap) {
private List<Object[]> exportData(String selectedHost, String exportDir, Map<String, Map<String, List<String>>> dataMap) {
return dataMap.entrySet().stream()
.filter(entry -> selectedHost.equals("*") || StringProcessor.matchesHostPattern(entry.getKey(), selectedHost))
.filter(entry -> !entry.getKey().contains("*"))
@@ -428,7 +451,7 @@ public class Databoard extends JPanel {
.collect(Collectors.toList());
}
private String exportEntry(Map.Entry<String, Map<String, List<String>>> entry, String exportDir) {
private Object[] exportEntry(Map.Entry<String, Map<String, List<String>>> entry, String exportDir) {
String key = entry.getKey();
Map<String, List<String>> ruleMap = entry.getValue();
@@ -442,7 +465,7 @@ public class Databoard extends JPanel {
.collect(Collectors.toMap(
messageEntry -> messageEntry,
messageEntry -> StringProcessor.getRandomUUID(),
(existing, replacement) -> existing // 在冲突时保留现有的映射
(existing, replacement) -> existing
));
Map<String, Map<String, Object>> httpMap = processEntries(
@@ -463,7 +486,7 @@ public class Databoard extends JPanel {
String filename = String.format("%s/%s-%s.hae", exportDir, StringProcessor.getCurrentTime(), hostName);
boolean createdStatus = projectProcessor.createHaeFile(filename, key, ruleMap, urlMap, httpMap);
return String.format("Filename: %s, Status: %s", filename, createdStatus);
return new Object[]{filename, createdStatus};
}
@@ -507,9 +530,9 @@ public class Databoard extends JPanel {
importActionWorker.cancel(true);
}
importActionWorker = new SwingWorker<List<String>, Void>() {
importActionWorker = new SwingWorker<List<Object[]>, Void>() {
@Override
protected List<String> doInBackground() {
protected List<Object[]> doInBackground() {
List<String> filesWithExtension = findFilesWithExtension(new File(exportDir), ".hae");
return filesWithExtension.stream()
.map(Databoard.this::importData)
@@ -519,10 +542,9 @@ public class Databoard extends JPanel {
@Override
protected void done() {
try {
List<String> taskStatusList = get();
List<Object[]> taskStatusList = get();
if (!taskStatusList.isEmpty()) {
String importStatusMessage = "Imported File List Status:\n" + String.join("\n", taskStatusList);
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(importStatusMessage), "Info", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(taskStatusList), "Info", JOptionPane.INFORMATION_MESSAGE);
}
} catch (Exception ignored) {
}
@@ -532,7 +554,7 @@ public class Databoard extends JPanel {
importActionWorker.execute();
}
private String importData(String filename) {
private Object[] importData(String filename) {
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
HaeFileContent haeFileContent = projectProcessor.readHaeFile(filename);
@@ -568,7 +590,7 @@ public class Databoard extends JPanel {
}
}
return String.format("Filename: %s, Status: %s", filename, readStatus);
return new Object[]{filename, readStatus};
}
private List<String> findFilesWithExtension(File directory, String extension) {
@@ -648,6 +670,8 @@ public class Databoard extends JPanel {
}
messageTableModel.deleteByHost(host);
hostTextField.setText("");
}
}
}

View File

@@ -1,7 +1,6 @@
package hae.component.board.message;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.core.ByteArray;
import burp.api.montoya.http.message.HttpHeader;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
@@ -11,6 +10,7 @@ import burp.api.montoya.ui.editor.HttpRequestEditor;
import burp.api.montoya.ui.editor.HttpResponseEditor;
import hae.Config;
import hae.cache.CachePool;
import hae.utils.ConfigLoader;
import hae.utils.project.FileProcessor;
import hae.utils.string.HashCalculator;
import hae.utils.string.StringProcessor;
@@ -23,6 +23,8 @@ import javax.swing.table.TableRowSorter;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
@@ -30,15 +32,17 @@ import static burp.api.montoya.ui.editor.EditorOptions.READ_ONLY;
public class MessageTableModel extends AbstractTableModel {
private final MontoyaApi api;
private final ConfigLoader configLoader;
private final MessageTable messageTable;
private final JSplitPane splitPane;
private final LinkedList<MessageEntry> log = new LinkedList<>();
private final LinkedList<MessageEntry> filteredLog;
private SwingWorker<Void, Void> currentWorker;
public MessageTableModel(MontoyaApi api) {
public MessageTableModel(MontoyaApi api, ConfigLoader configLoader) {
this.filteredLog = new LinkedList<>();
this.api = api;
this.configLoader = configLoader;
JTabbedPane messageTab = new JTabbedPane();
UserInterface userInterface = api.userInterface();
@@ -435,7 +439,7 @@ public class MessageTableModel extends AbstractTableModel {
public class MessageTable extends JTable {
private MessageEntry messageEntry;
private SwingWorker<Object, Void> currentWorker;
private final ExecutorService executorService;
private int lastSelectedIndex = -1;
private final HttpRequestEditor requestEditor;
private final HttpResponseEditor responseEditor;
@@ -444,41 +448,31 @@ public class MessageTableModel extends AbstractTableModel {
super(messageTableModel);
this.requestEditor = requestEditor;
this.responseEditor = responseEditor;
this.executorService = Executors.newSingleThreadExecutor();
}
@Override
public void changeSelection(int row, int col, boolean toggle, boolean extend) {
super.changeSelection(row, col, toggle, extend);
requestEditor.setRequest(HttpRequest.httpRequest("Loading..."));
responseEditor.setResponse(HttpResponse.httpResponse("Loading..."));
if (currentWorker != null && !currentWorker.isDone()) {
currentWorker.cancel(true);
int selectedIndex = convertRowIndexToModel(row);
if (lastSelectedIndex != selectedIndex) {
lastSelectedIndex = selectedIndex;
executorService.execute(this::getSelectedMessage);
}
}
currentWorker = new SwingWorker<>() {
@Override
protected Void doInBackground() {
int selectedIndex = convertRowIndexToModel(row);
if (lastSelectedIndex != selectedIndex) {
lastSelectedIndex = selectedIndex;
messageEntry = filteredLog.get(selectedIndex);
private void getSelectedMessage() {
messageEntry = filteredLog.get(lastSelectedIndex);
HttpRequestResponse httpRequestResponse = messageEntry.getRequestResponse();
HttpRequestResponse httpRequestResponse = messageEntry.getRequestResponse();
ByteArray requestByte = httpRequestResponse.request().toByteArray();
ByteArray responseByte = httpRequestResponse.response().toByteArray();
requestEditor.setRequest(HttpRequest.httpRequest(messageEntry.getRequestResponse().httpService(), requestByte));
responseEditor.setResponse(HttpResponse.httpResponse(responseByte));
}
return null;
}
};
currentWorker.execute();
requestEditor.setRequest(HttpRequest.httpRequest(messageEntry.getRequestResponse().httpService(), httpRequestResponse.request().toByteArray()));
int responseSizeWithMb = httpRequestResponse.response().toString().length() / 1024 / 1024;
if ((responseSizeWithMb < Integer.parseInt(configLoader.getLimitSize())) || configLoader.getLimitSize().equals("0")) {
responseEditor.setResponse(httpRequestResponse.response());
} else {
responseEditor.setResponse(HttpResponse.httpResponse("Exceeds length limit."));
}
}
}
}

View File

@@ -34,7 +34,7 @@ public class AIPower {
public AIPower(MontoyaApi api, ConfigLoader configLoader, String aiModel, String aiBaseUrl, String[] apiKey) {
this.api = api;
this.configLoader = configLoader;
this.httpUtils = new HttpUtils(api);
this.httpUtils = new HttpUtils(api, configLoader);
this.aiModel = aiModel;
this.aiBaseUrl = aiBaseUrl;

View File

@@ -23,6 +23,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,7 @@ public class Datatable extends JPanel {
private final JTable dataTable;
private final DefaultTableModel dataTableModel;
private final JTextField searchField;
private final JTextField secondSearchField;
private final TableRowSorter<DefaultTableModel> sorter;
private final JCheckBox searchMode = new JCheckBox("Reverse search");
private final String tabName;
@@ -52,7 +54,8 @@ public class Datatable extends JPanel {
this.dataTable = new JTable(dataTableModel);
this.sorter = new TableRowSorter<>(dataTableModel);
this.searchField = new JTextField();
this.searchField = new JTextField(10);
this.secondSearchField = new JTextField(10);
this.aiEmpoweredMenu = new JPopupMenu();
this.footerPanel = new JPanel(new BorderLayout(0, 5));
@@ -80,11 +83,7 @@ public class Datatable extends JPanel {
}
}
// 设置灰色默认文本
String searchText = "Search";
UIEnhancer.setTextFieldPlaceholder(searchField, searchText);
// 监听输入框内容输入、更新、删除
UIEnhancer.setTextFieldPlaceholder(searchField, "Search");
searchField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
@@ -103,6 +102,25 @@ public class Datatable extends JPanel {
});
UIEnhancer.setTextFieldPlaceholder(secondSearchField, "Second search");
secondSearchField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
performSearch();
}
@Override
public void removeUpdate(DocumentEvent e) {
performSearch();
}
@Override
public void changedUpdate(DocumentEvent e) {
performSearch();
}
});
// 设置布局
JScrollPane scrollPane = new JScrollPane(dataTable);
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
@@ -162,6 +180,8 @@ public class Datatable extends JPanel {
optionsPanel.add(Box.createHorizontalStrut(5));
optionsPanel.add(searchField);
optionsPanel.add(Box.createHorizontalStrut(5));
optionsPanel.add(secondSearchField);
optionsPanel.add(Box.createHorizontalStrut(5));
optionsPanel.add(aiEmpoweredButton);
footerPanel.setBorder(BorderFactory.createEmptyBorder(2, 3, 5, 3));
@@ -252,29 +272,61 @@ public class Datatable extends JPanel {
}
private void performSearch() {
RowFilter<Object, Object> firstRowFilter = applyFirstSearchFilter();
RowFilter<Object, Object> secondRowFilter = applySecondFilter();
if (searchField.getForeground().equals(Color.BLACK)) {
RowFilter<Object, Object> rowFilter = new RowFilter<Object, Object>() {
public boolean include(Entry<?, ?> entry) {
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();
if (pattern != null) {
return searchFieldTextText.isEmpty() || pattern.matcher(entryValue).find() != searchMode.isSelected();
} else {
return searchFieldTextText.isEmpty() || entryValue.contains(searchFieldTextText) != searchMode.isSelected();
}
}
};
sorter.setRowFilter(rowFilter);
sorter.setRowFilter(firstRowFilter);
if (secondSearchField.getForeground().equals(Color.BLACK)) {
List<RowFilter<Object, Object>> filters = new ArrayList<>();
filters.add(firstRowFilter);
filters.add(secondRowFilter);
sorter.setRowFilter(RowFilter.andFilter(filters));
}
}
}
private RowFilter<Object, Object> applyFirstSearchFilter() {
return new RowFilter<Object, Object>() {
public boolean include(Entry<?, ?> entry) {
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();
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();
searchFieldTextText = searchFieldTextText.toLowerCase();
if (pattern != null) {
return searchFieldTextText.isEmpty() || pattern.matcher(entryValue).find();
} else {
return searchFieldTextText.isEmpty() || entryValue.contains(searchFieldTextText);
}
}
};
}
public void setTableListener(MessageTableModel messagePanel) {
// 表格复制功能
dataTable.setTransferHandler(new TransferHandler() {

View File

@@ -9,9 +9,11 @@ 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.Config;
import hae.component.board.table.Datatable;
import hae.instances.http.utils.MessageProcessor;
import hae.utils.ConfigLoader;
import hae.utils.http.HttpUtils;
import hae.utils.string.StringProcessor;
import javax.swing.*;
@@ -37,6 +39,7 @@ public class RequestEditor implements HttpRequestEditorProvider {
private static class Editor implements ExtensionProvidedHttpRequestEditor {
private final MontoyaApi api;
private final ConfigLoader configLoader;
private final HttpUtils httpUtils;
private final EditorCreationContext creationContext;
private final MessageProcessor messageProcessor;
private HttpRequestResponse requestResponse;
@@ -47,6 +50,7 @@ public class RequestEditor implements HttpRequestEditorProvider {
public Editor(MontoyaApi api, ConfigLoader configLoader, EditorCreationContext creationContext) {
this.api = api;
this.configLoader = configLoader;
this.httpUtils = new HttpUtils(api, configLoader);
this.creationContext = creationContext;
this.messageProcessor = new MessageProcessor(api);
}
@@ -69,16 +73,10 @@ public class RequestEditor implements HttpRequestEditorProvider {
try {
String host = StringProcessor.getHostByUrl(request.url());
if (!host.isEmpty()) {
String[] hostList = configLoader.getBlockHost().split("\\|");
boolean isBlockHost = isBlockHost(hostList, host);
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
String toolType = creationContext.toolSource().toolType().toolName();
boolean isToolScope = configLoader.getScope().contains(toolType);
boolean matches = httpUtils.verifyHttpRequestResponse(requestResponse, toolType);
boolean matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost || !isToolScope;
if (!matches && !request.bodyToString().equals("Loading...")) {
if (!matches) {
this.dataList = messageProcessor.processRequest("", request, false);
return isListHasData(this.dataList);
}
@@ -121,19 +119,6 @@ public class RequestEditor implements HttpRequestEditorProvider {
}
}
public static boolean isBlockHost(String[] hostList, String host) {
boolean isBlockHost = false;
for (String hostName : hostList) {
String cleanedHost = StringProcessor.replaceFirstOccurrence(hostName, "*.", "");
if (hostName.contains("*.") && StringProcessor.matchFromEnd(host, cleanedHost)) {
isBlockHost = true;
} else if (host.equals(hostName) || hostName.equals("*")) {
isBlockHost = true;
}
}
return isBlockHost;
}
public static boolean isListHasData(List<Map<String, String>> dataList) {
if (dataList != null && !dataList.isEmpty()) {
Map<String, String> dataMap = dataList.get(0);
@@ -148,7 +133,7 @@ public class RequestEditor implements HttpRequestEditorProvider {
Map<String, String> dataMap = result.get(0);
if (dataMap != null && !dataMap.isEmpty()) {
dataMap.keySet().forEach(i -> {
String[] extractData = dataMap.get(i).split("\n");
String[] extractData = dataMap.get(i).split(Config.boundary);
Datatable dataPanel = new Datatable(api, configLoader, i, Arrays.asList(extractData));
tabbedPane.addTab(i, dataPanel);
});

View File

@@ -13,11 +13,11 @@ import burp.api.montoya.ui.editor.extension.HttpResponseEditorProvider;
import hae.component.board.table.Datatable;
import hae.instances.http.utils.MessageProcessor;
import hae.utils.ConfigLoader;
import hae.utils.http.HttpUtils;
import hae.utils.string.StringProcessor;
import javax.swing.*;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -38,6 +38,7 @@ public class ResponseEditor implements HttpResponseEditorProvider {
private static class Editor implements ExtensionProvidedHttpResponseEditor {
private final MontoyaApi api;
private final ConfigLoader configLoader;
private final HttpUtils httpUtils;
private final EditorCreationContext creationContext;
private final MessageProcessor messageProcessor;
private HttpRequestResponse requestResponse;
@@ -48,6 +49,7 @@ public class ResponseEditor implements HttpResponseEditorProvider {
public Editor(MontoyaApi api, ConfigLoader configLoader, EditorCreationContext creationContext) {
this.api = api;
this.configLoader = configLoader;
this.httpUtils = new HttpUtils(api, configLoader);
this.creationContext = creationContext;
this.messageProcessor = new MessageProcessor(api);
}
@@ -75,20 +77,14 @@ public class ResponseEditor implements HttpResponseEditorProvider {
try {
String host = StringProcessor.getHostByUrl(request.url());
if (!host.isEmpty()) {
String[] hostList = configLoader.getBlockHost().split("\\|");
boolean isBlockHost = RequestEditor.isBlockHost(hostList, host);
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
String toolType = creationContext.toolSource().toolType().toolName();
boolean isToolScope = configLoader.getScope().contains(toolType);
matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost || !isToolScope;
matches = httpUtils.verifyHttpRequestResponse(requestResponse, toolType);
}
} catch (Exception ignored) {
}
}
if (!matches && !response.bodyToString().equals("Loading...")) {
if (!matches) {
this.dataList = messageProcessor.processResponse("", response, false);
return RequestEditor.isListHasData(this.dataList);
}

View File

@@ -7,20 +7,20 @@ import burp.api.montoya.http.handler.*;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import hae.component.board.message.MessageTableModel;
import hae.instances.editor.RequestEditor;
import hae.instances.http.utils.MessageProcessor;
import hae.utils.ConfigLoader;
import hae.utils.http.HttpUtils;
import hae.utils.string.StringProcessor;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class HttpMessageHandler implements HttpHandler {
private final MontoyaApi api;
private final ConfigLoader configLoader;
private final HttpUtils httpUtils;
private final MessageTableModel messageTableModel;
private final MessageProcessor messageProcessor;
@@ -29,12 +29,11 @@ public class HttpMessageHandler implements HttpHandler {
private final ThreadLocal<String> host = ThreadLocal.withInitial(() -> "");
private final ThreadLocal<List<String>> colorList = 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<HttpRequest> httpRequest = new ThreadLocal<>();
public HttpMessageHandler(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) {
this.api = api;
this.configLoader = configLoader;
this.httpUtils = new HttpUtils(api, configLoader);
this.messageTableModel = messageTableModel;
this.messageProcessor = new MessageProcessor(api);
}
@@ -47,22 +46,7 @@ public class HttpMessageHandler implements HttpHandler {
Annotations annotations = httpRequestToBeSent.annotations();
try {
httpRequest.set(httpRequestToBeSent);
host.set(StringProcessor.getHostByUrl(httpRequestToBeSent.url()));
String[] hostList = configLoader.getBlockHost().split("\\|");
boolean isBlockHost = RequestEditor.isBlockHost(hostList, host.get());
String toolType = httpRequestToBeSent.toolSource().toolType().toolName();
boolean isToolScope = configLoader.getScope().contains(toolType);
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
matches.set(suffixList.contains(httpRequestToBeSent.fileExtension().toLowerCase()) || isBlockHost || !isToolScope);
if (!matches.get()) {
List<Map<String, String>> result = messageProcessor.processRequest(host.get(), httpRequestToBeSent, true);
setColorAndCommentList(result);
}
} catch (Exception e) {
api.logging().logToError("handleHttpRequestToBeSent: " + e.getMessage());
}
@@ -73,33 +57,42 @@ public class HttpMessageHandler implements HttpHandler {
@Override
public ResponseReceivedAction handleHttpResponseReceived(HttpResponseReceived httpResponseReceived) {
Annotations annotations = httpResponseReceived.annotations();
HttpRequest request = httpResponseReceived.initiatingRequest();
HttpRequestResponse requestResponse = HttpRequestResponse.httpRequestResponse(request, httpResponseReceived);
String toolType = httpResponseReceived.toolSource().toolType().toolName();
if (!matches.get()) {
List<Map<String, String>> result = messageProcessor.processResponse(host.get(), httpResponseReceived, true);
setColorAndCommentList(result);
// 设置高亮颜色和注释
if (!colorList.get().isEmpty() && !commentList.get().isEmpty()) {
String color = messageProcessor.retrieveFinalColor(messageProcessor.retrieveColorIndices(colorList.get()));
annotations.setHighlightColor(HighlightColor.highlightColor(color));
String comment = StringProcessor.mergeComment(String.join(", ", commentList.get()));
annotations.setNotes(comment);
boolean matches = httpUtils.verifyHttpRequestResponse(requestResponse, toolType);
HttpRequestResponse httpRequestResponse = HttpRequestResponse.httpRequestResponse(httpRequest.get(), httpResponseReceived);
if (!matches) {
try {
setColorAndCommentList(messageProcessor.processRequest(host.get(), request, true));
setColorAndCommentList(messageProcessor.processResponse(host.get(), httpResponseReceived, true));
// 添加到Databoard
String method = httpRequest.get().method();
String url = httpRequest.get().url();
String status = String.valueOf(httpResponseReceived.statusCode());
String length = String.valueOf(httpResponseReceived.toByteArray().length());
// 设置高亮颜色和注释
if (!colorList.get().isEmpty() && !commentList.get().isEmpty()) {
String color = messageProcessor.retrieveFinalColor(messageProcessor.retrieveColorIndices(colorList.get()));
annotations.setHighlightColor(HighlightColor.highlightColor(color));
String comment = StringProcessor.mergeComment(String.join(", ", commentList.get()));
annotations.setNotes(comment);
// 后台提交,防止线程阻塞
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
messageTableModel.add(httpRequestResponse, url, method, status, length, comment, color, "", "");
return null;
}
}.run();
HttpRequestResponse httpRequestResponse = HttpRequestResponse.httpRequestResponse(request, httpResponseReceived);
String method = request.method();
String url = request.url();
String status = String.valueOf(httpResponseReceived.statusCode());
String length = String.valueOf(httpResponseReceived.toByteArray().length());
// 后台提交,防止线程阻塞
new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() {
messageTableModel.add(httpRequestResponse, url, method, status, length, comment, color, "", "");
return null;
}
}.execute();
}
} catch (Exception e) {
api.logging().logToError("handleHttpResponseReceived: " + e.getMessage());
}
}

View File

@@ -92,7 +92,7 @@ public class RegularMatcher {
if (!result.isEmpty()) {
tmpMap.put("color", color);
String dataStr = String.join("\n", result);
String dataStr = String.join(Config.boundary, result);
tmpMap.put("data", dataStr);
String nameAndSize = String.format("%s (%s)", name, result.size());

View File

@@ -77,8 +77,11 @@ public class ConfigLoader {
public void initConfig() {
Map<String, Object> r = new LinkedHashMap<>();
r.put("excludeSuffix", getExcludeSuffix());
r.put("blockHost", getBlockHost());
r.put("ExcludeSuffix", getExcludeSuffix());
r.put("BlockHost", getBlockHost());
r.put("ExcludeStatus", getExcludeStatus());
r.put("LimitSize", getLimitSize());
r.put("HaEScope", getScope());
try {
Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8);
yaml.dump(r, ws);
@@ -147,21 +150,29 @@ public class ConfigLoader {
}
public String getBlockHost() {
return getValueFromConfig("blockHost", Config.host);
return getValueFromConfig("BlockHost", Config.host);
}
public String getExcludeSuffix() {
return getValueFromConfig("excludeSuffix", Config.suffix);
return getValueFromConfig("ExcludeSuffix", Config.suffix);
}
public String getExcludeStatus() {
return getValueFromConfig("ExcludeStatus", Config.status);
}
public String getLimitSize() {
return getValueFromConfig("LimitSize", Config.size);
}
public String getScope() {
return getValueFromConfig("HaEScope", Config.scopeOptions);
}
private String getValueFromConfig(String name, String value) {
private String getValueFromConfig(String name, String defaultValue) {
File yamlSetting = new File(configFilePath);
if (!yamlSetting.exists() || !yamlSetting.isFile()) {
return value;
return defaultValue;
}
try (InputStream inorder = Files.newInputStream(Paths.get(configFilePath))) {
@@ -173,7 +184,7 @@ public class ConfigLoader {
} catch (Exception ignored) {
}
return value;
return defaultValue;
}
public void setAlibabaAIAPIKey(String apiKey) {
@@ -189,11 +200,19 @@ public class ConfigLoader {
}
public void setExcludeSuffix(String excludeSuffix) {
setValueToConfig("excludeSuffix", excludeSuffix);
setValueToConfig("ExcludeSuffix", excludeSuffix);
}
public void setBlockHost(String blockHost) {
setValueToConfig("blockHost", blockHost);
setValueToConfig("BlockHost", blockHost);
}
public void setExcludeStatus(String status) {
setValueToConfig("ExcludeStatus", status);
}
public void setLimitSize(String size) {
setValueToConfig("LimitSize", size);
}
public void setScope(String scope) {

View File

@@ -1,16 +1,24 @@
package hae.utils.http;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.http.HttpService;
import burp.api.montoya.http.message.HttpRequestResponse;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.http.message.requests.HttpTransformation;
import burp.api.montoya.http.message.responses.HttpResponse;
import burp.api.montoya.utilities.RandomUtils;
import hae.utils.ConfigLoader;
import hae.utils.string.StringProcessor;
import java.util.Arrays;
import java.util.List;
public class HttpUtils {
private final MontoyaApi api;
private final ConfigLoader configLoader;
public HttpUtils(MontoyaApi api) {
public HttpUtils(MontoyaApi api, ConfigLoader configLoader) {
this.api = api;
this.configLoader = configLoader;
}
public HttpRequest generateRequestByMultipartUploadMethod(String url, String name, String filename, String content) {
@@ -18,25 +26,54 @@ public class HttpUtils {
String boundary = api.utilities().randomUtils().randomString(32, RandomUtils.CharacterSet.ASCII_LETTERS);
StringBuilder newBody = new StringBuilder();
newBody.append(String.format("--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n\r\n%s\r\n", boundary, name, filename, content));
newBody.append(String.format("--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", boundary, "purpose", "file-extract"));
newBody.append("--").append(boundary).append("--\r\n");
String newBody = String.format("--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n\r\n%s\r\n", boundary, name, filename, content) +
String.format("--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", boundary, "purpose", "file-extract") +
"--" + boundary + "--\r\n";
baseRequest = baseRequest.withUpdatedHeader("Content-Type", "multipart/form-data; boundary=" + boundary).withBody(newBody.toString());
baseRequest = baseRequest.withUpdatedHeader("Content-Type", "multipart/form-data; boundary=" + boundary).withBody(newBody);
return baseRequest;
}
public HttpRequest generateRequestByJsonMethod(String url, String data) {
HttpRequest baseRequest = HttpRequest.httpRequestFromUrl(url).withTransformationApplied(HttpTransformation.TOGGLE_METHOD);
HttpService baseService = baseRequest.httpService();
String requestString = baseRequest.toString().replace("application/x-www-form-urlencoded", "application/json");
baseRequest = HttpRequest.httpRequest(baseService, requestString).withBody(data);
return baseRequest;
}
public HttpRequest generateRequestByDeleteMethod(String url) {
return HttpRequest.httpRequestFromUrl(url).withMethod("DELETE");
}
public boolean verifyHttpRequestResponse(HttpRequestResponse requestResponse, String toolType) {
HttpRequest request = requestResponse.request();
HttpResponse response = requestResponse.response();
boolean retStatus = false;
try {
String host = StringProcessor.getHostByUrl(request.url());
String[] hostList = configLoader.getBlockHost().split("\\|");
boolean isBlockHost = isBlockHost(hostList, host);
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
boolean isExcludeSuffix = suffixList.contains(request.fileExtension().toLowerCase());
boolean isToolScope = !configLoader.getScope().contains(toolType);
List<String> statusList = Arrays.asList(configLoader.getExcludeStatus().split("\\|"));
boolean isExcludeStatus = statusList.contains(String.valueOf(response.statusCode()));
retStatus = isExcludeSuffix || isBlockHost || isToolScope || isExcludeStatus;
} catch (Exception ignored) {
}
return retStatus;
}
private boolean isBlockHost(String[] hostList, String host) {
boolean isBlockHost = false;
for (String hostName : hostList) {
String cleanedHost = StringProcessor.replaceFirstOccurrence(hostName, "*.", "");
if (hostName.contains("*.") && StringProcessor.matchFromEnd(host, cleanedHost)) {
isBlockHost = true;
} else if (host.equals(hostName) || hostName.equals("*")) {
isBlockHost = true;
}
}
return isBlockHost;
}
}

View File

@@ -1,284 +1,284 @@
rules:
- group: Fingerprint
rule:
- name: Shiro
loaded: true
f_regex: (=deleteMe|rememberMe=)
s_regex: ''
format: '{0}'
color: green
scope: any header
engine: dfa
sensitive: true
- name: JSON Web Token
loaded: true
f_regex: (eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}|eyJ[A-Za-z0-9_\/+-]{10,}\.[A-Za-z0-9._\/+-]{10,})
s_regex: ''
format: '{0}'
color: green
scope: any
engine: nfa
sensitive: true
- name: Swagger UI
loaded: true
f_regex: ((swagger-ui.html)|(\"swagger\":)|(Swagger UI)|(swaggerUi)|(swaggerVersion))
s_regex: ''
format: '{0}'
color: red
scope: response body
engine: dfa
sensitive: false
- name: Ueditor
loaded: true
f_regex: (ueditor\.(config|all)\.js)
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: dfa
sensitive: false
- name: Druid
loaded: true
f_regex: (Druid Stat Index)
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: dfa
sensitive: false
- group: Maybe Vulnerability
rule:
- name: Java Deserialization
loaded: true
f_regex: (javax\.faces\.ViewState)
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: dfa
sensitive: false
- name: Debug Logic Parameters
loaded: true
f_regex: ((access=)|(adm=)|(admin=)|(alter=)|(cfg=)|(clone=)|(config=)|(create=)|(dbg=)|(debug=)|(delete=)|(disable=)|(edit=)|(enable=)|(exec=)|(execute=)|(grant=)|(load=)|(make=)|(modify=)|(rename=)|(reset=)|(root=)|(shell=)|(test=)|(toggl=))
s_regex: ''
format: '{0}'
color: cyan
scope: request
engine: dfa
sensitive: false
- name: URL As A Value
loaded: true
f_regex: (=(https?)(://|%3a%2f%2f))
s_regex: ''
format: '{0}'
color: cyan
scope: any
engine: nfa
sensitive: false
- name: Upload Form
loaded: true
f_regex: (type\=\"file\")
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: dfa
sensitive: false
- name: DoS Paramters
loaded: true
f_regex: ((size=)|(page=)|(num=)|(limit=)|(start=)|(end=)|(count=))
s_regex: ''
format: '{0}'
color: cyan
scope: request
engine: dfa
sensitive: false
- group: Basic Information
rule:
- name: Email
loaded: true
f_regex: (([a-z0-9]+[_|\.])*[a-z0-9]+@([a-z0-9]+[-|_|\.])*[a-z0-9]+\.((?!js|css|jpg|jpeg|png|ico)[a-z]{2,5}))
s_regex: ''
format: '{0}'
color: yellow
scope: response
engine: nfa
sensitive: false
- name: Chinese IDCard
loaded: true
f_regex: '[^0-9]((\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(\d{6}(18|19|20)\d{2}(0[1-9]|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)))[^0-9]'
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: nfa
sensitive: true
- name: Chinese Mobile Number
loaded: true
f_regex: '[^\w]((?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8})[^\w]'
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: nfa
sensitive: false
- name: Internal IP Address
loaded: true
f_regex: '[^0-9]((127\.0\.0\.1)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3}))'
s_regex: ''
format: '{0}'
color: cyan
scope: response
engine: nfa
sensitive: true
- name: MAC Address
loaded: true
f_regex: (^([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})|[^a-zA-Z0-9]([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}))
s_regex: ''
format: '{0}'
color: green
scope: response
engine: nfa
sensitive: true
- group: Sensitive Information
rule:
- name: Cloud Key
loaded: true
f_regex: (((access)(|-|_)(key)(|-|_)(id|secret))|(LTAI[a-z0-9]{12,20}))
s_regex: ''
format: '{0}'
color: yellow
scope: any
engine: nfa
sensitive: false
- name: Windows File/Dir Path
loaded: true
f_regex: '[^\w](([a-zA-Z]:\\(?:\w+\\?)*)|([a-zA-Z]:\\(?:\w+\\)*\w+\.\w+))'
s_regex: ''
format: '{0}'
color: green
scope: response
engine: nfa
sensitive: true
- name: Password Field
loaded: true
f_regex: ((|'|")(|[\w]{1,10})([p](ass|wd|asswd|assword))(|[\w]{1,10})(|'|")(:|=)(
|)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Username Field
loaded: true
f_regex: ((|'|")(|[\w]{1,10})(([u](ser|name|sername))|(account)|((((create|update)((d|r)|(by|on|at)))|(creator))))(|[\w]{1,10})(|'|")(:|=)(
|)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: nfa
sensitive: false
- name: WeCom Key
loaded: true
f_regex: ((corp)(id|secret))
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: dfa
sensitive: false
- name: JDBC Connection
loaded: true
f_regex: (jdbc:[a-z:]+://[a-z0-9\.\-_:;=/@?,&]+)
s_regex: ''
format: '{0}'
color: yellow
scope: any
engine: nfa
sensitive: false
- name: Authorization Header
loaded: true
f_regex: ((basic [a-z0-9=:_\+\/-]{5,100})|(bearer [a-z0-9_.=:_\+\/-]{5,100}))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Sensitive Field
loaded: true
f_regex: ((\[)?('|")?([\w]{0,10})((key)|(secret)|(token)|(config)|(auth)|(access)|(admin))([\w]{0,10})('|")?(\])?(
|)(:|=)( |)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: yellow
scope: response
engine: nfa
sensitive: false
- group: Other
rule:
- name: Linkfinder
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,}|)))(?:"|')
s_regex: ''
format: '{0}'
color: gray
scope: response body
engine: nfa
sensitive: true
- name: Source Map
loaded: true
f_regex: (\.js\.map)
s_regex: ''
format: '{0}'
color: pink
scope: response body
engine: dfa
sensitive: false
- name: HTML Notes
loaded: true
f_regex: (<!--.*?-->)
s_regex: ''
format: '{0}'
color: magenta
scope: response body
engine: nfa
sensitive: false
- name: Create Script
loaded: true
f_regex: (\+\{.*?\}\[[a-zA-Z]\]\+".*?\.js")
s_regex: '"?([\w].*?)"?:"(.*?)"'
format: '{0}.{1}'
color: green
scope: response body
engine: nfa
sensitive: false
- name: URL Schemes
loaded: true
f_regex: ((?![http]|[https])(([-A-Za-z0-9]{1,20})://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Router Push
loaded: true
f_regex: (\$router\.push)
s_regex: ''
format: '{0}'
color: magenta
scope: response body
engine: dfa
sensitive: false
- name: All URL
loaded: true
f_regex: (https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;\u4E00-\u9FFF]+[-A-Za-z0-9+&@#/%=~_|])
s_regex: ''
format: '{0}'
color: gray
scope: response body
engine: nfa
sensitive: true
- group: Fingerprint
rule:
- name: Shiro
loaded: true
f_regex: (=deleteMe|rememberMe=)
s_regex: ''
format: '{0}'
color: green
scope: any header
engine: dfa
sensitive: true
- name: JSON Web Token
loaded: true
f_regex: (eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9._-]{10,}|eyJ[A-Za-z0-9_\/+-]{10,}\.[A-Za-z0-9._\/+-]{10,})
s_regex: ''
format: '{0}'
color: green
scope: any
engine: nfa
sensitive: true
- name: Swagger UI
loaded: true
f_regex: ((swagger-ui.html)|(\"swagger\":)|(Swagger UI)|(swaggerUi)|(swaggerVersion))
s_regex: ''
format: '{0}'
color: red
scope: response body
engine: dfa
sensitive: false
- name: Ueditor
loaded: true
f_regex: (ueditor\.(config|all)\.js)
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: dfa
sensitive: false
- name: Druid
loaded: true
f_regex: (Druid Stat Index)
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: dfa
sensitive: false
- group: Maybe Vulnerability
rule:
- name: Java Deserialization
loaded: true
f_regex: (javax\.faces\.ViewState)
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: dfa
sensitive: false
- name: Debug Logic Parameters
loaded: true
f_regex: ((access=)|(adm=)|(admin=)|(alter=)|(cfg=)|(clone=)|(config=)|(create=)|(dbg=)|(debug=)|(delete=)|(disable=)|(edit=)|(enable=)|(exec=)|(execute=)|(grant=)|(load=)|(make=)|(modify=)|(rename=)|(reset=)|(root=)|(shell=)|(test=)|(toggl=))
s_regex: ''
format: '{0}'
color: cyan
scope: request
engine: dfa
sensitive: false
- name: URL As A Value
loaded: true
f_regex: (=(https?)(://|%3a%2f%2f))
s_regex: ''
format: '{0}'
color: cyan
scope: any
engine: nfa
sensitive: false
- name: Upload Form
loaded: true
f_regex: (type\=\"file\")
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: dfa
sensitive: false
- name: DoS Paramters
loaded: true
f_regex: ((size=)|(page=)|(num=)|(limit=)|(start=)|(end=)|(count=))
s_regex: ''
format: '{0}'
color: cyan
scope: request
engine: dfa
sensitive: false
- group: Basic Information
rule:
- name: Email
loaded: true
f_regex: (([a-z0-9]+[_|\.])*[a-z0-9]+@([a-z0-9]+[-|_|\.])*[a-z0-9]+\.((?!js|css|jpg|jpeg|png|ico)[a-z]{2,5}))
s_regex: ''
format: '{0}'
color: yellow
scope: response
engine: nfa
sensitive: false
- name: Chinese IDCard
loaded: true
f_regex: '[^0-9]((\d{8}(0\d|10|11|12)([0-2]\d|30|31)\d{3}$)|(\d{6}(18|19|20)\d{2}(0[1-9]|10|11|12)([0-2]\d|30|31)\d{3}(\d|X|x)))[^0-9]'
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: nfa
sensitive: true
- name: Chinese Mobile Number
loaded: true
f_regex: '[^\w]((?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8})[^\w]'
s_regex: ''
format: '{0}'
color: orange
scope: response body
engine: nfa
sensitive: false
- name: Internal IP Address
loaded: true
f_regex: '[^0-9]((127\.0\.0\.1)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3}))'
s_regex: ''
format: '{0}'
color: cyan
scope: response
engine: nfa
sensitive: true
- name: MAC Address
loaded: true
f_regex: (^([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5})|[^a-zA-Z0-9]([a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}))
s_regex: ''
format: '{0}'
color: green
scope: response
engine: nfa
sensitive: true
- group: Sensitive Information
rule:
- name: Cloud Key
loaded: true
f_regex: (((access)(|-|_)(key)(|-|_)(id|secret))|(LTAI[a-z0-9]{12,20}))
s_regex: ''
format: '{0}'
color: yellow
scope: any
engine: nfa
sensitive: false
- name: Windows File/Dir Path
loaded: true
f_regex: '[^\w](([a-zA-Z]:\\(?:\w+\\?)*)|([a-zA-Z]:\\(?:\w+\\)*\w+\.\w+))'
s_regex: ''
format: '{0}'
color: green
scope: response
engine: nfa
sensitive: true
- name: Password Field
loaded: true
f_regex: ((|'|")(|[\w]{1,10})([p](ass|wd|asswd|assword))(|[\w]{1,10})(|'|")(:|=)(
|)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Username Field
loaded: true
f_regex: ((|'|")(|[\w]{1,10})(([u](ser|name|sername))|(account)|((((create|update)((d|r)|(by|on|at)))|(creator))))(|[\w]{1,10})(|'|")(:|=)(
|)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: nfa
sensitive: false
- name: WeCom Key
loaded: true
f_regex: ((corp)(id|secret))
s_regex: ''
format: '{0}'
color: green
scope: response body
engine: dfa
sensitive: false
- name: JDBC Connection
loaded: true
f_regex: (jdbc:[a-z:]+://[a-z0-9\.\-_:;=/@?,&]+)
s_regex: ''
format: '{0}'
color: yellow
scope: any
engine: nfa
sensitive: false
- name: Authorization Header
loaded: true
f_regex: ((basic [a-z0-9=:_\+\/-]{5,100})|(bearer [a-z0-9_.=:_\+\/-]{5,100}))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Sensitive Field
loaded: true
f_regex: ((\[)?('|")?([\w]{0,10})((key)|(secret)|(token)|(config)|(auth)|(access)|(admin)|(ticket))([\w]{0,10})('|")?(\])?(
|)(:|=)( |)('|")(.*?)('|")(|,))
s_regex: ''
format: '{0}'
color: yellow
scope: response
engine: nfa
sensitive: false
- group: Other
rule:
- name: Linkfinder
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,}|)))(?:"|')
s_regex: ''
format: '{0}'
color: gray
scope: response body
engine: nfa
sensitive: true
- name: Source Map
loaded: true
f_regex: (\.js\.map)
s_regex: ''
format: '{0}'
color: pink
scope: response body
engine: dfa
sensitive: false
- name: Create Script
loaded: true
f_regex: (\{[^{}]*\}\s*\[[^\s]*\]\s*\+\s*"[^\s]*\.js")
s_regex: '"?([\w].*?)"?:"(.*?)"'
format: '{0}.{1}'
color: green
scope: response body
engine: nfa
sensitive: false
- name: URL Schemes
loaded: true
f_regex: ((?![http]|[https])(([-A-Za-z0-9]{1,20})://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]))
s_regex: ''
format: '{0}'
color: yellow
scope: response body
engine: nfa
sensitive: false
- name: Router Push
loaded: true
f_regex: (\$router\.push)
s_regex: ''
format: '{0}'
color: magenta
scope: response body
engine: dfa
sensitive: false
- name: All URL
loaded: true
f_regex: (https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;\u4E00-\u9FFF]+[-A-Za-z0-9+&@#/%=~_|])
s_regex: ''
format: '{0}'
color: gray
scope: response body
engine: nfa
sensitive: true
- name: Request URI
loaded: true
f_regex: ' ((?!.*\.js(\?.*)?$)(.*?[^.js$])) '
s_regex: ''
format: '{0}'
color: gray
scope: request line
engine: nfa
sensitive: false