diff --git a/src/main/java/hae/Config.java b/src/main/java/hae/Config.java index e5e7c1b..b255169 100644 --- a/src/main/java/hae/Config.java +++ b/src/main/java/hae/Config.java @@ -8,6 +8,8 @@ import java.util.concurrent.ConcurrentHashMap; public class Config { public static String suffix = "3g2|3gp|7z|aac|abw|aif|aifc|aiff|apk|arc|au|avi|azw|bat|bin|bmp|bz|bz2|cmd|cmx|cod|com|csh|css|csv|dll|doc|docx|ear|eot|epub|exe|flac|flv|gif|gz|ico|ics|ief|jar|jfif|jpe|jpeg|jpg|less|m3u|mid|midi|mjs|mkv|mov|mp2|mp3|mp4|mpa|mpe|mpeg|mpg|mpkg|mpp|mpv2|odp|ods|odt|oga|ogg|ogv|ogx|otf|pbm|pdf|pgm|png|pnm|ppm|ppt|pptx|ra|ram|rar|ras|rgb|rmi|rtf|scss|sh|snd|svg|swf|tar|tif|tiff|ttf|vsd|war|wav|weba|webm|webp|wmv|woff|woff2|xbm|xls|xlsx|xpm|xul|xwd|zip"; + public static String host = "gh0st.cn"; + public static String[] scope = new String[]{ "any", "any header", diff --git a/src/main/java/hae/HaE.java b/src/main/java/hae/HaE.java index 3c5e534..d8cae24 100644 --- a/src/main/java/hae/HaE.java +++ b/src/main/java/hae/HaE.java @@ -16,7 +16,7 @@ public class HaE implements BurpExtension { @Override public void initialize(MontoyaApi api) { // 设置扩展名称 - String version = "3.0.2"; + String version = "3.1"; api.extension().setName(String.format("HaE (%s) - Highlighter and Extractor", version)); // 加载扩展后输出的项目信息 @@ -34,14 +34,14 @@ public class HaE implements BurpExtension { api.userInterface().registerSuiteTab("HaE", new Main(api, configLoader, messageTableModel)); // 注册HTTP处理器 - api.http().registerHttpHandler(new HttpMessageHandler(api, messageTableModel)); + api.http().registerHttpHandler(new HttpMessageHandler(api, configLoader, messageTableModel)); // 注册WebSocket处理器 api.proxy().registerWebSocketCreationHandler(proxyWebSocketCreation -> proxyWebSocketCreation.proxyWebSocket().registerProxyMessageHandler(new WebSocketMessageHandler(api))); // 注册消息编辑框(用于展示数据) - api.userInterface().registerHttpRequestEditorProvider(new RequestEditor(api)); - api.userInterface().registerHttpResponseEditorProvider(new ResponseEditor(api)); + api.userInterface().registerHttpRequestEditorProvider(new RequestEditor(api, configLoader)); + api.userInterface().registerHttpResponseEditorProvider(new ResponseEditor(api, configLoader)); api.userInterface().registerWebSocketMessageEditorProvider(new WebSocketEditor(api)); } } diff --git a/src/main/java/hae/cache/CachePool.java b/src/main/java/hae/cache/CachePool.java index c071c2c..eeacc5d 100644 --- a/src/main/java/hae/cache/CachePool.java +++ b/src/main/java/hae/cache/CachePool.java @@ -1,20 +1,34 @@ package hae.cache; -import java.util.HashMap; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; + import java.util.Map; +import java.util.concurrent.TimeUnit; public class CachePool { - private static final Map>> cache = new HashMap<>(); + private static final int MAX_SIZE = 100000; + private static final int EXPIRE_DURATION = 5; - public static void addToCache(String key, Map> value) { + private static final Cache>> cache = + Caffeine.newBuilder() + .maximumSize(MAX_SIZE) + .expireAfterWrite(EXPIRE_DURATION, TimeUnit.HOURS) + .build(); + + public static void put(String key, Map> value) { cache.put(key, value); } - public static Map> getFromCache(String key) { - return cache.get(key); + public static Map> get(String key) { + return cache.getIfPresent(key); } - public static void removeFromCache(String key) { - cache.remove(key); + public static void remove(String key) { + cache.invalidate(key); + } + + public static void clear() { + cache.invalidateAll(); } } \ No newline at end of file diff --git a/src/main/java/hae/component/Main.java b/src/main/java/hae/component/Main.java index 03e0142..43e019a 100644 --- a/src/main/java/hae/component/Main.java +++ b/src/main/java/hae/component/Main.java @@ -66,17 +66,17 @@ public class Main extends JPanel { // 依次添加Rules、Config、Databoard Rules rules = new Rules(api, configLoader); mainTabbedPane.addTab("Rules", rules); - mainTabbedPane.addTab("Config", new Config(api, configLoader, rules)); mainTabbedPane.addTab("Databoard", new Databoard(api, configLoader, messageTableModel)); + mainTabbedPane.addTab("Config", new Config(api, configLoader, rules)); } private ImageIcon getImageIcon(boolean isDark) { ClassLoader classLoader = getClass().getClassLoader(); URL imageURL; if (isDark) { - imageURL = classLoader.getResource("logo.png"); + imageURL = classLoader.getResource("logo/logo.png"); } else { - imageURL = classLoader.getResource("logo_black.png"); + imageURL = classLoader.getResource("logo/logo_black.png"); } ImageIcon originalIcon = new ImageIcon(imageURL); Image originalImage = originalIcon.getImage(); diff --git a/src/main/java/hae/component/board/Databoard.java b/src/main/java/hae/component/board/Databoard.java index 370bfe3..004fd5a 100644 --- a/src/main/java/hae/component/board/Databoard.java +++ b/src/main/java/hae/component/board/Databoard.java @@ -250,12 +250,18 @@ public class Databoard extends JPanel { String cleanedText = StringProcessor.replaceFirstOccurrence(filterText, "*.", ""); - if (cleanedText.contains("*")) { - cleanedText = ""; - } + RowFilter rowFilter = new RowFilter() { + public boolean include(Entry entry) { + if (cleanedText.equals("*")) { + return true; + } else { + String host = StringProcessor.getHostByUrl((String) entry.getValue(1)); + return StringProcessor.matchFromEnd(host, cleanedText); + } + } + }; - RowFilter filter = RowFilter.regexFilter(cleanedText, 1); - sorter.setRowFilter(filter); + sorter.setRowFilter(rowFilter); messageTableModel.applyHostFilter(filterText); } diff --git a/src/main/java/hae/component/board/Datatable.java b/src/main/java/hae/component/board/Datatable.java index 0f60cb7..621eb35 100644 --- a/src/main/java/hae/component/board/Datatable.java +++ b/src/main/java/hae/component/board/Datatable.java @@ -2,8 +2,7 @@ package hae.component.board; import burp.api.montoya.MontoyaApi; import hae.component.board.message.MessageTableModel; -import jregex.Pattern; -import jregex.REFlags; +import hae.utils.ui.UIEnhancer; import javax.swing.*; import javax.swing.event.DocumentEvent; @@ -14,12 +13,11 @@ import javax.swing.table.TableRowSorter; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; 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; @@ -66,7 +64,7 @@ public class Datatable extends JPanel { // 设置灰色默认文本 String searchText = "Search"; - addPlaceholder(searchField, searchText); + UIEnhancer.setTextFieldPlaceholder(searchField, searchText); // 监听输入框内容输入、更新、删除 searchField.getDocument().addDocumentListener(new DocumentListener() { @@ -121,28 +119,6 @@ public class Datatable extends JPanel { add(optionsPanel, BorderLayout.SOUTH); } - public static void addPlaceholder(JTextField textField, String placeholderText) { - textField.setForeground(Color.GRAY); - textField.setText(placeholderText); - textField.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - if (textField.getText().equals(placeholderText)) { - textField.setText(""); - textField.setForeground(Color.BLACK); - } - } - - @Override - public void focusLost(FocusEvent e) { - if (textField.getText().isEmpty()) { - textField.setForeground(Color.GRAY); - textField.setText(placeholderText); - } - } - }); - } - private void addRowToTable(Object[] data) { int rowCount = dataTableModel.getRowCount(); int id = rowCount > 0 ? (Integer) dataTableModel.getValueAt(rowCount - 1, 0) + 1 : 1; @@ -159,7 +135,7 @@ public class Datatable extends JPanel { String searchFieldTextText = searchField.getText(); Pattern pattern = null; try { - pattern = new Pattern(searchFieldTextText, REFlags.IGNORE_CASE); + pattern = Pattern.compile(searchFieldTextText, Pattern.CASE_INSENSITIVE); } catch (Exception ignored) { } diff --git a/src/main/java/hae/component/board/message/MessageTableModel.java b/src/main/java/hae/component/board/message/MessageTableModel.java index b2559a5..03adb0e 100644 --- a/src/main/java/hae/component/board/message/MessageTableModel.java +++ b/src/main/java/hae/component/board/message/MessageTableModel.java @@ -290,7 +290,7 @@ public class MessageTableModel extends AbstractTableModel { private Map> getCacheData(byte[] content) { String hashIndex = HashCalculator.calculateHash(content); - return CachePool.getFromCache(hashIndex); + return CachePool.get(hashIndex); } private boolean areMapsEqual(Map> map1, Map> map2) { @@ -396,8 +396,8 @@ public class MessageTableModel extends AbstractTableModel { public class MessageTable extends JTable { private MessageEntry MessageEntry; private SwingWorker currentWorker; - // 设置响应报文返回的最大长度为3MB - private final int MAX_LENGTH = 3145728; + // 设置响应报文返回的最大长度 + private final int MAX_LENGTH = 5242880; private int lastSelectedIndex = -1; private final HttpRequestEditor requestEditor; private final HttpResponseEditor responseEditor; diff --git a/src/main/java/hae/component/config/Config.java b/src/main/java/hae/component/config/Config.java index bf889d8..f4bae28 100644 --- a/src/main/java/hae/component/config/Config.java +++ b/src/main/java/hae/component/config/Config.java @@ -3,10 +3,21 @@ package hae.component.config; import burp.api.montoya.MontoyaApi; import hae.component.rule.Rules; import hae.utils.config.ConfigLoader; +import hae.utils.ui.UIEnhancer; import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableModel; import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; public class Config extends JPanel { private final MontoyaApi api; @@ -22,67 +33,214 @@ public class Config extends JPanel { } private void initComponents() { - setLayout(new GridBagLayout()); - ((GridBagLayout) getLayout()).columnWidths = new int[]{0, 0, 0, 0, 0}; - ((GridBagLayout) getLayout()).rowHeights = new int[]{0, 0, 0}; - ((GridBagLayout) getLayout()).columnWeights = new double[]{0.0, 1.0, 0.0, 0.0, 1.0E-4}; - ((GridBagLayout) getLayout()).rowWeights = new double[]{0.0, 0.0, 1.0E-4}; + setLayout(new BorderLayout()); - JLabel rulesFilePathLabel = new JLabel("Rules Path:"); - JTextField rulesFilePathTextField = new JTextField(); - JButton onlineUpdateButton = new JButton("Update"); - JLabel excludeSuffixLabel = new JLabel("Exclude Suffix:"); - JTextField excludeSuffixTextField = new JTextField(); - JButton excludeSuffixSaveButton = new JButton("Save"); + GridBagConstraints constraints = new GridBagConstraints(); + constraints.weightx = 1.0; + constraints.fill = GridBagConstraints.HORIZONTAL; + + JPanel ruleInfoPanel = new JPanel(new GridBagLayout()); + ruleInfoPanel.setBorder(new EmptyBorder(5, 5, 5, 5)); + + JLabel ruleLabel = new JLabel("Path:"); + JTextField pathTextField = new JTextField(); + pathTextField.setEditable(false); + pathTextField.setText(configLoader.getRulesFilePath()); JButton reloadButton = new JButton("Reload"); + JButton updateButton = new JButton("Update"); + ruleInfoPanel.add(ruleLabel); + ruleInfoPanel.add(pathTextField, constraints); + ruleInfoPanel.add(Box.createHorizontalStrut(5)); + ruleInfoPanel.add(reloadButton); + ruleInfoPanel.add(Box.createHorizontalStrut(5)); + ruleInfoPanel.add(updateButton); - rulesFilePathTextField.setEditable(false); - - onlineUpdateButton.addActionListener(this::onlineUpdateActionPerformed); - excludeSuffixSaveButton.addActionListener(e -> excludeSuffixSaveActionPerformed(e, excludeSuffixTextField.getText())); reloadButton.addActionListener(this::reloadActionPerformed); + updateButton.addActionListener(this::onlineUpdateActionPerformed); - rulesFilePathTextField.setText(configLoader.getRulesFilePath()); - excludeSuffixTextField.setText(configLoader.getExcludeSuffix()); + JPanel settingPanel = new JPanel(new BorderLayout()); + DefaultTableModel model = new DefaultTableModel(); - add(rulesFilePathTextField, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(5, 0, 5, 5), 0, 0)); - add(rulesFilePathLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.WEST, GridBagConstraints.VERTICAL, - new Insets(5, 5, 5, 5), 0, 0)); - add(onlineUpdateButton, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(5, 0, 5, 5), 0, 0)); - add(reloadButton, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(5, 0, 5, 5), 0, 0)); - add(excludeSuffixLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, - new Insets(0, 5, 5, 5), 0, 0)); - add(excludeSuffixTextField, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 5), 0, 0)); - add(excludeSuffixSaveButton, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.SOUTH, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 5), 0, 0)); + JTable table = new JTable(model); + model.addColumn("Value"); + JScrollPane scrollPane = new JScrollPane(table); + + JPanel buttonPanel = new JPanel(); + buttonPanel.setBorder(new EmptyBorder(0, 3, 0, 0)); + GridBagLayout layout = new GridBagLayout(); + layout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0}; + layout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; + buttonPanel.setLayout(layout); + + JPanel inputPanel = new JPanel(new BorderLayout()); + 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 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); + } + + if (selected.equals("Block host")) { + addDataToTable(configLoader.getBlockHost().replaceAll("\\|", "\r\n"), model); + } + }); + setTypeComboBox.setSelectedItem("Exclude suffix"); + + 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.getExcludeSuffix()) && !values.isEmpty()) { + configLoader.setBlockHost(values); + } + } + } + }); + + constraints.insets = new Insets(0, 0, 3, 0); + constraints.gridy = 0; + buttonPanel.add(setTypeComboBox, constraints); + constraints.gridy = 1; + buttonPanel.add(addButton, constraints); + constraints.gridy = 2; + buttonPanel.add(removeButton, constraints); + constraints.gridy = 3; + buttonPanel.add(pasteButton, constraints); + constraints.gridy = 4; + buttonPanel.add(clearButton, constraints); + + JTextField addTextField = new JTextField(); + String defaultText = "Enter a new item"; + UIEnhancer.setTextFieldPlaceholder(addTextField, defaultText); + + inputPanelB.add(addTextField, BorderLayout.CENTER); + inputPanel.add(scrollPane, BorderLayout.CENTER); + inputPanel.add(inputPanelB, BorderLayout.NORTH); + + settingPanel.add(buttonPanel, BorderLayout.EAST); + settingPanel.add(inputPanel, BorderLayout.CENTER); + + addButton.addActionListener(e -> { + String addTextFieldText = addTextField.getText(); + if (!addTextFieldText.equals(defaultText)) { + addDataToTable(addTextFieldText, model); + } + addTextField.setText(""); + addTextField.requestFocusInWindow(); + }); + + pasteButton.addActionListener(e -> { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + try { + String data = (String) clipboard.getData(DataFlavor.stringFlavor); + + if (data != null && !data.isEmpty()) { + addDataToTable(data, model); + } + } catch (Exception ignored) { + } + }); + + removeButton.addActionListener(e -> { + int selectedRow = table.getSelectedRow(); + if (selectedRow != -1) { + model.removeRow(selectedRow); + } + }); + + 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, 5, 10, 5)); + settingMainPanel.add(settingLabelPanel, BorderLayout.NORTH); + settingMainPanel.add(settingPanel, BorderLayout.CENTER); + + add(ruleInfoPanel, BorderLayout.NORTH); + add(settingMainPanel, BorderLayout.CENTER); + } + + private String getFirstColumnDataAsString(DefaultTableModel model) { + StringBuilder firstColumnData = new StringBuilder(); + int numRows = model.getRowCount(); + + for (int row = 0; row < numRows; row++) { + firstColumnData.append(model.getValueAt(row, 0)); + if (row < numRows - 1) { + firstColumnData.append("|"); + } + } + + return firstColumnData.toString(); + } + + private void addDataToTable(String data, DefaultTableModel model) { + if (!data.isBlank()) { + String[] rows = data.split("\\r?\\n"); + for (String row : rows) { + model.addRow(new String[]{row}); + } + deduplicateTableData(model); + } + } + + private void deduplicateTableData(DefaultTableModel model) { + // 使用 Map 存储每一行的数据,用于去重 + Set> rowData = new LinkedHashSet<>(); + + int columnCount = model.getColumnCount(); + + // 将每一行数据作为一个列表,添加到 Set 中 + for (int i = 0; i < model.getRowCount(); i++) { + List row = new ArrayList<>(); + for (int j = 0; j < columnCount; j++) { + row.add(model.getValueAt(i, j)); + } + rowData.add(row); + } + + // 清除原始数据 + model.setRowCount(0); + + // 将去重后的数据添加回去 + for (List uniqueRow : rowData) { + model.addRow(uniqueRow.toArray()); + } } private void onlineUpdateActionPerformed(ActionEvent e) { // 添加提示框防止用户误触导致配置更新 int retCode = JOptionPane.showConfirmDialog(null, "Do you want to update rules?", "Info", JOptionPane.YES_NO_OPTION); if (retCode == JOptionPane.YES_OPTION) { - configLoader.initRules(); + configLoader.initRulesByNet(); reloadActionPerformed(null); } } - private void excludeSuffixSaveActionPerformed(ActionEvent e, String suffix) { - if (!suffix.equals(configLoader.getExcludeSuffix()) && !suffix.isEmpty()) { - configLoader.setExcludeSuffix(suffix); - } - } - private void reloadActionPerformed(ActionEvent e) { rules.reloadRuleGroup(); } diff --git a/src/main/java/hae/instances/editor/RequestEditor.java b/src/main/java/hae/instances/editor/RequestEditor.java index a08a6a4..c9c01f3 100644 --- a/src/main/java/hae/instances/editor/RequestEditor.java +++ b/src/main/java/hae/instances/editor/RequestEditor.java @@ -11,6 +11,8 @@ import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor; import burp.api.montoya.ui.editor.extension.HttpRequestEditorProvider; import hae.component.board.Datatable; import hae.instances.http.utils.MessageProcessor; +import hae.utils.config.ConfigLoader; +import hae.utils.string.StringProcessor; import javax.swing.*; import java.awt.*; @@ -20,26 +22,31 @@ import java.util.Map; public class RequestEditor implements HttpRequestEditorProvider { private final MontoyaApi api; + private final ConfigLoader configLoader; - public RequestEditor(MontoyaApi api) { + public RequestEditor(MontoyaApi api, ConfigLoader configLoader) { this.api = api; + this.configLoader = configLoader; } @Override public ExtensionProvidedHttpRequestEditor provideHttpRequestEditor(EditorCreationContext editorCreationContext) { - return new Editor(api, editorCreationContext); + return new Editor(api, configLoader, editorCreationContext); } private static class Editor implements ExtensionProvidedHttpRequestEditor { private final MontoyaApi api; + private final ConfigLoader configLoader; private final EditorCreationContext creationContext; private final MessageProcessor messageProcessor; private HttpRequestResponse requestResponse; + private List> dataList; 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); } @@ -52,15 +59,29 @@ public class RequestEditor implements HttpRequestEditorProvider { @Override public void setRequestResponse(HttpRequestResponse requestResponse) { this.requestResponse = requestResponse; + generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList); } @Override public synchronized boolean isEnabledFor(HttpRequestResponse requestResponse) { HttpRequest request = requestResponse.request(); - if (request != null && !request.bodyToString().equals("Loading...")) { - List> result = messageProcessor.processRequest("", request, false); - generateTabbedPaneFromResultMap(api, jTabbedPane, result); - return jTabbedPane.getTabCount() > 0; + if (request != null) { + try { + String host = StringProcessor.getHostByUrl(request.url()); + if (!host.isEmpty()) { + String[] hostList = configLoader.getBlockHost().split("\\|"); + boolean isBlockHost = isBlockHost(hostList, host); + + List suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|")); + boolean matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost; + + if (!matches && !request.bodyToString().equals("Loading...")) { + this.dataList = messageProcessor.processRequest("", request, false); + return isListHasData(this.dataList); + } + } + } catch (Exception ignored) { + } } return false; } @@ -97,11 +118,30 @@ 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 (StringProcessor.matchFromEnd(host, cleanedHost)) { + isBlockHost = true; + } + } + return isBlockHost; + } + + public static boolean isListHasData(List> dataList) { + if (dataList != null && !dataList.isEmpty()) { + Map dataMap = dataList.get(0); + return dataMap != null && !dataMap.isEmpty(); + } + return false; + } + public static void generateTabbedPaneFromResultMap(MontoyaApi api, JTabbedPane tabbedPane, List> result) { tabbedPane.removeAll(); - if (result != null && !result.isEmpty() && result.size() > 0) { + if (result != null && !result.isEmpty()) { Map dataMap = result.get(0); - if (dataMap != null && !dataMap.isEmpty() && dataMap.size() > 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)); diff --git a/src/main/java/hae/instances/editor/ResponseEditor.java b/src/main/java/hae/instances/editor/ResponseEditor.java index 1f3716a..033c368 100644 --- a/src/main/java/hae/instances/editor/ResponseEditor.java +++ b/src/main/java/hae/instances/editor/ResponseEditor.java @@ -4,6 +4,7 @@ import burp.api.montoya.MontoyaApi; import burp.api.montoya.core.ByteArray; import burp.api.montoya.core.Range; import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.http.message.requests.HttpRequest; import burp.api.montoya.http.message.responses.HttpResponse; import burp.api.montoya.ui.Selection; import burp.api.montoya.ui.editor.extension.EditorCreationContext; @@ -11,34 +12,42 @@ import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpResponseEditor; import burp.api.montoya.ui.editor.extension.HttpResponseEditorProvider; import hae.component.board.Datatable; import hae.instances.http.utils.MessageProcessor; +import hae.utils.config.ConfigLoader; +import hae.utils.string.StringProcessor; import javax.swing.*; import java.awt.*; +import java.util.Arrays; import java.util.List; import java.util.Map; public class ResponseEditor implements HttpResponseEditorProvider { private final MontoyaApi api; + private final ConfigLoader configLoader; - public ResponseEditor(MontoyaApi api) { + public ResponseEditor(MontoyaApi api, ConfigLoader configLoader) { this.api = api; + this.configLoader = configLoader; } @Override public ExtensionProvidedHttpResponseEditor provideHttpResponseEditor(EditorCreationContext editorCreationContext) { - return new Editor(api, editorCreationContext); + return new Editor(api, configLoader, editorCreationContext); } private static class Editor implements ExtensionProvidedHttpResponseEditor { private final MontoyaApi api; + private final ConfigLoader configLoader; private final EditorCreationContext creationContext; private final MessageProcessor messageProcessor; private HttpRequestResponse requestResponse; + private List> dataList; 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,16 +60,37 @@ public class ResponseEditor implements HttpResponseEditorProvider { @Override public void setRequestResponse(HttpRequestResponse requestResponse) { this.requestResponse = requestResponse; + RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList); } @Override public synchronized boolean isEnabledFor(HttpRequestResponse requestResponse) { - HttpResponse request = requestResponse.response(); - if (request != null && !request.bodyToString().equals("Loading...")) { - List> result = messageProcessor.processResponse("", request, false); - RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, result); - return jTabbedPane.getTabCount() > 0; + HttpResponse response = requestResponse.response(); + + if (response != null) { + HttpRequest request = requestResponse.request(); + boolean matches = false; + + if (request != null) { + try { + String host = StringProcessor.getHostByUrl(request.url()); + if (!host.isEmpty()) { + String[] hostList = configLoader.getBlockHost().split("\\|"); + boolean isBlockHost = RequestEditor.isBlockHost(hostList, host); + + List suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|")); + matches = suffixList.contains(request.fileExtension().toLowerCase()) || isBlockHost; + } + } catch (Exception ignored) { + } + } + + if (!matches && !response.bodyToString().equals("Loading...")) { + this.dataList = messageProcessor.processResponse("", response, false); + return RequestEditor.isListHasData(this.dataList); + } } + return false; } diff --git a/src/main/java/hae/instances/editor/WebSocketEditor.java b/src/main/java/hae/instances/editor/WebSocketEditor.java index 39a439b..bf0344b 100644 --- a/src/main/java/hae/instances/editor/WebSocketEditor.java +++ b/src/main/java/hae/instances/editor/WebSocketEditor.java @@ -33,6 +33,7 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider { private final EditorCreationContext creationContext; private final MessageProcessor messageProcessor; private ByteArray message; + private List> dataList; private final JTabbedPane jTabbedPane = new JTabbedPane(); @@ -50,15 +51,15 @@ public class WebSocketEditor implements WebSocketMessageEditorProvider { @Override public void setMessage(WebSocketMessage webSocketMessage) { this.message = webSocketMessage.payload(); + RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, this.dataList); } @Override public boolean isEnabledFor(WebSocketMessage webSocketMessage) { String websocketMessage = webSocketMessage.payload().toString(); if (!websocketMessage.isEmpty()) { - List> result = messageProcessor.processMessage("", websocketMessage, false); - RequestEditor.generateTabbedPaneFromResultMap(api, jTabbedPane, result); - return jTabbedPane.getTabCount() > 0; + this.dataList = messageProcessor.processMessage("", websocketMessage, false); + return RequestEditor.isListHasData(this.dataList); } return false; } diff --git a/src/main/java/hae/instances/http/HttpMessageHandler.java b/src/main/java/hae/instances/http/HttpMessageHandler.java index b44def3..b5fbfcb 100644 --- a/src/main/java/hae/instances/http/HttpMessageHandler.java +++ b/src/main/java/hae/instances/http/HttpMessageHandler.java @@ -6,9 +6,10 @@ import burp.api.montoya.core.HighlightColor; import burp.api.montoya.http.handler.*; import burp.api.montoya.http.message.HttpRequestResponse; import burp.api.montoya.http.message.requests.HttpRequest; -import hae.Config; import hae.component.board.message.MessageTableModel; +import hae.instances.editor.RequestEditor; import hae.instances.http.utils.MessageProcessor; +import hae.utils.config.ConfigLoader; import hae.utils.string.StringProcessor; import java.util.ArrayList; @@ -18,6 +19,7 @@ import java.util.Map; public class HttpMessageHandler implements HttpHandler { private final MontoyaApi api; + private final ConfigLoader configLoader; private final MessageTableModel messageTableModel; private final MessageProcessor messageProcessor; @@ -29,8 +31,9 @@ public class HttpMessageHandler implements HttpHandler { private final ThreadLocal matches = ThreadLocal.withInitial(() -> false); private final ThreadLocal httpRequest = new ThreadLocal<>(); - public HttpMessageHandler(MontoyaApi api, MessageTableModel messageTableModel) { + public HttpMessageHandler(MontoyaApi api, ConfigLoader configLoader, MessageTableModel messageTableModel) { this.api = api; + this.configLoader = configLoader; this.messageTableModel = messageTableModel; this.messageProcessor = new MessageProcessor(api); } @@ -46,8 +49,11 @@ public class HttpMessageHandler implements HttpHandler { host.set(StringProcessor.getHostByUrl(httpRequestToBeSent.url())); - List suffixList = Arrays.asList(Config.suffix.split("\\|")); - matches.set(suffixList.contains(httpRequestToBeSent.fileExtension())); + String[] hostList = configLoader.getBlockHost().split("\\|"); + boolean isBlockHost = RequestEditor.isBlockHost(hostList, host.get()); + + List suffixList = Arrays.asList(configLoader.getExcludeSuffix().split("\\|")); + matches.set(suffixList.contains(httpRequestToBeSent.fileExtension().toLowerCase()) || isBlockHost); if (!matches.get()) { List> result = messageProcessor.processRequest(host.get(), httpRequestToBeSent, true); diff --git a/src/main/java/hae/instances/http/utils/RegularMatcher.java b/src/main/java/hae/instances/http/utils/RegularMatcher.java index 11e410e..dfbc21c 100644 --- a/src/main/java/hae/instances/http/utils/RegularMatcher.java +++ b/src/main/java/hae/instances/http/utils/RegularMatcher.java @@ -9,12 +9,12 @@ import hae.Config; import hae.cache.CachePool; import hae.utils.string.HashCalculator; import hae.utils.string.StringProcessor; -import jregex.Matcher; -import jregex.Pattern; import java.text.MessageFormat; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class RegularMatcher { private final MontoyaApi api; @@ -27,7 +27,7 @@ public class RegularMatcher { public Map> match(String host, String type, String message, String header, String body) { // 先从缓存池里判断是否有已经匹配好的结果 String messageIndex = HashCalculator.calculateHash(message.getBytes()); - Map> map = CachePool.getFromCache(messageIndex); + Map> map = CachePool.get(messageIndex); if (map != null) { return map; } else { @@ -81,6 +81,7 @@ public class RegularMatcher { result.addAll(matchByRegex(f_regex, s_regex, matchContent, format, engine, sensitive)); } catch (Exception e) { api.logging().logToError(String.format("[x] Error Info:\nName: %s\nRegex: %s", name, f_regex)); + api.logging().logToError(e.getMessage()); continue; } @@ -98,27 +99,18 @@ public class RegularMatcher { // 添加到全局变量中,便于Databoard检索 if (!Objects.equals(host, "") && host != null) { List dataList = Arrays.asList(dataStr.split("\n")); - if (Config.globalDataMap.containsKey(host)) { - ConcurrentHashMap> gRuleMap = new ConcurrentHashMap<>(Config.globalDataMap.get(host)); - if (gRuleMap.containsKey(name)) { - // gDataList为不可变列表,因此需要重新创建一个列表以便于使用addAll方法 - List gDataList = gRuleMap.get(name); - List newDataList = new ArrayList<>(gDataList); - newDataList.addAll(dataList); - newDataList = new ArrayList<>(new HashSet<>(newDataList)); - gRuleMap.remove(name); - gRuleMap.put(name, newDataList); - } else { - gRuleMap.put(name, dataList); - } - Config.globalDataMap.remove(host); - Config.globalDataMap.put(host, gRuleMap); - } else { - Map> ruleMap = new HashMap<>(); - ruleMap.put(name, dataList); - // 添加单一Host - Config.globalDataMap.put(host, ruleMap); - } + + Config.globalDataMap.compute(host, (existingHost, existingMap) -> { + Map> gRuleMap = Optional.ofNullable(existingMap).orElse(new ConcurrentHashMap<>()); + + gRuleMap.merge(name, new ArrayList<>(dataList), (existingList, newList) -> { + Set combinedSet = new LinkedHashSet<>(existingList); + combinedSet.addAll(newList); + return new ArrayList<>(combinedSet); + }); + + return gRuleMap; + }); String[] splitHost = host.split("\\."); String onlyHost = host.split(":")[0]; @@ -139,7 +131,7 @@ public class RegularMatcher { } } }); - CachePool.addToCache(messageIndex, finalMap); + CachePool.put(messageIndex, finalMap); return finalMap; } } @@ -229,7 +221,7 @@ public class RegularMatcher { } private Matcher createPatternMatcher(String regex, String content, boolean sensitive) { - Pattern pattern = (sensitive) ? new Pattern(regex) : new Pattern(regex, Pattern.IGNORE_CASE); + Pattern pattern = sensitive ? Pattern.compile(regex) : Pattern.compile(regex, Pattern.CASE_INSENSITIVE); return pattern.matcher(content); } @@ -242,7 +234,7 @@ public class RegularMatcher { private LinkedList parseIndexesFromString(String input) { LinkedList indexes = new LinkedList<>(); - Pattern pattern = new Pattern("\\{(\\d+)}"); + Pattern pattern = Pattern.compile("\\{(\\d+)}"); Matcher matcher = pattern.matcher(input); while (matcher.find()) { @@ -264,7 +256,7 @@ public class RegularMatcher { } private String reorderIndex(String format) { - Pattern pattern = new Pattern("\\{(\\d+)}"); + Pattern pattern = Pattern.compile("\\{(\\d+)}"); Matcher matcher = pattern.matcher(format); int count = 0; while (matcher.find()) { diff --git a/src/main/java/hae/utils/config/ConfigLoader.java b/src/main/java/hae/utils/config/ConfigLoader.java index b62a72f..49fda87 100644 --- a/src/main/java/hae/utils/config/ConfigLoader.java +++ b/src/main/java/hae/utils/config/ConfigLoader.java @@ -1,6 +1,7 @@ package hae.utils.config; 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 hae.Config; @@ -11,6 +12,7 @@ import org.yaml.snakeyaml.representer.Representer; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; @@ -44,7 +46,7 @@ public class ConfigLoader { File rulesFilePath = new File(this.rulesFilePath); if (!(rulesFilePath.exists() && rulesFilePath.isFile())) { - initRules(); + initRulesByRes(); } Config.globalRules = getRules(); @@ -76,6 +78,7 @@ public class ConfigLoader { public void initConfig() { Map r = new LinkedHashMap<>(); r.put("excludeSuffix", getExcludeSuffix()); + r.put("blockHost", getBlockHost()); try { Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8); yaml.dump(r, ws); @@ -88,24 +91,6 @@ public class ConfigLoader { return rulesFilePath; } - public String getExcludeSuffix() { - File yamlSetting = new File(configFilePath); - if (!yamlSetting.exists() || !yamlSetting.isFile()) { - return Config.suffix; - } - - try (InputStream inorder = Files.newInputStream(Paths.get(configFilePath))) { - Map r = new Yaml().load(inorder); - - if (r.containsKey("excludeSuffix")) { - return r.get("excludeSuffix").toString(); - } - } catch (Exception ignored) { - } - - return Config.suffix; - } - // 获取规则配置 public Map getRules() { Map rules = new HashMap<>(); @@ -149,18 +134,104 @@ public class ConfigLoader { return rules; } - public void setExcludeSuffix(String excludeSuffix) { - Map r = new LinkedHashMap<>(); - r.put("excludeSuffix", excludeSuffix); - try { - Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8); - yaml.dump(r, ws); - ws.close(); + 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 r = new Yaml().load(inorder); + + if (r.containsKey("blockHost")) { + return r.get("blockHost").toString(); + } } catch (Exception ignored) { } + + return Config.host; + } + + public String getExcludeSuffix() { + File yamlSetting = new File(configFilePath); + if (!yamlSetting.exists() || !yamlSetting.isFile()) { + return Config.suffix; + } + + try (InputStream inorder = Files.newInputStream(Paths.get(configFilePath))) { + Map r = new Yaml().load(inorder); + + if (r.containsKey("excludeSuffix")) { + return r.get("excludeSuffix").toString(); + } + } catch (Exception ignored) { + } + + return Config.suffix; + } + + private Map loadCurrentConfig() { + Path path = Paths.get(configFilePath); + if (!Files.exists(path)) { + return new LinkedHashMap<>(); // 返回空的Map,表示没有当前配置 + } + + try (InputStream in = Files.newInputStream(path)) { + return yaml.load(in); + } catch (IOException e) { + return new LinkedHashMap<>(); // 读取失败时也返回空的Map + } } - public void initRules() { + public void setExcludeSuffix(String excludeSuffix) { + Map currentConfig = loadCurrentConfig(); + currentConfig.put("excludeSuffix", excludeSuffix); // 更新配置 + + try (Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8)) { + yaml.dump(currentConfig, ws); + } catch (IOException ignored) { + } + } + + public void setBlockHost(String blockHost) { + Map currentConfig = loadCurrentConfig(); + currentConfig.put("blockHost", blockHost); // 更新配置 + + try (Writer ws = new OutputStreamWriter(Files.newOutputStream(Paths.get(configFilePath)), StandardCharsets.UTF_8)) { + yaml.dump(currentConfig, ws); + } catch (IOException ignored) { + } + } + + public void initRulesByRes() { + boolean isCopySuccess = copyRulesToFile(this.rulesFilePath); + if (!isCopySuccess) { + api.extension().unload(); + } + } + + private boolean copyRulesToFile(String targetFilePath) { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream("rules/Rules.yml"); + File targetFile = new File(targetFilePath); + + try (inputStream; OutputStream outputStream = new FileOutputStream(targetFile)) { + if (inputStream != null) { + byte[] buffer = new byte[1024]; + int length; + + while ((length = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + + return true; + } + } catch (IOException ignored) { + } + + return false; + } + + public void initRulesByNet() { Thread t = new Thread() { public void run() { pullRules(); @@ -177,7 +248,7 @@ public class ConfigLoader { try { String url = "https://raw.githubusercontent.com/gh0stkey/HaE/gh-pages/Rules.yml"; HttpRequest httpRequest = HttpRequest.httpRequestFromUrl(url); - HttpRequestResponse requestResponse = api.http().sendRequest(httpRequest); + HttpRequestResponse requestResponse = api.http().sendRequest(httpRequest, RequestOptions.requestOptions().withUpstreamTLSVerification()); String responseBody = requestResponse.response().bodyToString(); if (responseBody.contains("rules")) { FileOutputStream fileOutputStream = new FileOutputStream(rulesFilePath); diff --git a/src/main/java/hae/utils/ui/UIEnhancer.java b/src/main/java/hae/utils/ui/UIEnhancer.java new file mode 100644 index 0000000..ee7da70 --- /dev/null +++ b/src/main/java/hae/utils/ui/UIEnhancer.java @@ -0,0 +1,30 @@ +package hae.utils.ui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class UIEnhancer { + public static void setTextFieldPlaceholder(JTextField textField, String placeholderText) { + textField.setForeground(Color.GRAY); + textField.setText(placeholderText); + textField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (textField.getText().equals(placeholderText)) { + textField.setText(""); + textField.setForeground(Color.BLACK); + } + } + + @Override + public void focusLost(FocusEvent e) { + if (textField.getText().isEmpty()) { + textField.setForeground(Color.GRAY); + textField.setText(placeholderText); + } + } + }); + } +} diff --git a/src/main/resources/logo.png b/src/main/resources/logo/logo.png similarity index 100% rename from src/main/resources/logo.png rename to src/main/resources/logo/logo.png diff --git a/src/main/resources/logo_black.png b/src/main/resources/logo/logo_black.png similarity index 100% rename from src/main/resources/logo_black.png rename to src/main/resources/logo/logo_black.png diff --git a/src/main/resources/rules/Rules.yml b/src/main/resources/rules/Rules.yml new file mode 100644 index 0000000..92eab8e --- /dev/null +++ b/src/main/resources/rules/Rules.yml @@ -0,0 +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