Version: 3.3 Update
This commit is contained in:
@@ -24,6 +24,8 @@ public class Config {
|
||||
"request body"
|
||||
};
|
||||
|
||||
public static String scopeOptions = "Suite|Target|Proxy|Scanner|Intruder|Repeater|Logger|Sequencer|Decoder|Comparer|Extensions|Organizer|Recorded login replayer";
|
||||
|
||||
public static String[] ruleFields = {
|
||||
"Loaded", "Name", "F-Regex", "S-Regex", "Format", "Color", "Scope", "Engine", "Sensitive"
|
||||
};
|
||||
@@ -51,9 +53,12 @@ public class Config {
|
||||
"gray"
|
||||
};
|
||||
|
||||
public static String prompt = "You are a data security expert in the field of cyber security. Your task is to optimize the information provided by the user and then output it in JSON format. The user-supplied information is data that has been extracted by regular expressions. The user-supplied information is divided into two parts, the first part is RuleName which represents the name of the regular expression and the second part is MarkInfo which represents the data extracted by the regular expression. You need to find the matching or similar data in MarkInfo according to the meaning of RuleName, and output the original rows of these data in JSON format.(garbled and meaningless data rows should be removed)\n" +
|
||||
"You must ensure that the extracted data is accurately expressed and correctly formatted in the JSON structure. Your output data must comply with the original MarkInfo content rows without modification, and strictly adhere to the following JSON format for return, no other text, code and formatting (e.g., line breaks, carriage returns, indentation, spaces), once the return of other irrelevant content will cause irreparable damage to the user: {\"data\":[\"data1\", \"data2\"]}.";
|
||||
|
||||
public static String userTextFormat = "User Input: \r\nRuleName: %s\r\nMarkInfo: %s";
|
||||
|
||||
public static Map<String, Object[][]> globalRules = new HashMap<>();
|
||||
|
||||
public static ConcurrentHashMap<String, Map<String, List<String>>> globalDataMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static ConcurrentHashMap<String, Map<String, Object>> globalHostHashMap = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class HaE implements BurpExtension {
|
||||
@Override
|
||||
public void initialize(MontoyaApi api) {
|
||||
// 设置扩展名称
|
||||
String version = "3.2.2";
|
||||
String version = "3.3";
|
||||
api.extension().setName(String.format("HaE (%s) - Highlighter and Extractor", version));
|
||||
|
||||
// 加载扩展后输出的项目信息
|
||||
@@ -44,7 +44,7 @@ public class HaE implements BurpExtension {
|
||||
// 注册消息编辑框(用于展示数据)
|
||||
api.userInterface().registerHttpRequestEditorProvider(new RequestEditor(api, configLoader));
|
||||
api.userInterface().registerHttpResponseEditorProvider(new ResponseEditor(api, configLoader));
|
||||
api.userInterface().registerWebSocketMessageEditorProvider(new WebSocketEditor(api));
|
||||
api.userInterface().registerWebSocketMessageEditorProvider(new WebSocketEditor(api, configLoader));
|
||||
|
||||
api.extension().registerUnloadingHandler(new ExtensionUnloadingHandler() {
|
||||
@Override
|
||||
|
||||
@@ -37,26 +37,17 @@ public class Main extends JPanel {
|
||||
|
||||
// 新增Logo
|
||||
JTabbedPane HaETabbedPane = new JTabbedPane();
|
||||
HaETabbedPane.addTab("", getImageIcon(false), mainTabbedPane);
|
||||
boolean isDarkBg = isDarkBg(HaETabbedPane);
|
||||
HaETabbedPane.addTab("", getImageIcon(isDarkBg), mainTabbedPane);
|
||||
// 中文Slogan:赋能白帽,高效作战
|
||||
HaETabbedPane.addTab(" Highlighter and Extractor - Empower ethical hacker for efficient operations. ", null);
|
||||
HaETabbedPane.setEnabledAt(1, false);
|
||||
HaETabbedPane.addPropertyChangeListener("background", new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
boolean isDarkBg = isDarkBg();
|
||||
boolean isDarkBg = isDarkBg(HaETabbedPane);
|
||||
HaETabbedPane.setIconAt(0, getImageIcon(isDarkBg));
|
||||
}
|
||||
|
||||
private boolean isDarkBg() {
|
||||
Color bg = HaETabbedPane.getBackground();
|
||||
int r = bg.getRed();
|
||||
int g = bg.getGreen();
|
||||
int b = bg.getBlue();
|
||||
int avg = (r + g + b) / 3;
|
||||
|
||||
return avg < 128;
|
||||
}
|
||||
});
|
||||
|
||||
add(HaETabbedPane, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
|
||||
@@ -70,6 +61,16 @@ public class Main extends JPanel {
|
||||
mainTabbedPane.addTab("Config", new Config(api, configLoader, rules));
|
||||
}
|
||||
|
||||
private boolean isDarkBg(JTabbedPane HaETabbedPane) {
|
||||
Color bg = HaETabbedPane.getBackground();
|
||||
int r = bg.getRed();
|
||||
int g = bg.getGreen();
|
||||
int b = bg.getBlue();
|
||||
int avg = (r + g + b) / 3;
|
||||
|
||||
return avg < 128;
|
||||
}
|
||||
|
||||
private ImageIcon getImageIcon(boolean isDark) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
URL imageURL;
|
||||
|
||||
@@ -5,6 +5,7 @@ import hae.Config;
|
||||
import hae.component.board.message.MessageEntry;
|
||||
import hae.component.board.message.MessageTableModel;
|
||||
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.project.ProjectProcessor;
|
||||
@@ -46,7 +47,7 @@ public class Databoard extends JPanel {
|
||||
private final DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
|
||||
private final JComboBox hostComboBox = new JComboBox(comboBoxModel);
|
||||
|
||||
private SwingWorker<Boolean, Void> handleComboBoxWorker;
|
||||
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;
|
||||
@@ -63,7 +64,7 @@ public class Databoard extends JPanel {
|
||||
private void initComponents() {
|
||||
setLayout(new GridBagLayout());
|
||||
((GridBagLayout) getLayout()).columnWidths = new int[]{25, 0, 0, 0, 20, 0};
|
||||
((GridBagLayout) getLayout()).rowHeights = new int[]{0, 65, 20, 25, 0};
|
||||
((GridBagLayout) getLayout()).rowHeights = new int[]{0, 65, 20, 0, 0};
|
||||
((GridBagLayout) getLayout()).columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, 0.0, 1.0E-4};
|
||||
((GridBagLayout) getLayout()).rowWeights = new double[]{0.0, 1.0, 0.0, 0.0, 1.0E-4};
|
||||
|
||||
@@ -120,7 +121,7 @@ public class Databoard extends JPanel {
|
||||
add(splitPane, new GridBagConstraints(1, 1, 3, 1, 0.0, 1.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
|
||||
new Insets(0, 5, 0, 5), 0, 0));
|
||||
add(progressBar, new GridBagConstraints(1, 3, 3, 1, 1.0, 0.0,
|
||||
add(progressBar, new GridBagConstraints(1, 2, 3, 1, 1.0, 0.0,
|
||||
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
|
||||
new Insets(0, 5, 0, 5), 0, 0));
|
||||
hostComboBox.setMaximumRowCount(5);
|
||||
@@ -143,6 +144,11 @@ public class Databoard extends JPanel {
|
||||
}
|
||||
|
||||
private void setProgressBar(boolean status) {
|
||||
setProgressBar(status, progressBar, "Loading ...");
|
||||
}
|
||||
|
||||
|
||||
public static void setProgressBar(boolean status, JProgressBar progressBar, String showString) {
|
||||
progressBar.setIndeterminate(status);
|
||||
if (!status) {
|
||||
progressBar.setMaximum(100);
|
||||
@@ -150,7 +156,7 @@ public class Databoard extends JPanel {
|
||||
progressBar.setStringPainted(true);
|
||||
progressBar.setValue(progressBar.getMaximum());
|
||||
} else {
|
||||
progressBar.setString("Loading...");
|
||||
progressBar.setString(showString);
|
||||
progressBar.setStringPainted(true);
|
||||
}
|
||||
}
|
||||
@@ -198,18 +204,27 @@ public class Databoard extends JPanel {
|
||||
handleComboBoxWorker.cancel(true);
|
||||
}
|
||||
|
||||
handleComboBoxWorker = new SwingWorker<Boolean, Void>() {
|
||||
handleComboBoxWorker = new SwingWorker<Map<String, List<String>>, Void>() {
|
||||
@Override
|
||||
protected Boolean doInBackground() {
|
||||
return populateTabbedPaneByHost(selectedHost);
|
||||
protected Map<String, List<String>> doInBackground() {
|
||||
return getSelectedMapByHost(selectedHost);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
if (!isCancelled()) {
|
||||
try {
|
||||
boolean status = get();
|
||||
if (status) {
|
||||
Map<String, List<String>> selectedDataMap = get();
|
||||
if (!selectedDataMap.isEmpty()) {
|
||||
dataTabbedPane.removeAll();
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : selectedDataMap.entrySet()) {
|
||||
String tabTitle = String.format("%s (%s)", entry.getKey(), entry.getValue().size());
|
||||
Datatable datatablePanel = new Datatable(api, configLoader, entry.getKey(), entry.getValue());
|
||||
datatablePanel.setTableListener(messageTableModel);
|
||||
dataTabbedPane.addTab(tabTitle, datatablePanel);
|
||||
}
|
||||
|
||||
JSplitPane messageSplitPane = messageTableModel.getSplitPane();
|
||||
splitPane.setLeftComponent(dataTabbedPane);
|
||||
splitPane.setRightComponent(messageSplitPane);
|
||||
@@ -257,7 +272,7 @@ public class Databoard extends JPanel {
|
||||
isMatchHost = false;
|
||||
}
|
||||
|
||||
private boolean populateTabbedPaneByHost(String selectedHost) {
|
||||
private Map<String, List<String>> getSelectedMapByHost(String selectedHost) {
|
||||
ConcurrentHashMap<String, Map<String, List<String>>> dataMap = Config.globalDataMap;
|
||||
Map<String, List<String>> selectedDataMap;
|
||||
|
||||
@@ -283,20 +298,7 @@ public class Databoard extends JPanel {
|
||||
selectedDataMap = dataMap.get(selectedHost);
|
||||
}
|
||||
|
||||
if (!selectedDataMap.isEmpty()) {
|
||||
dataTabbedPane.removeAll();
|
||||
|
||||
for (Map.Entry<String, List<String>> entry : selectedDataMap.entrySet()) {
|
||||
String tabTitle = String.format("%s (%s)", entry.getKey(), entry.getValue().size());
|
||||
Datatable datatablePanel = new Datatable(api, entry.getKey(), entry.getValue());
|
||||
datatablePanel.setTableListener(messageTableModel);
|
||||
dataTabbedPane.addTab(tabTitle, datatablePanel);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return selectedDataMap;
|
||||
}
|
||||
|
||||
private void filterComboBoxList() {
|
||||
@@ -396,7 +398,8 @@ public class Databoard extends JPanel {
|
||||
List<String> taskStatusList = get();
|
||||
if (!taskStatusList.isEmpty()) {
|
||||
String exportStatusMessage = String.format("Exported File List Status:\n%s", String.join("\n", taskStatusList));
|
||||
JOptionPane.showConfirmDialog(Databoard.this, exportStatusMessage, "Info", JOptionPane.YES_OPTION);
|
||||
|
||||
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(exportStatusMessage), "Info", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
@@ -406,6 +409,16 @@ 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));
|
||||
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
private List<String> 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))
|
||||
@@ -509,7 +522,7 @@ public class Databoard extends JPanel {
|
||||
List<String> taskStatusList = get();
|
||||
if (!taskStatusList.isEmpty()) {
|
||||
String importStatusMessage = "Imported File List Status:\n" + String.join("\n", taskStatusList);
|
||||
JOptionPane.showConfirmDialog(Databoard.this, importStatusMessage, "Info", JOptionPane.YES_OPTION);
|
||||
JOptionPane.showMessageDialog(Databoard.this, generateTaskStatusPane(importStatusMessage), "Info", JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
package hae.component.board;
|
||||
|
||||
import burp.api.montoya.MontoyaApi;
|
||||
import hae.component.board.message.MessageTableModel;
|
||||
import hae.utils.UIEnhancer;
|
||||
|
||||
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.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Datatable extends JPanel {
|
||||
private final MontoyaApi api;
|
||||
private final JTable dataTable;
|
||||
private final DefaultTableModel dataTableModel;
|
||||
private final JTextField searchField;
|
||||
private final TableRowSorter<DefaultTableModel> sorter;
|
||||
private final JCheckBox searchMode = new JCheckBox("Reverse search");
|
||||
private final String tabName;
|
||||
|
||||
public Datatable(MontoyaApi api, String tabName, List<String> dataList) {
|
||||
this.api = api;
|
||||
this.tabName = tabName;
|
||||
|
||||
String[] columnNames = {"#", "Information"};
|
||||
|
||||
dataTableModel = new DefaultTableModel(columnNames, 0);
|
||||
dataTable = new JTable(dataTableModel);
|
||||
sorter = new TableRowSorter<>(dataTableModel);
|
||||
|
||||
searchField = new JTextField();
|
||||
|
||||
initComponents(dataList);
|
||||
}
|
||||
|
||||
private void initComponents(List<String> dataList) {
|
||||
// 设置ID排序
|
||||
sorter.setComparator(0, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer s1, Integer s2) {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
});
|
||||
|
||||
dataTable.setRowSorter(sorter);
|
||||
TableColumn idColumn = dataTable.getColumnModel().getColumn(0);
|
||||
idColumn.setMaxWidth(50);
|
||||
|
||||
for (String item : dataList) {
|
||||
if (!item.isEmpty()) {
|
||||
addRowToTable(new Object[]{item});
|
||||
}
|
||||
}
|
||||
|
||||
// 设置灰色默认文本
|
||||
String searchText = "Search";
|
||||
UIEnhancer.setTextFieldPlaceholder(searchField, searchText);
|
||||
|
||||
// 监听输入框内容输入、更新、删除
|
||||
searchField.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);
|
||||
|
||||
searchMode.addItemListener(e -> performSearch());
|
||||
|
||||
setLayout(new BorderLayout(0, 5));
|
||||
|
||||
JPanel optionsPanel = new JPanel();
|
||||
optionsPanel.setBorder(BorderFactory.createEmptyBorder(2, 3, 5, 5));
|
||||
optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.X_AXIS));
|
||||
|
||||
// 新增复选框要在这修改rows
|
||||
JPanel menuPanel = new JPanel(new GridLayout(1, 1));
|
||||
menuPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
menuPanel.add(searchMode);
|
||||
menu.add(menuPanel);
|
||||
|
||||
JButton settingsButton = new JButton("Settings");
|
||||
settingsButton.addActionListener(e -> {
|
||||
int x = settingsButton.getX();
|
||||
int y = settingsButton.getY() - menu.getPreferredSize().height;
|
||||
menu.show(settingsButton, x, y);
|
||||
});
|
||||
|
||||
optionsPanel.add(settingsButton);
|
||||
optionsPanel.add(Box.createHorizontalStrut(5));
|
||||
optionsPanel.add(searchField);
|
||||
|
||||
add(scrollPane, BorderLayout.CENTER);
|
||||
add(optionsPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private void addRowToTable(Object[] data) {
|
||||
int rowCount = dataTableModel.getRowCount();
|
||||
int id = rowCount > 0 ? (Integer) dataTableModel.getValueAt(rowCount - 1, 0) + 1 : 1;
|
||||
Object[] rowData = new Object[data.length + 1];
|
||||
rowData[0] = id;
|
||||
System.arraycopy(data, 0, rowData, 1, data.length);
|
||||
dataTableModel.addRow(rowData);
|
||||
}
|
||||
|
||||
private void performSearch() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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).replace("\0", "").replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", ""));
|
||||
clip.setContents(stringSelection, null);
|
||||
} else {
|
||||
super.exportToClipboard(comp, clip, action);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dataTable.setDefaultEditor(Object.class, null);
|
||||
|
||||
// 表格内容双击事件
|
||||
dataTable.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
int selectedRow = dataTable.getSelectedRow();
|
||||
if (selectedRow != -1) {
|
||||
String rowData = dataTable.getValueAt(selectedRow, 1).toString();
|
||||
messagePanel.applyMessageFilter(tabName, rowData);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return selectData.toString();
|
||||
}
|
||||
|
||||
public JTable getDataTable() {
|
||||
return this.dataTable;
|
||||
}
|
||||
}
|
||||
|
||||
157
src/main/java/hae/component/board/table/AIPower.java
Normal file
157
src/main/java/hae/component/board/table/AIPower.java
Normal file
@@ -0,0 +1,157 @@
|
||||
package hae.component.board.table;
|
||||
|
||||
import burp.api.montoya.MontoyaApi;
|
||||
import burp.api.montoya.http.RequestOptions;
|
||||
import burp.api.montoya.http.message.HttpRequestResponse;
|
||||
import burp.api.montoya.http.message.requests.HttpRequest;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import hae.Config;
|
||||
import hae.utils.ConfigLoader;
|
||||
import hae.utils.http.HttpUtils;
|
||||
import okhttp3.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AIPower {
|
||||
private final MontoyaApi api;
|
||||
private final HttpUtils httpUtils;
|
||||
private final ConfigLoader configLoader;
|
||||
private final String apiAuth;
|
||||
private final String aiModel;
|
||||
private final String aiBaseUrl;
|
||||
|
||||
public AIPower(MontoyaApi api, ConfigLoader configLoader, String aiModel, String aiBaseUrl, String[] apiKey) {
|
||||
this.api = api;
|
||||
this.configLoader = configLoader;
|
||||
this.httpUtils = new HttpUtils(api);
|
||||
this.aiModel = aiModel;
|
||||
this.aiBaseUrl = aiBaseUrl;
|
||||
|
||||
this.apiAuth = String.format("Bearer %s", apiKey[new Random().nextInt(apiKey.length)]);
|
||||
}
|
||||
|
||||
// Stream Response
|
||||
public String chatWithAPI(String ruleName, String data) {
|
||||
OkHttpClient httpClient = new OkHttpClient();
|
||||
String fileId = uploadFileToAIService(ruleName, data);
|
||||
Gson gson = new Gson();
|
||||
|
||||
if (fileId != null) {
|
||||
String chatUrl = String.format("%s/chat/completions", aiBaseUrl);
|
||||
String chatMessage = generateJsonData(configLoader.getAIPrompt(), fileId);
|
||||
Request request = new Request.Builder()
|
||||
.url(chatUrl)
|
||||
.header("Authorization", apiAuth)
|
||||
.post(RequestBody.create(MediaType.parse("application/json"), chatMessage))
|
||||
.build();
|
||||
|
||||
try (Response response = httpClient.newCall(request).execute()) {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new IOException("Unexpected code " + response);
|
||||
}
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(response.body().byteStream()));
|
||||
StringBuilder chatReturn = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("data: ") && !line.contains("[DONE]")) {
|
||||
String jsonData = line.substring(6);
|
||||
Type type = new TypeToken<Map<String, Object>>() {
|
||||
}.getType();
|
||||
Map<String, Object> map = gson.fromJson(jsonData, type);
|
||||
String content = getDeltaContent(map);
|
||||
if (content != null) {
|
||||
chatReturn.append(content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deleteFileOnAIService(fileId);
|
||||
|
||||
return chatReturn.toString();
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getDeltaContent(Map<String, Object> map) {
|
||||
List<Map<String, Map<String, String>>> choices = (List<Map<String, Map<String, String>>>) map.get("choices");
|
||||
if (choices != null && !choices.isEmpty()) {
|
||||
Map<String, String> delta = choices.get(0).get("delta");
|
||||
return delta.get("content");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String uploadFileToAIService(String ruleName, String data) {
|
||||
String uploadUrl = String.format("%s/files", aiBaseUrl);
|
||||
String uploadParam = "file";
|
||||
String filename = "hae.txt";
|
||||
String content = String.format(Config.userTextFormat, ruleName, data);
|
||||
|
||||
HttpRequest uploadFileRequest = httpUtils.generateRequestByMultipartUploadMethod(uploadUrl, uploadParam, filename, content).withAddedHeader("Authorization", apiAuth);
|
||||
|
||||
HttpRequestResponse uploadFileRequestResponse = api.http().sendRequest(uploadFileRequest, RequestOptions.requestOptions().withUpstreamTLSVerification());
|
||||
String responseBody = uploadFileRequestResponse.response().bodyToString();
|
||||
Pattern pattern = Pattern.compile("\"id\":\"(.*?)\",");
|
||||
Matcher matcher = pattern.matcher(responseBody);
|
||||
|
||||
return matcher.find() ? matcher.group(1) : null;
|
||||
}
|
||||
|
||||
private void deleteFileOnAIService(String fileId) {
|
||||
String deleteFileUrl = String.format("%s/files/%s", aiBaseUrl, fileId);
|
||||
HttpRequest deleteFileRequest = httpUtils.generateRequestByDeleteMethod(deleteFileUrl).withAddedHeader("Authorization", apiAuth);
|
||||
api.http().sendRequest(deleteFileRequest, RequestOptions.requestOptions().withUpstreamTLSVerification());
|
||||
}
|
||||
|
||||
private String getFileContentOnAiService(String fileId) {
|
||||
String getFileContentUrl = String.format("%s/files/%s/content", aiBaseUrl, fileId);
|
||||
HttpRequest getFileContentRequest = HttpRequest.httpRequestFromUrl(getFileContentUrl).withAddedHeader("Authorization", apiAuth);
|
||||
HttpRequestResponse getFileRequestResponse = api.http().sendRequest(getFileContentRequest, RequestOptions.requestOptions().withUpstreamTLSVerification());
|
||||
String responseBody = getFileRequestResponse.response().bodyToString();
|
||||
Pattern pattern = Pattern.compile("\"content\":\"(.*?)\",\"file_type\"");
|
||||
Matcher matcher = pattern.matcher(responseBody);
|
||||
|
||||
return matcher.find() ? matcher.group(1) : null;
|
||||
}
|
||||
|
||||
private String generateJsonData(String prompt, String fileId) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("model", aiModel);
|
||||
data.put("stream", true);
|
||||
data.put("messages", new Object[]{
|
||||
new HashMap<String, Object>() {{
|
||||
put("role", "system");
|
||||
put("content", prompt);
|
||||
}},
|
||||
new HashMap<String, Object>() {{
|
||||
put("role", "system");
|
||||
put("content", aiModel.equals("qwen-long") ? String.format("fileid://%s", fileId) : getFileContentOnAiService(fileId));
|
||||
}},
|
||||
new HashMap<String, Object>() {{
|
||||
put("role", "user");
|
||||
put("content", "Start");
|
||||
}}
|
||||
});
|
||||
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
return gson.toJson(data);
|
||||
}
|
||||
|
||||
}
|
||||
347
src/main/java/hae/component/board/table/Datatable.java
Normal file
347
src/main/java/hae/component/board/table/Datatable.java
Normal file
@@ -0,0 +1,347 @@
|
||||
package hae.component.board.table;
|
||||
|
||||
import burp.api.montoya.MontoyaApi;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import hae.component.board.Databoard;
|
||||
import hae.component.board.message.MessageTableModel;
|
||||
import hae.utils.ConfigLoader;
|
||||
import hae.utils.UIEnhancer;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Datatable extends JPanel {
|
||||
private final MontoyaApi api;
|
||||
private final ConfigLoader configLoader;
|
||||
private final JTable dataTable;
|
||||
private final DefaultTableModel dataTableModel;
|
||||
private final JTextField searchField;
|
||||
private final TableRowSorter<DefaultTableModel> sorter;
|
||||
private final JCheckBox searchMode = new JCheckBox("Reverse search");
|
||||
private final String tabName;
|
||||
private final JProgressBar progressBar;
|
||||
private final JPopupMenu aiEmpoweredMenu;
|
||||
private final JPanel footerPanel;
|
||||
|
||||
public Datatable(MontoyaApi api, ConfigLoader configLoader, String tabName, List<String> dataList) {
|
||||
this.api = api;
|
||||
this.configLoader = configLoader;
|
||||
this.tabName = tabName;
|
||||
this.progressBar = new JProgressBar();
|
||||
|
||||
String[] columnNames = {"#", "Information"};
|
||||
this.dataTableModel = new DefaultTableModel(columnNames, 0);
|
||||
|
||||
this.dataTable = new JTable(dataTableModel);
|
||||
this.sorter = new TableRowSorter<>(dataTableModel);
|
||||
this.searchField = new JTextField();
|
||||
this.aiEmpoweredMenu = new JPopupMenu();
|
||||
this.footerPanel = new JPanel(new BorderLayout(0, 5));
|
||||
|
||||
initComponents(dataList);
|
||||
}
|
||||
|
||||
private void initComponents(List<String> dataList) {
|
||||
progressBar.setVisible(false);
|
||||
|
||||
// 设置ID排序
|
||||
sorter.setComparator(0, new Comparator<Integer>() {
|
||||
@Override
|
||||
public int compare(Integer s1, Integer s2) {
|
||||
return s1.compareTo(s2);
|
||||
}
|
||||
});
|
||||
|
||||
dataTable.setRowSorter(sorter);
|
||||
TableColumn idColumn = dataTable.getColumnModel().getColumn(0);
|
||||
idColumn.setMaxWidth(50);
|
||||
|
||||
for (String item : dataList) {
|
||||
if (!item.isEmpty()) {
|
||||
addRowToTable(new Object[]{item});
|
||||
}
|
||||
}
|
||||
|
||||
// 设置灰色默认文本
|
||||
String searchText = "Search";
|
||||
UIEnhancer.setTextFieldPlaceholder(searchField, searchText);
|
||||
|
||||
// 监听输入框内容输入、更新、删除
|
||||
searchField.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);
|
||||
|
||||
setLayout(new BorderLayout(0, 5));
|
||||
|
||||
JPanel optionsPanel = new JPanel();
|
||||
optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.X_AXIS));
|
||||
|
||||
// Settings按钮
|
||||
JPanel settingMenuPanel = new JPanel(new GridLayout(1, 1));
|
||||
settingMenuPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
JPopupMenu settingMenu = new JPopupMenu();
|
||||
settingMenuPanel.add(searchMode);
|
||||
searchMode.addItemListener(e -> performSearch());
|
||||
settingMenu.add(settingMenuPanel);
|
||||
|
||||
JButton settingsButton = new JButton("Settings");
|
||||
setMenuShow(settingMenu, settingsButton);
|
||||
|
||||
// AI Empowered按钮
|
||||
JPanel aiEmpoweredPanel = new JPanel(new GridLayout(2, 1));
|
||||
aiEmpoweredPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
JButton empoweredByAlibabaButton = new JButton("Alibaba - QwenLong");
|
||||
empoweredByAlibabaButton.addActionListener(e -> {
|
||||
aiEmpoweredByAlibabaActionPerformed(e, tabName, getTableData(dataTable));
|
||||
});
|
||||
JButton empoweredByMoonshotButton = new JButton("Moonshot - Kimi");
|
||||
empoweredByMoonshotButton.addActionListener(e -> {
|
||||
aiEmpoweredByMoonshotActionPerformed(e, tabName, getTableData(dataTable));
|
||||
});
|
||||
aiEmpoweredPanel.add(empoweredByAlibabaButton);
|
||||
aiEmpoweredPanel.add(empoweredByMoonshotButton);
|
||||
aiEmpoweredMenu.add(aiEmpoweredPanel);
|
||||
|
||||
JButton aiEmpoweredButton = new JButton("AI Empowered");
|
||||
setMenuShow(aiEmpoweredMenu, aiEmpoweredButton);
|
||||
aiEmpoweredMenu.addPopupMenuListener(new PopupMenuListener() {
|
||||
@Override
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
|
||||
empoweredByAlibabaButton.setEnabled(!configLoader.getAlibabaAIAPIKey().isEmpty());
|
||||
empoweredByMoonshotButton.setEnabled(!configLoader.getMoonshotAIAPIKey().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
optionsPanel.add(settingsButton);
|
||||
optionsPanel.add(Box.createHorizontalStrut(5));
|
||||
optionsPanel.add(searchField);
|
||||
optionsPanel.add(Box.createHorizontalStrut(5));
|
||||
optionsPanel.add(aiEmpoweredButton);
|
||||
|
||||
footerPanel.setBorder(BorderFactory.createEmptyBorder(2, 3, 5, 3));
|
||||
footerPanel.add(optionsPanel, BorderLayout.CENTER);
|
||||
footerPanel.add(progressBar, BorderLayout.SOUTH);
|
||||
|
||||
add(scrollPane, BorderLayout.CENTER);
|
||||
add(footerPanel, BorderLayout.SOUTH);
|
||||
|
||||
setProgressBar(false);
|
||||
}
|
||||
|
||||
private void setMenuShow(JPopupMenu menu, JButton button) {
|
||||
button.addActionListener(e -> {
|
||||
Point buttonLocation = button.getLocationOnScreen();
|
||||
Dimension menuSize = menu.getPreferredSize();
|
||||
int x = buttonLocation.x + (button.getWidth() - menuSize.width) / 2;
|
||||
int y = buttonLocation.y - menuSize.height;
|
||||
menu.show(button, x - buttonLocation.x, y - buttonLocation.y);
|
||||
});
|
||||
}
|
||||
|
||||
private void setProgressBar(boolean status) {
|
||||
Databoard.setProgressBar(status, progressBar, "AI+ ...");
|
||||
}
|
||||
|
||||
private void addRowToTable(Object[] data) {
|
||||
int rowCount = dataTableModel.getRowCount();
|
||||
int id = rowCount > 0 ? (Integer) dataTableModel.getValueAt(rowCount - 1, 0) + 1 : 1;
|
||||
Object[] rowData = new Object[data.length + 1];
|
||||
rowData[0] = id;
|
||||
System.arraycopy(data, 0, rowData, 1, data.length);
|
||||
dataTableModel.addRow(rowData);
|
||||
}
|
||||
|
||||
private void aiEmpoweredByAlibabaActionPerformed(ActionEvent e, String ruleName, String data) {
|
||||
AIPower aiPower = new AIPower(api, configLoader, "qwen-long", "https://dashscope.aliyuncs.com/compatible-mode/v1", configLoader.getAlibabaAIAPIKey().split("\\|"));
|
||||
aiEmpoweredButtonAction(ruleName, data, aiPower);
|
||||
}
|
||||
|
||||
private void aiEmpoweredByMoonshotActionPerformed(ActionEvent e, String ruleName, String data) {
|
||||
AIPower aiPower = new AIPower(api, configLoader, "moonshot-v1-128k", "https://api.moonshot.cn/v1", configLoader.getMoonshotAIAPIKey().split("\\|"));
|
||||
aiEmpoweredButtonAction(ruleName, data, aiPower);
|
||||
}
|
||||
|
||||
private void aiEmpoweredButtonAction(String ruleName, String data, AIPower aiPower) {
|
||||
progressBar.setVisible(true);
|
||||
aiEmpoweredMenu.setVisible(true);
|
||||
setProgressBar(true);
|
||||
|
||||
SwingWorker<String, Void> worker = new SwingWorker<String, Void>() {
|
||||
@Override
|
||||
protected String doInBackground() throws Exception {
|
||||
return aiPower.chatWithAPI(ruleName, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
setProgressBar(false);
|
||||
|
||||
try {
|
||||
String chatReturn = get();
|
||||
if (!chatReturn.isEmpty()) {
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<Map<String, Object>>() {
|
||||
}.getType();
|
||||
Map<String, List<String>> map = gson.fromJson(chatReturn, type);
|
||||
|
||||
dataTableModel.setRowCount(0);
|
||||
for (String item : map.get("data")) {
|
||||
if (!item.isEmpty()) {
|
||||
addRowToTable(new Object[]{item});
|
||||
}
|
||||
}
|
||||
|
||||
JOptionPane.showMessageDialog(Datatable.this, "AI+ has completed the AI empowered work.", "AI+ Info", JOptionPane.INFORMATION_MESSAGE);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(Datatable.this, "AI+ returns null, please check!", "AI+ Info", JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
JOptionPane.showMessageDialog(Datatable.this, "AI+ returns error, please check!", "AI+ Info", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
};
|
||||
worker.execute();
|
||||
|
||||
aiEmpoweredMenu.setVisible(false);
|
||||
}
|
||||
|
||||
private void performSearch() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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).replace("\0", "").replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", ""));
|
||||
clip.setContents(stringSelection, null);
|
||||
} else {
|
||||
super.exportToClipboard(comp, clip, action);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dataTable.setDefaultEditor(Object.class, null);
|
||||
|
||||
// 表格内容双击事件
|
||||
dataTable.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
int selectedRow = dataTable.getSelectedRow();
|
||||
if (selectedRow != -1) {
|
||||
String rowData = dataTable.getValueAt(selectedRow, 1).toString();
|
||||
messagePanel.applyMessageFilter(tabName, rowData);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String getTableData(JTable table) {
|
||||
StringBuilder selectData = new StringBuilder();
|
||||
int rowCount = table.getRowCount();
|
||||
for (int i = 0; i < rowCount; i++) {
|
||||
selectData.append(table.getValueAt(i, 1).toString()).append("\r\n");
|
||||
}
|
||||
|
||||
if (!selectData.isEmpty()) {
|
||||
selectData.delete(selectData.length() - 2, selectData.length());
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return selectData.toString();
|
||||
}
|
||||
|
||||
public String getSelectedDataAtTable(JTable table) {
|
||||
int[] selectRows = table.getSelectedRows();
|
||||
StringBuilder selectData = new StringBuilder();
|
||||
|
||||
for (int row : selectRows) {
|
||||
selectData.append(table.getValueAt(row, 1).toString()).append("\r\n");
|
||||
}
|
||||
|
||||
if (!selectData.isEmpty()) {
|
||||
selectData.delete(selectData.length() - 2, selectData.length());
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
||||
return selectData.toString();
|
||||
}
|
||||
|
||||
|
||||
public JTable getDataTable() {
|
||||
return this.dataTable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ import hae.utils.UIEnhancer;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
@@ -14,12 +17,11 @@ import java.awt.*;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class Config extends JPanel {
|
||||
private final MontoyaApi api;
|
||||
@@ -27,22 +29,22 @@ public class Config extends JPanel {
|
||||
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));
|
||||
|
||||
@@ -62,6 +64,153 @@ public class Config extends JPanel {
|
||||
reloadButton.addActionListener(this::reloadActionPerformed);
|
||||
updateButton.addActionListener(this::onlineUpdateActionPerformed);
|
||||
|
||||
constraints.gridx = 1;
|
||||
JTabbedPane configTabbedPanel = new JTabbedPane();
|
||||
|
||||
String[] settingMode = new String[]{"Exclude suffix", "Block host"};
|
||||
JPanel settingPanel = createConfigTablePanel(settingMode, "Setting");
|
||||
JPanel scopePanel = getScopePanel();
|
||||
JScrollPane scopeScrollPane = new JScrollPane(scopePanel);
|
||||
scopeScrollPane.setBorder(new TitledBorder("Scope"));
|
||||
settingPanel.add(scopeScrollPane, BorderLayout.NORTH);
|
||||
configTabbedPanel.add("Setting", settingPanel);
|
||||
|
||||
String[] aiMode = new String[]{"Alibaba", "Moonshot"};
|
||||
JPanel aiPanel = createConfigTablePanel(aiMode, "AI+");
|
||||
JTextArea promptTextArea = new JTextArea();
|
||||
promptTextArea.setLineWrap(true);
|
||||
promptTextArea.getDocument().addDocumentListener(new DocumentListener() {
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent e) {
|
||||
onTextChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent e) {
|
||||
onTextChange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent e) {
|
||||
onTextChange();
|
||||
}
|
||||
|
||||
private void onTextChange() {
|
||||
String promptText = promptTextArea.getText();
|
||||
configLoader.setAIPrompt(promptText);
|
||||
}
|
||||
});
|
||||
promptTextArea.setText(configLoader.getAIPrompt());
|
||||
JScrollPane promptScrollPane = new JScrollPane(promptTextArea);
|
||||
promptScrollPane.setBorder(new TitledBorder("Prompt"));
|
||||
promptScrollPane.setPreferredSize(new Dimension(0, 100));
|
||||
aiPanel.add(promptScrollPane, BorderLayout.NORTH);
|
||||
configTabbedPanel.add("AI+", aiPanel);
|
||||
add(ruleInfoPanel, BorderLayout.NORTH);
|
||||
add(configTabbedPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private JPanel getScopePanel() {
|
||||
JPanel scopePanel = new JPanel();
|
||||
scopePanel.setLayout(new BoxLayout(scopePanel, BoxLayout.X_AXIS));
|
||||
|
||||
String[] scopeInit = hae.Config.scopeOptions.split("\\|");
|
||||
String[] scopeMode = configLoader.getScope().split("\\|");
|
||||
for (String scope : scopeInit) {
|
||||
JCheckBox checkBox = new JCheckBox(scope);
|
||||
scopePanel.add(checkBox);
|
||||
for (String mode : scopeMode) {
|
||||
if (scope.equals(mode)) {
|
||||
checkBox.setSelected(true);
|
||||
}
|
||||
}
|
||||
|
||||
checkBox.addActionListener(e -> updateScope(checkBox));
|
||||
}
|
||||
return scopePanel;
|
||||
}
|
||||
|
||||
private TableModelListener craeteSettingTableModelListener(JComboBox<String> setTypeComboBox, DefaultTableModel model) {
|
||||
return new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
String values = getFirstColumnDataAsString(model);
|
||||
|
||||
if (selected.equals("Exclude suffix")) {
|
||||
if (!values.equals(configLoader.getExcludeSuffix()) && !values.isEmpty()) {
|
||||
configLoader.setExcludeSuffix(values);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.equals("Block host")) {
|
||||
if (!values.equals(configLoader.getBlockHost()) && !values.isEmpty()) {
|
||||
configLoader.setBlockHost(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ActionListener createSettingActionListener(JComboBox<String> setTypeComboBox, DefaultTableModel model) {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
model.setRowCount(0);
|
||||
|
||||
if (selected.equals("Exclude suffix")) {
|
||||
addDataToTable(configLoader.getExcludeSuffix().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
|
||||
if (selected.equals("Block host")) {
|
||||
addDataToTable(configLoader.getBlockHost().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private TableModelListener craeteAITableModelListener(JComboBox<String> setTypeComboBox, DefaultTableModel model) {
|
||||
return new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
String values = getFirstColumnDataAsString(model);
|
||||
|
||||
if (selected.equals("Alibaba")) {
|
||||
if (!values.equals(configLoader.getAlibabaAIAPIKey()) && !values.isEmpty()) {
|
||||
configLoader.setAlibabaAIAPIKey(values);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.equals("Moonshot")) {
|
||||
if (!values.equals(configLoader.getMoonshotAIAPIKey()) && !values.isEmpty()) {
|
||||
configLoader.setMoonshotAIAPIKey(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ActionListener createAIActionListener(JComboBox<String> setTypeComboBox, DefaultTableModel model) {
|
||||
return new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
model.setRowCount(0);
|
||||
|
||||
if (selected.equals("Alibaba")) {
|
||||
addDataToTable(configLoader.getAlibabaAIAPIKey().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
|
||||
if (selected.equals("Moonshot")) {
|
||||
addDataToTable(configLoader.getMoonshotAIAPIKey().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private JPanel createConfigTablePanel(String[] mode, String type) {
|
||||
JPanel settingPanel = new JPanel(new BorderLayout());
|
||||
DefaultTableModel model = new DefaultTableModel();
|
||||
|
||||
@@ -80,48 +229,19 @@ public class Config extends JPanel {
|
||||
JPanel inputPanelB = new JPanel(new BorderLayout());
|
||||
inputPanelB.setBorder(new EmptyBorder(0, 0, 3, 0));
|
||||
|
||||
constraints.gridx = 1;
|
||||
JButton addButton = new JButton("Add");
|
||||
JButton removeButton = new JButton("Remove");
|
||||
JButton pasteButton = new JButton("Paste");
|
||||
JButton clearButton = new JButton("Clear");
|
||||
|
||||
JComboBox<String> setTypeComboBox = new JComboBox<>();
|
||||
String[] mode = new String[]{"Exclude suffix", "Block host"};
|
||||
setTypeComboBox.setModel(new DefaultComboBoxModel<>(mode));
|
||||
setTypeComboBox.addActionListener(e -> {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
model.setRowCount(0);
|
||||
|
||||
if (selected.equals("Exclude suffix")) {
|
||||
addDataToTable(configLoader.getExcludeSuffix().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
setTypeComboBox.addActionListener(type.equals("AI+") ? createAIActionListener(setTypeComboBox, model) : createSettingActionListener(setTypeComboBox, model));
|
||||
|
||||
if (selected.equals("Block host")) {
|
||||
addDataToTable(configLoader.getBlockHost().replaceAll("\\|", "\r\n"), model);
|
||||
}
|
||||
});
|
||||
setTypeComboBox.setSelectedItem("Exclude suffix");
|
||||
setTypeComboBox.setSelectedItem(mode[0]);
|
||||
|
||||
model.addTableModelListener(new TableModelListener() {
|
||||
@Override
|
||||
public void tableChanged(TableModelEvent e) {
|
||||
String selected = (String) setTypeComboBox.getSelectedItem();
|
||||
String values = getFirstColumnDataAsString(model);
|
||||
|
||||
if (selected.equals("Exclude suffix")) {
|
||||
if (!values.equals(configLoader.getExcludeSuffix()) && !values.isEmpty()) {
|
||||
configLoader.setExcludeSuffix(values);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected.equals("Block host")) {
|
||||
if (!values.equals(configLoader.getBlockHost()) && !values.isEmpty()) {
|
||||
configLoader.setBlockHost(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
model.addTableModelListener(type.equals("AI+") ? craeteAITableModelListener(setTypeComboBox, model) : craeteSettingTableModelListener(setTypeComboBox, model));
|
||||
|
||||
constraints.insets = new Insets(0, 0, 3, 0);
|
||||
constraints.gridy = 0;
|
||||
@@ -146,13 +266,13 @@ public class Config extends JPanel {
|
||||
settingPanel.add(inputPanel, BorderLayout.CENTER);
|
||||
|
||||
|
||||
addButton.addActionListener(e -> addActionPerformedAction(e, model));
|
||||
addButton.addActionListener(e -> addActionPerformed(e, model));
|
||||
|
||||
addTextField.addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
addActionPerformedAction(null, model);
|
||||
addActionPerformed(null, model);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -178,16 +298,14 @@ public class Config extends JPanel {
|
||||
|
||||
clearButton.addActionListener(e -> model.setRowCount(0));
|
||||
|
||||
JPanel settingMainPanel = new JPanel(new BorderLayout());
|
||||
JLabel settingLabel = new JLabel("Setting:");
|
||||
JPanel settingLabelPanel = new JPanel(new BorderLayout());
|
||||
settingLabelPanel.add(settingLabel, BorderLayout.WEST);
|
||||
settingMainPanel.setBorder(new EmptyBorder(0, 15, 10, 15));
|
||||
settingMainPanel.add(settingLabelPanel, BorderLayout.NORTH);
|
||||
settingMainPanel.add(settingPanel, BorderLayout.CENTER);
|
||||
|
||||
add(ruleInfoPanel, BorderLayout.NORTH);
|
||||
add(settingMainPanel, BorderLayout.CENTER);
|
||||
JPanel settingMainPanel = new JPanel(new BorderLayout());
|
||||
settingMainPanel.setBorder(new EmptyBorder(5, 15, 10, 15));
|
||||
JScrollPane settingScroller = new JScrollPane(settingPanel);
|
||||
settingScroller.setBorder(new TitledBorder(type.equals("AI+") ? "API Key" : "Setting"));
|
||||
settingMainPanel.add(settingScroller, BorderLayout.CENTER);
|
||||
|
||||
return settingMainPanel;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,7 +357,22 @@ public class Config extends JPanel {
|
||||
}
|
||||
}
|
||||
|
||||
private void addActionPerformedAction(ActionEvent e, DefaultTableModel model) {
|
||||
public void updateScope(JCheckBox checkBox) {
|
||||
String boxText = checkBox.getText();
|
||||
boolean selected = checkBox.isSelected();
|
||||
|
||||
Set<String> HaEScope = new HashSet<>(Arrays.asList(configLoader.getScope().split("\\|")));
|
||||
|
||||
if (selected) {
|
||||
HaEScope.add(boxText);
|
||||
} else {
|
||||
HaEScope.remove(boxText);
|
||||
}
|
||||
|
||||
configLoader.setScope(String.join("|", HaEScope));
|
||||
}
|
||||
|
||||
private void addActionPerformed(ActionEvent e, DefaultTableModel model) {
|
||||
String addTextFieldText = addTextField.getText();
|
||||
if (!addTextFieldText.equals(defaultText)) {
|
||||
addDataToTable(addTextFieldText, model);
|
||||
|
||||
@@ -9,7 +9,7 @@ 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.table.Datatable;
|
||||
import hae.instances.http.utils.MessageProcessor;
|
||||
import hae.utils.ConfigLoader;
|
||||
import hae.utils.string.StringProcessor;
|
||||
@@ -59,7 +59,7 @@ public class RequestEditor implements HttpRequestEditorProvider {
|
||||
@Override
|
||||
public void setRequestResponse(HttpRequestResponse requestResponse) {
|
||||
this.requestResponse = requestResponse;
|
||||
generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList);
|
||||
generateTabbedPaneFromResultMap(api, configLoader, jTabbedPane, this.dataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,7 +73,10 @@ public class RequestEditor implements HttpRequestEditorProvider {
|
||||
boolean isBlockHost = isBlockHost(hostList, host);
|
||||
|
||||
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
|
||||
boolean matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost;
|
||||
String toolType = creationContext.toolSource().toolType().toolName();
|
||||
boolean isToolScope = configLoader.getScope().contains(toolType);
|
||||
|
||||
boolean matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost || !isToolScope;
|
||||
|
||||
if (!matches && !request.bodyToString().equals("Loading...")) {
|
||||
this.dataList = messageProcessor.processRequest("", request, false);
|
||||
@@ -139,14 +142,14 @@ public class RequestEditor implements HttpRequestEditorProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void generateTabbedPaneFromResultMap(MontoyaApi api, JTabbedPane tabbedPane, List<Map<String, String>> result) {
|
||||
public static void generateTabbedPaneFromResultMap(MontoyaApi api, ConfigLoader configLoader, JTabbedPane tabbedPane, List<Map<String, String>> result) {
|
||||
tabbedPane.removeAll();
|
||||
if (result != null && !result.isEmpty()) {
|
||||
Map<String, String> dataMap = result.get(0);
|
||||
if (dataMap != null && !dataMap.isEmpty()) {
|
||||
dataMap.keySet().forEach(i -> {
|
||||
String[] extractData = dataMap.get(i).split("\n");
|
||||
Datatable dataPanel = new Datatable(api, i, Arrays.asList(extractData));
|
||||
Datatable dataPanel = new Datatable(api, configLoader, i, Arrays.asList(extractData));
|
||||
tabbedPane.addTab(i, dataPanel);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import burp.api.montoya.ui.Selection;
|
||||
import burp.api.montoya.ui.editor.extension.EditorCreationContext;
|
||||
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpResponseEditor;
|
||||
import burp.api.montoya.ui.editor.extension.HttpResponseEditorProvider;
|
||||
import hae.component.board.Datatable;
|
||||
import hae.component.board.table.Datatable;
|
||||
import hae.instances.http.utils.MessageProcessor;
|
||||
import hae.utils.ConfigLoader;
|
||||
import hae.utils.string.StringProcessor;
|
||||
@@ -60,7 +60,7 @@ public class ResponseEditor implements HttpResponseEditorProvider {
|
||||
@Override
|
||||
public void setRequestResponse(HttpRequestResponse requestResponse) {
|
||||
this.requestResponse = requestResponse;
|
||||
RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList);
|
||||
RequestEditor.generateTabbedPaneFromResultMap(api, configLoader, jTabbedPane, this.dataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +79,10 @@ public class ResponseEditor implements HttpResponseEditorProvider {
|
||||
boolean isBlockHost = RequestEditor.isBlockHost(hostList, host);
|
||||
|
||||
List<String> suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|"));
|
||||
matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost;
|
||||
String toolType = creationContext.toolSource().toolType().toolName();
|
||||
boolean isToolScope = configLoader.getScope().contains(toolType);
|
||||
|
||||
matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost || !isToolScope;
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ import burp.api.montoya.ui.contextmenu.WebSocketMessage;
|
||||
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.table.Datatable;
|
||||
import hae.instances.http.utils.MessageProcessor;
|
||||
import hae.utils.ConfigLoader;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -18,18 +19,21 @@ import java.util.Map;
|
||||
|
||||
public class WebSocketEditor implements WebSocketMessageEditorProvider {
|
||||
private final MontoyaApi api;
|
||||
private final ConfigLoader configLoader;
|
||||
|
||||
public WebSocketEditor(MontoyaApi api) {
|
||||
public WebSocketEditor(MontoyaApi api, ConfigLoader configLoader) {
|
||||
this.api = api;
|
||||
this.configLoader = configLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionProvidedWebSocketMessageEditor provideMessageEditor(EditorCreationContext editorCreationContext) {
|
||||
return new Editor(api, editorCreationContext);
|
||||
return new Editor(api, configLoader, editorCreationContext);
|
||||
}
|
||||
|
||||
private static class Editor implements ExtensionProvidedWebSocketMessageEditor {
|
||||
private final MontoyaApi api;
|
||||
private final ConfigLoader configLoader;
|
||||
private final EditorCreationContext creationContext;
|
||||
private final MessageProcessor messageProcessor;
|
||||
private ByteArray message;
|
||||
@@ -37,8 +41,9 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider {
|
||||
|
||||
private final JTabbedPane jTabbedPane = new JTabbedPane();
|
||||
|
||||
public Editor(MontoyaApi api, EditorCreationContext creationContext) {
|
||||
public Editor(MontoyaApi api, ConfigLoader configLoader, EditorCreationContext creationContext) {
|
||||
this.api = api;
|
||||
this.configLoader = configLoader;
|
||||
this.creationContext = creationContext;
|
||||
this.messageProcessor = new MessageProcessor(api);
|
||||
}
|
||||
@@ -51,7 +56,7 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider {
|
||||
@Override
|
||||
public void setMessage(WebSocketMessage webSocketMessage) {
|
||||
this.message = webSocketMessage.payload();
|
||||
RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList);
|
||||
RequestEditor.generateTabbedPaneFromResultMap(api, configLoader, jTabbedPane, this.dataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,14 +48,16 @@ public class HttpMessageHandler implements HttpHandler {
|
||||
|
||||
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);
|
||||
matches.set(suffixList.contains(httpRequestToBeSent.fileExtension().toLowerCase()) || isBlockHost || !isToolScope);
|
||||
|
||||
if (!matches.get()) {
|
||||
List<Map<String, String>> result = messageProcessor.processRequest(host.get(), httpRequestToBeSent, true);
|
||||
|
||||
@@ -134,40 +134,80 @@ public class ConfigLoader {
|
||||
return rules;
|
||||
}
|
||||
|
||||
public String getAlibabaAIAPIKey() {
|
||||
return getValueFromConfig("AlibabaAIAPIKey", "");
|
||||
}
|
||||
|
||||
public String getMoonshotAIAPIKey() {
|
||||
return getValueFromConfig("MoonshotAIAPIKey", "");
|
||||
}
|
||||
|
||||
public String getAIPrompt() {
|
||||
return getValueFromConfig("AIPrompt", Config.prompt);
|
||||
}
|
||||
|
||||
public String getBlockHost() {
|
||||
File yamlSetting = new File(configFilePath);
|
||||
if (!yamlSetting.exists() || !yamlSetting.isFile()) {
|
||||
return Config.host;
|
||||
}
|
||||
|
||||
try (InputStream inorder = Files.newInputStream(Paths.get(configFilePath))) {
|
||||
Map<String, Object> r = new Yaml().load(inorder);
|
||||
|
||||
if (r.containsKey("blockHost")) {
|
||||
return r.get("blockHost").toString();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return Config.host;
|
||||
return getValueFromConfig("blockHost", Config.host);
|
||||
}
|
||||
|
||||
public String getExcludeSuffix() {
|
||||
return getValueFromConfig("excludeSuffix", Config.suffix);
|
||||
}
|
||||
|
||||
public String getScope() {
|
||||
return getValueFromConfig("HaEScope", Config.scopeOptions);
|
||||
}
|
||||
|
||||
private String getValueFromConfig(String name, String value) {
|
||||
File yamlSetting = new File(configFilePath);
|
||||
if (!yamlSetting.exists() || !yamlSetting.isFile()) {
|
||||
return Config.suffix;
|
||||
return value;
|
||||
}
|
||||
|
||||
try (InputStream inorder = Files.newInputStream(Paths.get(configFilePath))) {
|
||||
Map<String, Object> r = new Yaml().load(inorder);
|
||||
|
||||
if (r.containsKey("excludeSuffix")) {
|
||||
return r.get("excludeSuffix").toString();
|
||||
if (r.containsKey(name)) {
|
||||
return r.get(name).toString();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return Config.suffix;
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setAlibabaAIAPIKey(String apiKey) {
|
||||
setValueToConfig("AlibabaAIAPIKey", apiKey);
|
||||
}
|
||||
|
||||
public void setMoonshotAIAPIKey(String apiKey) {
|
||||
setValueToConfig("MoonshotAIAPIKey", apiKey);
|
||||
}
|
||||
|
||||
public void setAIPrompt(String prompt) {
|
||||
setValueToConfig("AIPrompt", prompt);
|
||||
}
|
||||
|
||||
public void setExcludeSuffix(String excludeSuffix) {
|
||||
setValueToConfig("excludeSuffix", excludeSuffix);
|
||||
}
|
||||
|
||||
public void setBlockHost(String blockHost) {
|
||||
setValueToConfig("blockHost", blockHost);
|
||||
}
|
||||
|
||||
public void setScope(String scope) {
|
||||
setValueToConfig("HaEScope", scope);
|
||||
}
|
||||
|
||||
private void setValueToConfig(String name, String value) {
|
||||
Map<String, Object> currentConfig = loadCurrentConfig();
|
||||
currentConfig.put(name, value);
|
||||
|
||||
try (Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8)) {
|
||||
yaml.dump(currentConfig, ws);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> loadCurrentConfig() {
|
||||
@@ -183,26 +223,6 @@ public class ConfigLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public void setExcludeSuffix(String excludeSuffix) {
|
||||
Map<String, Object> currentConfig = loadCurrentConfig();
|
||||
currentConfig.put("excludeSuffix", excludeSuffix); // 更新配置
|
||||
|
||||
try (Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8)) {
|
||||
yaml.dump(currentConfig, ws);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlockHost(String blockHost) {
|
||||
Map<String, Object> currentConfig = loadCurrentConfig();
|
||||
currentConfig.put("blockHost", blockHost); // 更新配置
|
||||
|
||||
try (Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8)) {
|
||||
yaml.dump(currentConfig, ws);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void initRulesByRes() {
|
||||
boolean isCopySuccess = copyRulesToFile(this.rulesFilePath);
|
||||
if (!isCopySuccess) {
|
||||
|
||||
42
src/main/java/hae/utils/http/HttpUtils.java
Normal file
42
src/main/java/hae/utils/http/HttpUtils.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package hae.utils.http;
|
||||
|
||||
import burp.api.montoya.MontoyaApi;
|
||||
import burp.api.montoya.http.HttpService;
|
||||
import burp.api.montoya.http.message.requests.HttpRequest;
|
||||
import burp.api.montoya.http.message.requests.HttpTransformation;
|
||||
import burp.api.montoya.utilities.RandomUtils;
|
||||
|
||||
public class HttpUtils {
|
||||
private final MontoyaApi api;
|
||||
|
||||
public HttpUtils(MontoyaApi api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
public HttpRequest generateRequestByMultipartUploadMethod(String url, String name, String filename, String content) {
|
||||
HttpRequest baseRequest = HttpRequest.httpRequestFromUrl(url).withTransformationApplied(HttpTransformation.TOGGLE_METHOD);
|
||||
|
||||
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");
|
||||
|
||||
baseRequest = baseRequest.withUpdatedHeader("Content-Type", "multipart/form-data; boundary=" + boundary).withBody(newBody.toString());
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -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))([\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
|
||||
|
||||
Reference in New Issue
Block a user