diff --git a/BurpExtender.java b/BurpExtender.java new file mode 100644 index 0000000..2054e95 --- /dev/null +++ b/BurpExtender.java @@ -0,0 +1,292 @@ +package burp; + +import burp.core.processor.ColorProcessor; +import burp.core.processor.MessageProcessor; +import burp.ui.MainUI; +import burp.ui.board.MessagePanel; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import javax.swing.*; +import java.awt.*; +import java.io.PrintWriter; +import java.util.List; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * @author EvilChen & 0chencc + */ + +public class BurpExtender implements IBurpExtender, IHttpListener, IMessageEditorTabFactory, ITab { + private MainUI main; + // stdout变成公开属性,便于其他类调用输出调试信息 + public static PrintWriter stdout; + private IBurpExtenderCallbacks callbacks; + private static IExtensionHelpers helpers; + ColorProcessor colorProcessor = new ColorProcessor(); + MessageProcessor messageProcessor = new MessageProcessor(); + private MessagePanel messagePanel; + + @Override + public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) + { + this.callbacks = callbacks; + BurpExtender.helpers = callbacks.getHelpers(); + + String version = "2.5.1"; + callbacks.setExtensionName(String.format("HaE (%s) - Highlighter and Extractor", version)); + + // 定义输出 + stdout = new PrintWriter(callbacks.getStdout(), true); + stdout.println("[ HACK THE WORLD - TO DO IT ]"); + stdout.println("[#] Author: EvilChen & 0chencc"); + stdout.println("[#] Github: https://github.com/gh0stkey/HaE"); + + // UI + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + initialize(); + } + }); + + callbacks.registerHttpListener(BurpExtender.this); + callbacks.registerMessageEditorTabFactory(BurpExtender.this); + + } + + private void initialize(){ + messagePanel = new MessagePanel(callbacks, helpers); + main = new MainUI(messagePanel); + callbacks.customizeUiComponent(main); + callbacks.addSuiteTab(BurpExtender.this); + } + + @Override + public String getTabCaption(){ + return "HaE"; + } + + @Override + public Component getUiComponent() { + return main; + } + + /** + * 使用processHttpMessage用来做Highlighter + */ + @Override + public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { + // 判断是否是响应,且该代码作用域为:REPEATER、INTRUDER、PROXY(分别对应toolFlag 64、32、4) + if (toolFlag == 64 || toolFlag == 32 || toolFlag == 4) { + byte[] content; + + if (messageIsRequest) { + content = messageInfo.getRequest(); + } else { + content = messageInfo.getResponse(); + } + + IHttpService iHttpService = null; + + String host = ""; + + try { + iHttpService = messageInfo.getHttpService(); + host = iHttpService.getHost(); + } catch (Exception ignored) { + } + + if (Objects.equals(host, "")) { + List requestTmpHeaders = helpers.analyzeRequest(content).getHeaders(); + host = requestTmpHeaders.get(1).split(":")[1].trim(); + } + + List> result = null; + try { + result = messageProcessor.processMessage(helpers, content, messageIsRequest, true, host); + } 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<>(); + + if (originalColor != null) { + colorList.add(originalColor); + } + + colorList.add(result.get(0).get("color")); + resColor = colorProcessor.retrieveFinalColor(colorProcessor.retrieveColorIndices(colorList)); + messageInfo.setHighlight(resColor); + + String addComment = String.join(", ", result.get(1).get("comment")); + String allComment = !Objects.equals(originalComment, "") ? String.format("%s, %s", originalComment, addComment) : addComment; + resComment = mergeComment(allComment); + + messageInfo.setComment(resComment); + } + + String endComment = resComment.isEmpty() ? originalComment : resComment; + String endColor = resColor.isEmpty() ? originalColor : resColor; + + if (!messageIsRequest && !Objects.equals(endComment, "") && !Objects.equals(endColor, "")) { + messagePanel.add(messageInfo, endComment, String.valueOf(content.length), endColor); + } + } + } + + private String mergeComment(String comment) { + Map itemCounts = new HashMap<>(); + String[] items = comment.split(", "); + + for (String item : items) { + String itemName = item.substring(0, item.lastIndexOf("(")).trim(); + int count = Integer.parseInt(item.substring(item.lastIndexOf("(") + 1, item.lastIndexOf(")")).trim()); + itemCounts.put(itemName, itemCounts.getOrDefault(itemName, 0) + count); + } + + StringBuilder mergedItems = new StringBuilder(); + + for (Map.Entry entry : itemCounts.entrySet()) { + String itemName = entry.getKey(); + int count = entry.getValue(); + + mergedItems.append(itemName).append(" (").append(count).append("), "); + } + + return mergedItems.substring(0, mergedItems.length() - 2); + } + + class MarkInfoTab implements IMessageEditorTab { + private final JTabbedPane jTabbedPane = new JTabbedPane(); + private JTable jTable = new JTable(); + private final IMessageEditorController controller; + private Map extractRequestMap; + private Map extractResponseMap; + private ArrayList titleList = new ArrayList<>(); + + public MarkInfoTab(IMessageEditorController controller, boolean editable) { + this.controller = controller; + } + + @Override + public String getTabCaption() { + return "MarkInfo"; + } + + @Override + public Component getUiComponent() { + jTabbedPane.addChangeListener(new ChangeListener() { + @Override + public void stateChanged(ChangeEvent arg0) { + jTable = (JTable) ((JScrollPane)jTabbedPane.getSelectedComponent()).getViewport().getView(); + } + }); + return this.jTabbedPane; + } + + @Override + public boolean isEnabled(byte[] content, boolean isRequest) { + List> result = null; + + try { + result = messageProcessor.processMessage(helpers, content, isRequest, false, ""); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + if (result != null && !result.isEmpty()) { + Map dataMap = result.get(0); + if (isRequest) { + extractRequestMap = dataMap; + } else { + extractResponseMap = dataMap; + } + return true; + } + return false; + } + + @Override + public byte[] getMessage() { + return null; + } + + @Override + public boolean isModified() { + return false; + } + + /** + * 快捷键复制功能 + */ + @Override + public byte[] getSelectedData() { + int[] selectRows = jTable.getSelectedRows(); + StringBuilder selectData = new StringBuilder(); + for (int row : selectRows) { + selectData.append(jTable.getValueAt(row, 0).toString()).append("\n"); + } + // 便于单行复制,去除最后一个换行符 + String revData = selectData.reverse().toString().replaceFirst("\n", ""); + StringBuilder retData = new StringBuilder(revData).reverse(); + return helpers.stringToBytes(retData.toString()); + } + + /** + * 使用setMessage用来做Extractor + */ + @Override + public void setMessage(byte[] content, boolean isRequest) { + if (content.length > 0) { + if (isRequest) { + makeTable(extractRequestMap); + } else { + makeTable(extractResponseMap); + } + } + } + + /** + * 创建MarkInfo表单 + */ + public void makeTable(Map dataMap) { + ArrayList lTitleList = new ArrayList<>(); + dataMap.keySet().forEach(i->{ + String[] extractData = dataMap.get(i).split("\n"); + Object[][] data = new Object[extractData.length][1]; + for (int x = 0; x < extractData.length; x++) { + data[x][0] = extractData[x]; + } + JTable infoTable = new JTable(data, new Object[]{"Information"}); + infoTable.setAutoCreateRowSorter(true); + JScrollPane jScrollPane = new JScrollPane(infoTable); + + lTitleList.add(i); + this.jTabbedPane.addTab(i, jScrollPane); + }); + + /* + * 使用removeAll会导致MarkInfo UI出现空白的情况,为了改善用户侧体验,采用remove的方式进行删除; + * 采用全局ArrayList的方式遍历删除Tab,以此应对BurpSuite缓存机制导致的MarkInfo UI错误展示。 + */ + titleList.forEach(t->{ + int indexOfTab = this.jTabbedPane.indexOfTab(t); + if (indexOfTab != -1) { + this.jTabbedPane.removeTabAt(indexOfTab); + } + }); + + titleList = lTitleList; + } + } + + @Override + public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) { + return new MarkInfoTab(controller, editable); + } +} \ No newline at end of file