diff --git a/images/databoard.png b/images/databoard.png index e89b9d3..3357aab 100644 Binary files a/images/databoard.png and b/images/databoard.png differ diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 011ac22..a9cdbf9 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -35,7 +35,7 @@ public class BurpExtender implements IBurpExtender, IHttpListener, IMessageEdito new ConfigLoader(); - String version = "2.5.2"; + String version = "2.5.3"; callbacks.setExtensionName(String.format("HaE (%s) - Highlighter and Extractor", version)); // 定义输出 @@ -111,10 +111,12 @@ public class BurpExtender implements IBurpExtender, IHttpListener, IMessageEdito } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } + String resComment = ""; String resColor = ""; String originalColor = messageInfo.getHighlight(); String originalComment = messageInfo.getComment(); + if (result != null && !result.isEmpty() && result.size() > 0) { List colorList = new ArrayList<>(); diff --git a/src/main/java/burp/core/processor/DataProcessingUnit.java b/src/main/java/burp/core/processor/DataProcessingUnit.java index d07c9b9..c566a81 100644 --- a/src/main/java/burp/core/processor/DataProcessingUnit.java +++ b/src/main/java/burp/core/processor/DataProcessingUnit.java @@ -49,7 +49,7 @@ public class DataProcessingUnit { public Map> matchContentByRegex(byte[] content, String headers, byte[] body, String scopeString, String host) throws NoSuchAlgorithmException { - // 先从池子里判断是否有已经匹配好的结果 + // 先从缓存池里判断是否有已经匹配好的结果 String messageIndex = HashCalculator.calculateHash(content); Map> map = GlobalCachePool.getFromCache(messageIndex); if (map != null) { diff --git a/src/main/java/burp/ui/board/Databoard.java b/src/main/java/burp/ui/board/Databoard.java index 3e2c22e..e4c789e 100644 --- a/src/main/java/burp/ui/board/Databoard.java +++ b/src/main/java/burp/ui/board/Databoard.java @@ -195,7 +195,12 @@ public class Databoard extends JPanel { for (String host : getHostByList()) { String lowerCaseHost = host.toLowerCase(); if (lowerCaseHost.contains(input)) { - comboBoxModel.addElement(host); + if (lowerCaseHost.equals(input)) { + comboBoxModel.insertElementAt(lowerCaseHost, 0); + comboBoxModel.setSelectedItem(lowerCaseHost); + } else { + comboBoxModel.addElement(host); + } } } } @@ -277,7 +282,7 @@ public class Databoard extends JPanel { for (Map.Entry> entrySet : entry.getValue().entrySet()) { Thread t = new Thread(() -> { String tabTitle = String.format("%s (%s)", entrySet.getKey(), entrySet.getValue().size()); - newTabbedPane.addTab(tabTitle, new JScrollPane(new DataTable(entrySet.getKey(), entrySet.getValue()))); + newTabbedPane.addTab(tabTitle, new DataTable(entrySet.getKey(), entrySet.getValue())); dataTabbedPaneA.addTab(entry.getKey(), newTabbedPane); }); t.start(); @@ -295,7 +300,7 @@ public class Databoard extends JPanel { splitPane.setLeftComponent(dataTabbedPaneB); for (Map.Entry> entry : selectedDataMap.entrySet()) { String tabTitle = String.format("%s (%s)", entry.getKey(), entry.getValue().size()); - dataTabbedPaneB.addTab(tabTitle, new JScrollPane(new DataTable(entry.getKey(), entry.getValue()))); + dataTabbedPaneB.addTab(tabTitle, new DataTable(entry.getKey(), entry.getValue())); } } @@ -324,31 +329,100 @@ public class Databoard extends JPanel { } } + class DataTable extends JPanel { + private final JTable table; + private final DefaultTableModel model; + private final JTextField searchField; + private TableRowSorter sorter; - class DataTable extends JTable { - public DataTable(String tableName, List list){ - DefaultTableModel model = new DefaultTableModel(); - Object[][] data = new Object[list.size()][1]; - for (int x = 0; x < list.size(); x++) { - data[x][0] = list.get(x); - } - model.setDataVector(data, new Object[]{"Information"}); - setAutoCreateRowSorter(true); - setModel(model); - setDefaultEditor(Object.class, null); - addMouseListener(new MouseAdapter() { + public DataTable(String tableName, List list) { + model = new DefaultTableModel(); + table = new JTable(model); + sorter = new TableRowSorter<>(model); + + table.setRowSorter(sorter); + table.setDefaultEditor(Object.class, null); + + // 表格内容双击事件 + table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { - int selectedRow = getSelectedRow(); + int selectedRow = table.getSelectedRow(); if (selectedRow != -1) { - String rowData = getValueAt(selectedRow, 0).toString(); + String rowData = table.getValueAt(selectedRow, 0).toString(); messagePanel.applyMessageFilter(tableName, rowData); } } } }); + + model.addColumn("Information"); + for (String item : list) { + model.addRow(new Object[]{item}); + } + + String defaultText = "Search"; + + searchField = new JTextField(defaultText); + // 设置灰色默认文本Search + searchField.setForeground(Color.GRAY); + searchField.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (searchField.getText().equals(defaultText)) { + searchField.setText(""); + searchField.setForeground(Color.BLACK); + } + } + + @Override + public void focusLost(FocusEvent e) { + if (searchField.getText().isEmpty()) { + searchField.setForeground(Color.GRAY); + searchField.setText(defaultText); + } + } + }); + + // 监听输入框内容输入、更新、删除 + 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(); + } + + private void performSearch() { + // 通过字体颜色来判断是否可以进行过滤 + if (searchField.getForeground() == Color.BLACK) { + String searchText = searchField.getText(); + if (sorter == null) { + sorter = new TableRowSorter<>(model); + table.setRowSorter(sorter); + } + RowFilter rowFilter = RowFilter.regexFilter(searchText, 0); + sorter.setRowFilter(rowFilter); + } + } + }); + + // 设置布局 + JScrollPane scrollPane = new JScrollPane(table); + + setLayout(new BorderLayout(0, 5)); + add(scrollPane, BorderLayout.CENTER); + add(searchField, BorderLayout.SOUTH); } } } diff --git a/src/main/java/burp/ui/board/LogEntry.java b/src/main/java/burp/ui/board/LogEntry.java index 6b0f39a..b549810 100644 --- a/src/main/java/burp/ui/board/LogEntry.java +++ b/src/main/java/burp/ui/board/LogEntry.java @@ -9,16 +9,18 @@ public class LogEntry { private final IHttpRequestResponsePersisted requestResponse; private final URL url; private final String length; + private final String status; private final String color; private final String method; - LogEntry(IHttpRequestResponsePersisted requestResponse, String method, URL url, String comment, String length, String color) { + LogEntry(IHttpRequestResponsePersisted requestResponse, String method, URL url, String comment, String length, String color, String status) { this.requestResponse = requestResponse; this.method = method; this.url = url; this.comment = comment; this.length = length; this.color = color; + this.status = status; } public String getColor() { @@ -41,6 +43,10 @@ public class LogEntry { return this.method; } + public String getStatus() { + return this.status; + } + public IHttpRequestResponsePersisted getRequestResponse() { return this.requestResponse; } diff --git a/src/main/java/burp/ui/board/MessagePanel.java b/src/main/java/burp/ui/board/MessagePanel.java index 7e8b0b3..28e87b1 100644 --- a/src/main/java/burp/ui/board/MessagePanel.java +++ b/src/main/java/burp/ui/board/MessagePanel.java @@ -7,10 +7,14 @@ import burp.IHttpRequestResponsePersisted; import burp.IHttpService; import burp.IMessageEditor; import burp.IMessageEditorController; +import burp.IRequestInfo; import burp.config.ConfigEntry; +import burp.core.utils.HashCalculator; import burp.core.utils.StringHelper; +import java.net.URL; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -117,7 +121,7 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo @Override public int getColumnCount() { - return 5; + return 6; } @Override @@ -132,8 +136,10 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo case 2: return "Comment"; case 3: - return "Length"; + return "Status"; case 4: + return "Length"; + case 5: return "Color"; default: return ""; @@ -159,8 +165,10 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo case 2: return logEntry.getComment(); case 3: - return logEntry.getLength(); + return logEntry.getStatus(); case 4: + return logEntry.getLength(); + case 5: return logEntry.getColor(); default: return ""; @@ -296,12 +304,55 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo } public void add(IHttpRequestResponse messageInfo, String comment, String length, String color) { - synchronized(log) - { - LogEntry logEntry = new LogEntry(callbacks.saveBuffersToTempFiles(messageInfo), helpers.analyzeRequest(messageInfo).getMethod(), - helpers.analyzeRequest(messageInfo).getUrl(), comment, length, color); - log.add(logEntry); + synchronized(log) { + IRequestInfo iRequestInfo = helpers.analyzeRequest(messageInfo); + URL url = iRequestInfo.getUrl(); + String method = iRequestInfo.getMethod(); + String status = String.valueOf(helpers.analyzeResponse(messageInfo.getResponse()).getStatusCode()); + + LogEntry logEntry = new LogEntry(callbacks.saveBuffersToTempFiles(messageInfo), method, url, comment, length, color, status); + + try { + // 比较Hash,如若存在重复的请求或响应,则不放入消息内容里 + String reqHashA = getMessageHash(true, messageInfo.getRequest()); + String resHashA = getMessageHash(false, messageInfo.getResponse()); + boolean isDuplicate = false; + + for (LogEntry entry : log) { + IHttpRequestResponsePersisted reqResMessage = entry.getRequestResponse(); + String reqHashB = getMessageHash(true, reqResMessage.getRequest()); + String resHashB = getMessageHash(false, reqResMessage.getResponse()); + + if (reqHashB.equals(reqHashA) || resHashB.equals(resHashA)) { + isDuplicate = true; + break; + } + } + + if (!isDuplicate) { + log.add(logEntry); + } + + } catch (Exception e) { + e.printStackTrace(); + } } + + } + + private String getMessageHash(boolean isRequest, byte[] content) + throws NoSuchAlgorithmException { + String hash = ""; + + if (isRequest) { + hash = HashCalculator.calculateHash(content); + } else { + int responseBodyOffset = helpers.analyzeResponse(content).getBodyOffset(); + byte[] responseBody = Arrays.copyOfRange(content, responseBodyOffset, content.length); + hash = HashCalculator.calculateHash(responseBody); + } + + return hash; } public class Table extends JTable { @@ -314,6 +365,8 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo @Override public void changeSelection(int row, int col, boolean toggle, boolean extend) { + super.changeSelection(row, col, toggle, extend); + logEntry = filteredLog.get(convertRowIndexToModel(row)); requestViewer.setMessage("Loading...".getBytes(), true); responseViewer.setMessage("Loading...".getBytes(), false); @@ -335,10 +388,9 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo currentWorker = worker; // 启动后台线程 worker.execute(); - super.changeSelection(row, col, toggle, extend); } - private void refreshMessage() { + private synchronized void refreshMessage() { SwingUtilities.invokeLater(() -> { requestViewer.setMessage(logEntry.getRequestResponse().getRequest(), true); responseViewer.setMessage(logEntry.getRequestResponse().getResponse(), false); @@ -346,5 +398,4 @@ public class MessagePanel extends AbstractTableModel implements IMessageEditorCo } } -} - +} \ No newline at end of file