├── src ├── test │ ├── java │ │ ├── Start.java │ │ └── burp │ │ │ ├── ResultsTableModelTests.java │ │ │ ├── JSONParserTests.java │ │ │ └── PayloadsTableModelTests.java │ └── resources │ │ └── output.json └── main │ ├── resources │ └── GitHub-Mark-32px.png │ └── java │ ├── burp │ └── BurpExtender.java │ └── rpm │ ├── Payload.java │ ├── ui │ ├── PayloadTable.java │ ├── CellRenderer.java │ ├── JHyperlink.java │ ├── JSONParser.java │ ├── ResultTable.java │ ├── ExtenderPopupMenu.java │ └── GUI.java │ ├── controller │ └── ContentController.java │ ├── model │ ├── ResultsTableModel.java │ └── PayloadsTableModel.java │ ├── ResultEntry.java │ ├── ResponsePatternMatcher.java │ └── MessageProcessor.java ├── releases └── Response Pattern Matcher-v2.0.1.jar ├── .gitattributes ├── .gitignore ├── settings.gradle ├── README.md ├── gradlew.bat └── gradlew /src/test/java/Start.java: -------------------------------------------------------------------------------- 1 | public class Start { 2 | public static void main(String[] args) { burp.StartBurp.main(args); } 3 | } -------------------------------------------------------------------------------- /src/main/resources/GitHub-Mark-32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackj07/Response-Pattern-Matcher/HEAD/src/main/resources/GitHub-Mark-32px.png -------------------------------------------------------------------------------- /releases/Response Pattern Matcher-v2.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackj07/Response-Pattern-Matcher/HEAD/releases/Response Pattern Matcher-v2.0.1.jar -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import rpm.ResponsePatternMatcher; 4 | 5 | public class BurpExtender extends ResponsePatternMatcher { } 6 | //This class has to be in this package for the Burp extension to work -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory and other unnecessary Gradle dirs 2 | .gradle/ 3 | gradle/ 4 | 5 | #Ignore IDE stuff 6 | .idea/ 7 | *.iml 8 | 9 | # Ignore Gradle build output directory 10 | build/ 11 | 12 | # Ignore complied classes 13 | out/ 14 | 15 | # for OS specific 16 | .DS_Store 17 | .DS_Store? -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.0.1/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'Response Pattern Matcher' 11 | -------------------------------------------------------------------------------- /src/main/java/rpm/Payload.java: -------------------------------------------------------------------------------- 1 | package rpm; 2 | 3 | public class Payload { 4 | private final String content; 5 | private final Boolean isRegex; 6 | private final Boolean active; 7 | 8 | public Payload(String content, Boolean isRegex, Boolean active){ 9 | this.content=content; 10 | this.isRegex=isRegex; 11 | this.active = active; 12 | } 13 | 14 | public String getContent(){ 15 | return content; 16 | } 17 | 18 | public Boolean getIsRegex(){ 19 | return isRegex; 20 | } 21 | 22 | public Boolean getActive(){ 23 | return active; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/rpm/ui/PayloadTable.java: -------------------------------------------------------------------------------- 1 | package rpm.ui; 2 | 3 | import rpm.controller.ContentController; 4 | 5 | import javax.swing.*; 6 | import javax.swing.table.TableModel; 7 | 8 | class PayloadTable extends JTable { 9 | private final ContentController contentController; 10 | 11 | public PayloadTable(TableModel tableModel, ContentController contentController) { 12 | super(tableModel); 13 | this.contentController = contentController; 14 | } 15 | 16 | @Override 17 | public void changeSelection(int row, int col, boolean toggle, boolean extend) { 18 | // show the log entry for the selected row 19 | contentController.setSelectedPayloadRow(row); 20 | super.changeSelection(row, col, toggle, extend); 21 | } 22 | 23 | public void setDefaultColumnSizes(){ 24 | getColumnModel().getColumn(0).setPreferredWidth(420); 25 | getColumnModel().getColumn(1).setPreferredWidth(80); 26 | getColumnModel().getColumn(2).setPreferredWidth(80); 27 | setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/rpm/ui/CellRenderer.java: -------------------------------------------------------------------------------- 1 | package rpm.ui; 2 | 3 | import rpm.ResultEntry; 4 | 5 | import javax.swing.*; 6 | import javax.swing.table.DefaultTableCellRenderer; 7 | import java.awt.*; 8 | import java.util.List; 9 | 10 | class CellRenderer extends DefaultTableCellRenderer{ 11 | private Color highlightColour; 12 | private List results; 13 | public void setHighlightColor(Color colour){ this.highlightColour=colour; } 14 | public void setResults(Listresults){ this.results = results; } 15 | 16 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){ 17 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 18 | 19 | ResultEntry result = null; 20 | if(results != null)result = results.get(table.convertRowIndexToModel(row)); 21 | 22 | if(result != null && result.getColor() != null){ 23 | c.setBackground(result.getColor()); 24 | }else{ 25 | c.setBackground(table.getBackground());//no highlight 26 | } 27 | 28 | if(isSelected && highlightColour != null)c.setBackground(highlightColour);//Put burp selection highlight defaults back 29 | return c; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/resources/output.json: -------------------------------------------------------------------------------- 1 | [ { 2 | "Number" : 1, 3 | "Tool" : "proxy", 4 | "URL" : "http://test.com", 5 | "HTTP Contents" : { 6 | "Request" : "", 7 | "Response" : "" 8 | }, 9 | "Sample Extract" : "/body> password is welc0me1", 10 | "Payload Content" : "password" 11 | }, { 12 | "Number" : 2, 13 | "Tool" : "proxy", 14 | "URL" : "https://github.com/", 15 | "HTTP Contents" : { 16 | "Request" : "", 17 | "Response" : "" 18 | }, 19 | "Sample Extract" : "/body> username is jack123", 20 | "Payload Content" : "username" 21 | }, { 22 | "Number" : 3, 23 | "Tool" : "proxy", 24 | "URL" : "https://www.lipsum.com/", 25 | "HTTP Contents" : { 26 | "Request" : "", 27 | "Response" : "" 28 | }, 29 | "Sample Extract" : "port:3234", 30 | "Payload Content" : "port" 31 | }, { 32 | "Number" : 4, 33 | "Tool" : "repeater", 34 | "URL" : "http://test2.com", 35 | "HTTP Contents" : { 36 | "Request" : "", 37 | "Response" : "" 38 | }, 39 | "Sample Extract" : "/body> password is welc0me2", 40 | "Payload Content" : "password" 41 | }, { 42 | "Number" : 5, 43 | "Tool" : "proxy", 44 | "URL" : "http://test3.com", 45 | "HTTP Contents" : { 46 | "Request" : "", 47 | "Response" : "" 48 | }, 49 | "Sample Extract" : "asdasdsdfSDFAHtempsdgdg", 50 | "Payload Content" : "temp" 51 | } ] -------------------------------------------------------------------------------- /src/main/java/rpm/controller/ContentController.java: -------------------------------------------------------------------------------- 1 | package rpm.controller; 2 | 3 | import burp.IHttpRequestResponse; 4 | import burp.IHttpRequestResponsePersisted; 5 | import burp.IMessageEditor; 6 | 7 | public class ContentController { 8 | private IHttpRequestResponse currentlyDisplayedItem; 9 | private int selectedPayloadRow; 10 | private IMessageEditor requestViewer; 11 | private IMessageEditor responseViewer; 12 | 13 | public IHttpRequestResponse getCurrentlyDisplayedItem() { 14 | return currentlyDisplayedItem; 15 | } 16 | 17 | public void setCurrentlyDisplayedItem(IHttpRequestResponsePersisted currentlyDisplayedItem) { 18 | this.currentlyDisplayedItem = currentlyDisplayedItem; 19 | } 20 | 21 | public void setSelectedPayloadRow(int selectedPayloadRow) { 22 | this.selectedPayloadRow = selectedPayloadRow; 23 | } 24 | 25 | public int getSelectedPayloadRow() { 26 | return selectedPayloadRow; 27 | } 28 | 29 | public IMessageEditor getRequestViewer() { 30 | return requestViewer; 31 | } 32 | 33 | public void setRequestViewer(IMessageEditor requestViewer) { 34 | this.requestViewer = requestViewer; 35 | } 36 | 37 | public IMessageEditor getResponseViewer() { 38 | return responseViewer; 39 | } 40 | 41 | public void setResponseViewer(IMessageEditor responseViewer) { 42 | this.responseViewer = responseViewer; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/rpm/ui/JHyperlink.java: -------------------------------------------------------------------------------- 1 | package rpm.ui; 2 | 3 | import burp.BurpExtender; 4 | 5 | import java.awt.Desktop; 6 | import java.awt.event.MouseAdapter; 7 | import java.awt.event.MouseEvent; 8 | import java.io.IOException; 9 | import java.net.URI; 10 | import java.net.URISyntaxException; 11 | 12 | import javax.swing.*; 13 | 14 | /** 15 | * A hyperlink component that is based on JLabel. (modified) 16 | * 17 | * @author www.codejava.net 18 | * 19 | */ 20 | public class JHyperlink extends JLabel { 21 | private final String url; 22 | 23 | public JHyperlink(Icon image, String url, String tooltip) { 24 | super(image); 25 | this.url = url; 26 | 27 | setToolTipText(tooltip); 28 | 29 | addMouseListener(new MouseAdapter() { 30 | 31 | @Override 32 | public void mouseClicked(MouseEvent e) { 33 | try { 34 | 35 | Desktop.getDesktop().browse(new URI(JHyperlink.this.url)); 36 | 37 | } catch (IOException | URISyntaxException e1) { 38 | JOptionPane.showMessageDialog(JHyperlink.this, 39 | "Could not open the hyperlink. Error: " + e1.getMessage(), 40 | "Error", 41 | JOptionPane.ERROR_MESSAGE); 42 | } catch (Exception e2){ 43 | BurpExtender.stderror.println("An error occurred creating a JHyperlink:"); 44 | BurpExtender.stderror.println(e2); 45 | e2.printStackTrace(); 46 | } 47 | } 48 | 49 | }); 50 | 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/java/rpm/model/ResultsTableModel.java: -------------------------------------------------------------------------------- 1 | package rpm.model; 2 | 3 | import rpm.ResponsePatternMatcher; 4 | import rpm.ResultEntry; 5 | 6 | import javax.swing.table.AbstractTableModel; 7 | import java.util.List; 8 | 9 | public class ResultsTableModel extends AbstractTableModel { 10 | private final List results; 11 | public ResultsTableModel(List results) { 12 | this.results=results; 13 | } 14 | 15 | @Override 16 | public int getRowCount() { 17 | return results.size(); 18 | } 19 | 20 | @Override 21 | public int getColumnCount() { 22 | return 5; 23 | } 24 | 25 | @Override 26 | public String getColumnName(int columnIndex) { 27 | switch (columnIndex) { 28 | case 0: 29 | return "#"; 30 | case 1: 31 | return "Tool"; 32 | case 2: 33 | return "URL"; 34 | case 3: 35 | return "Payload"; 36 | case 4: 37 | return "Sample Extract"; 38 | default: 39 | return ""; 40 | } 41 | } 42 | 43 | @Override 44 | public Class getColumnClass(int columnIndex) { 45 | if(columnIndex == 0)return Integer.class; 46 | return String.class; 47 | } 48 | 49 | @Override 50 | public Object getValueAt(int rowIndex, int columnIndex) { 51 | if(rowIndex > results.size()) return ""; 52 | ResultEntry resultEntry = results.get(rowIndex); 53 | 54 | switch (columnIndex) { 55 | case 0: 56 | return resultEntry.getNumber(); 57 | case 1: 58 | return ResponsePatternMatcher.callbacks.getToolName(resultEntry.getTool()); 59 | case 2: 60 | return resultEntry.getUrl().toString(); 61 | case 3: 62 | return resultEntry.getPayloadContent(); 63 | case 4: 64 | return resultEntry.getSampleExtract(); 65 | default: 66 | return ""; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/rpm/ResultEntry.java: -------------------------------------------------------------------------------- 1 | package rpm; 2 | 3 | import burp.IHttpRequestResponsePersisted; 4 | 5 | import java.awt.*; 6 | import java.net.URL; 7 | 8 | public class ResultEntry { 9 | //Needs to be in serializable (Setter getter) format for Jackson json parser 10 | private int number; 11 | private int tool; 12 | private URL url; 13 | private IHttpRequestResponsePersisted requestResponse; 14 | private String sampleExtract; 15 | private String payloadContent; 16 | private Color color; 17 | 18 | public ResultEntry(int number, int tool, URL url, IHttpRequestResponsePersisted requestResponse, 19 | String sampleExtract, String payloadContent) { 20 | this.number = number; 21 | this.tool = tool; 22 | this.url = url; 23 | this.requestResponse = requestResponse; 24 | this.sampleExtract = sampleExtract; 25 | this.payloadContent = payloadContent; 26 | } 27 | 28 | public int getNumber() { 29 | return number; 30 | } 31 | 32 | public void setNumber(int number) { 33 | this.number = number; 34 | } 35 | 36 | public int getTool() { 37 | return tool; 38 | } 39 | 40 | public void setTool(int tool) { 41 | this.tool = tool; 42 | } 43 | 44 | public URL getUrl() { 45 | return url; 46 | } 47 | 48 | public void setUrl(URL url) { 49 | this.url = url; 50 | } 51 | 52 | public IHttpRequestResponsePersisted getRequestResponse() { 53 | return requestResponse; 54 | } 55 | 56 | public void setRequestResponse(IHttpRequestResponsePersisted requestResponse) { 57 | this.requestResponse = requestResponse; 58 | } 59 | 60 | public String getSampleExtract() { 61 | return sampleExtract; 62 | } 63 | 64 | public void setSampleExtract(String sampleExtract) { 65 | this.sampleExtract = sampleExtract; 66 | } 67 | 68 | public String getPayloadContent() { 69 | return payloadContent; 70 | } 71 | 72 | public void setPayloadContent(String payloadContent) { 73 | this.payloadContent = payloadContent; 74 | } 75 | 76 | public Color getColor() { 77 | return color; 78 | } 79 | 80 | public void setColor(Color color) { 81 | this.color = color; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/rpm/ui/JSONParser.java: -------------------------------------------------------------------------------- 1 | package rpm.ui; 2 | 3 | import burp.BurpExtender; 4 | import burp.IBurpExtenderCallbacks; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.node.ArrayNode; 7 | import com.fasterxml.jackson.databind.node.ObjectNode; 8 | import rpm.ResultEntry; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.util.ArrayList; 13 | 14 | public class JSONParser { 15 | ObjectMapper mapper; 16 | IBurpExtenderCallbacks callbacks; 17 | 18 | public JSONParser(IBurpExtenderCallbacks callbacks){ 19 | mapper = new ObjectMapper(); 20 | this.callbacks = callbacks; //so you can pass in mock for testing 21 | } 22 | 23 | public void writeResultsToFile(File file, ArrayListresults){ 24 | try { 25 | ArrayNode rootNode = mapper.createArrayNode(); 26 | for (ResultEntry result : results){ 27 | ObjectNode resultObject = mapper.createObjectNode(); 28 | 29 | resultObject.put("Number", result.getNumber()); 30 | resultObject.put("Tool", callbacks.getToolName(result.getTool())); 31 | resultObject.put("URL", result.getUrl().toString()); 32 | 33 | ObjectNode requestResponse = mapper.createObjectNode(); 34 | requestResponse.put("Request", new String(result.getRequestResponse().getRequest())); 35 | requestResponse.put("Response", new String(result.getRequestResponse().getResponse())); 36 | resultObject.set("HTTP Contents", requestResponse); 37 | 38 | resultObject.put("Sample Extract", result.getSampleExtract()); 39 | resultObject.put("Payload Content", result.getPayloadContent()); 40 | 41 | rootNode.add(resultObject); 42 | } 43 | //Pretty print to file 44 | mapper.writerWithDefaultPrettyPrinter().writeValue(file, rootNode); 45 | }catch (IOException ex){ 46 | BurpExtender.stderror.println("An exception occurred when exporting results to file:"); 47 | BurpExtender.stderror.println(ex); 48 | ex.printStackTrace(); 49 | } catch (Exception e2){ 50 | BurpExtender.stderror.println("An error occurred parsing JSON:"); 51 | BurpExtender.stderror.println(e2); 52 | e2.printStackTrace(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Response Pattern Matcher 2 | Adds extensibility to Burp by using a list of payloads to pattern match on HTTP responses highlighting interesting and potentially vulnerable areas. Can be used to search HTML source code for interesting keywords, developer comments, passwords, admin panel links, hidden form fields, and more. 3 | 4 | # Usage 5 | The .jar file is available in the /releases directory, this can be loaded in through Burp Extender. 6 |
    7 |
  1. When the extension is loaded in you will see a Response Pattern Matcher tab, by default pre-existing payloads exist that will be pattern matched against every response that goes through Burp. This includes tools such as the Scanner.
  2. 8 |
  3. Configure these payloads accordingly, these are quite generic so for an assessment you may want to add project specific keywords and regular expressions.
  4. 9 |
  5. The is regex check box indicates whether to search the responses for the provided Pattern using Java's Pattern Matcher functionality. A good example is available below.
  6. 10 |
  7. The active check box indicates whether the payload will be used. Uncheck this to disable the payload.
  8. 11 |
  9. Use the "In Scope Only" checkbox to search only within responses that are in Scope defined under Target > Scope.
  10. 12 |
  11. Use the config tab to choose whether to match on Requests and or Responses. Matches against either of these are available under the Matches tab.
  12. 13 |
  13. For best results, define your scope, configure your payloads, and then start testing. Burp's Scanner will kick in and push everything through the Response Pattern Matcher too so the tool searches the full sitemap.
  14. 14 |
  15. If you want to test the matches against a request or response again you can send the item to repeater from the HTTP history in Burp.
  16. 15 |
  17. Note /* cannot be set to be regex, this will most likely crash burp as it matches on everything.
  18. 16 |
17 | 18 | [Java regex tutorial](http://vogella.com/tutorials/JavaRegularExpressions/article.html) 19 | 20 | # Matches 21 | As of v2.0 additional functionality has been added to organise matches.
22 | If you highlight items in the Matches tab you can highlight identical matches, as well as delete and export them to a .json file. 23 | 24 | # Requirements 25 | Built using: 26 | - Oracle OpenJDK 17.0.8 27 | - burp-extender-api (2.3) 28 | - Tested on Burp Community Edition 2023.7.1 29 | 30 | # Acknowledgements 31 | Author: Jack Jarvis, Bridewell
32 | Developed using IntelliJ IDE and the Gradle Build Tool. 33 |

34 | CoreyD97 Burp Extender Utilities:
35 | https://github.com/CoreyD97/BurpExtenderUtilities 36 |

37 | For further Burp Extension development please refer to:
38 | https://portswigger.net/burp/documentation/desktop/extensions
-------------------------------------------------------------------------------- /src/main/java/rpm/ResponsePatternMatcher.java: -------------------------------------------------------------------------------- 1 | package rpm; 2 | 3 | import burp.*; 4 | 5 | import rpm.controller.ContentController; 6 | 7 | import rpm.ui.GUI; 8 | import java.awt.*; 9 | import java.io.*; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | public class ResponsePatternMatcher implements IBurpExtender, ITab, IHttpListener, 14 | IMessageEditorController, IExtensionStateListener { 15 | //Static Burp objects 16 | public static IBurpExtenderCallbacks callbacks; 17 | public static IExtensionHelpers helpers; 18 | public static PrintWriter stdout; 19 | public static PrintWriter stderror; 20 | 21 | //Threading 22 | private ExecutorService service; 23 | 24 | //UI 25 | GUI gui; 26 | 27 | //Controller 28 | private ContentController contentController; 29 | 30 | // 31 | // implement IBurpExtender 32 | // 33 | @Override 34 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks){ 35 | service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 36 | contentController = new ContentController(); 37 | 38 | // keep a reference to our callbacks object 39 | ResponsePatternMatcher.callbacks = callbacks; 40 | 41 | //Terminal Output 42 | stdout = new PrintWriter(callbacks.getStdout(), true); 43 | stderror = new PrintWriter(callbacks.getStderr(), true); 44 | 45 | // obtain an extension helpers object 46 | helpers = callbacks.getHelpers(); 47 | 48 | // set our extension name 49 | callbacks.setExtensionName("Response Pattern Matcher"); 50 | 51 | //Set up the GUI 52 | gui = new GUI(contentController, this); 53 | gui.initialise(); 54 | } 55 | 56 | // 57 | // implement ITab 58 | // 59 | @Override 60 | public String getTabCaption(){ 61 | return "Response Pattern Matcher"; 62 | } 63 | 64 | @Override 65 | public Component getUiComponent(){ 66 | return gui.getTabs_outer(); 67 | } 68 | 69 | // 70 | // implement IHttpListener 71 | // 72 | @Override 73 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo){ 74 | service.execute(new MessageProcessor(toolFlag, messageIsRequest, messageInfo, gui)); 75 | } 76 | 77 | // 78 | // implement IMessageEditorController 79 | // 80 | @Override 81 | public byte[] getRequest() { 82 | return contentController.getCurrentlyDisplayedItem().getRequest(); 83 | } 84 | 85 | @Override 86 | public byte[] getResponse() { 87 | return contentController.getCurrentlyDisplayedItem().getResponse(); 88 | } 89 | 90 | @Override 91 | public IHttpService getHttpService() { 92 | return contentController.getCurrentlyDisplayedItem().getHttpService(); 93 | } 94 | 95 | @Override 96 | public void extensionUnloaded() { 97 | //Close Thread Pool 98 | service.shutdownNow(); 99 | stdout.println("Extension Unloaded Successfully"); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto init 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto init 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/java/rpm/model/PayloadsTableModel.java: -------------------------------------------------------------------------------- 1 | package rpm.model; 2 | 3 | import rpm.Payload; 4 | import com.coreyd97.BurpExtenderUtilities.Preferences; 5 | 6 | import javax.swing.table.AbstractTableModel; 7 | import java.util.List; 8 | 9 | public class PayloadsTableModel extends AbstractTableModel { 10 | 11 | private final List payloads; 12 | private final Preferences prefs; 13 | public PayloadsTableModel(List payloads, Preferences prefs){ 14 | this.payloads = payloads; 15 | this.prefs = prefs; 16 | } 17 | 18 | @Override 19 | public int getRowCount() { 20 | return payloads.size(); 21 | } 22 | 23 | @Override 24 | public int getColumnCount() { return 3; } 25 | 26 | @Override 27 | public String getColumnName(int columnIndex) 28 | { 29 | switch (columnIndex) 30 | { 31 | case 0: 32 | return "Payload"; 33 | case 1: 34 | return "Is Regex"; 35 | case 2: 36 | return "Active"; 37 | default: 38 | return ""; 39 | } 40 | } 41 | 42 | @Override 43 | public Class getColumnClass(int columnIndex) 44 | { 45 | switch(columnIndex){ 46 | case 0: 47 | return String.class; 48 | case 1: 49 | return Boolean.class; 50 | case 2: 51 | return Boolean.class; 52 | default: 53 | return String.class; 54 | } 55 | } 56 | 57 | @Override 58 | public boolean isCellEditable(int row, int col) { 59 | if (col == 1) { 60 | return !payloads.get(row).getContent().equals("/*"); 61 | } else return col == 2; 62 | } 63 | 64 | @Override 65 | public Object getValueAt(int rowIndex, int columnIndex) { 66 | switch(columnIndex) { 67 | case 0: 68 | return payloads.get(rowIndex).getContent(); 69 | case 1: 70 | return payloads.get(rowIndex).getIsRegex(); 71 | case 2: 72 | return payloads.get(rowIndex).getActive(); 73 | default: 74 | return payloads.get(rowIndex).getContent(); 75 | } 76 | } 77 | 78 | @Override 79 | public void setValueAt(Object value, int row, int col) { 80 | if(row > payloads.size())return; 81 | super.setValueAt(value, row, col); 82 | 83 | if (col == 1) { 84 | if ((Boolean) this.getValueAt(row, col)) { 85 | payloads.set(row, new Payload(payloads.get(row).getContent(),false, payloads.get(row).getActive())); 86 | prefs.setSetting("Payloads", payloads); 87 | } 88 | else if (!(Boolean) this.getValueAt(row, col)) { 89 | payloads.set(row, new Payload(payloads.get(row).getContent(),true, payloads.get(row).getActive())); 90 | prefs.setSetting("Payloads", payloads); 91 | } 92 | } 93 | 94 | if (col == 2){ 95 | if ((Boolean) this.getValueAt(row, col)) { 96 | payloads.set(row, new Payload(payloads.get(row).getContent(), payloads.get(row).getIsRegex(), false)); 97 | prefs.setSetting("Payloads", payloads); 98 | } 99 | else if (!(Boolean) this.getValueAt(row, col)) { 100 | payloads.set(row, new Payload(payloads.get(row).getContent(), payloads.get(row).getIsRegex(), true)); 101 | prefs.setSetting("Payloads", payloads); 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/java/burp/ResultsTableModelTests.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import rpm.Payload; 5 | import rpm.ResultEntry; 6 | import rpm.model.ResultsTableModel; 7 | 8 | import java.net.URL; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.List; 12 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; 14 | import static org.junit.jupiter.api.Assertions.assertNull; 15 | 16 | public class ResultsTableModelTests { 17 | @Test 18 | void resultsTableModel_getValueAtMethodReturnsCorrectItem(){ 19 | Exception ex = null; 20 | 21 | try { 22 | ResultEntry result1 = new ResultEntry(1, 1, new URL("http://test.com"), requestResponsePersisted, "/body> password is welc0me1", "password"); 23 | ResultEntry result2 = new ResultEntry(2, 1, new URL("https://github.com/"), requestResponsePersisted, "/body> username is jack123", "username"); 24 | ResultEntry result3 = new ResultEntry(3, 2, new URL("https://www.lipsum.com/"), requestResponsePersisted, "port:3234", "port"); 25 | ResultEntry result4 = new ResultEntry(4, 3, new URL("http://test2.com"), requestResponsePersisted, "/body> password is welc0me2", "password"); 26 | ResultEntry result5 = new ResultEntry(5, 1, new URL("http://test3.com"), requestResponsePersisted, "asdasdsdfSDFAHtempsdgdg", "temp"); 27 | 28 | ArrayList results = new ArrayList<>(Arrays.asList(result1, result2, result3, result4, result5)); 29 | 30 | ResultsTableModel resultsTableModelTableModel = new ResultsTableModel(results); 31 | 32 | assertEquals(1, resultsTableModelTableModel.getValueAt(0,0)); 33 | assertEquals("https://github.com/", resultsTableModelTableModel.getValueAt(1,2).toString()); 34 | assertEquals("port", resultsTableModelTableModel.getValueAt(2,3)); 35 | assertEquals("/body> password is welc0me2", resultsTableModelTableModel.getValueAt(3,4)); 36 | }catch (Exception e){ 37 | ex = e; 38 | } 39 | 40 | assertNull(ex); 41 | } 42 | 43 | private final IHttpRequestResponsePersisted requestResponsePersisted = new IHttpRequestResponsePersisted() { 44 | @Override 45 | public void deleteTempFiles() { 46 | 47 | } 48 | 49 | @Override 50 | public byte[] getRequest() { 51 | return new byte[0]; 52 | } 53 | 54 | @Override 55 | public void setRequest(byte[] bytes) { 56 | 57 | } 58 | 59 | @Override 60 | public byte[] getResponse() { 61 | return new byte[0]; 62 | } 63 | 64 | @Override 65 | public void setResponse(byte[] bytes) { 66 | 67 | } 68 | 69 | @Override 70 | public String getComment() { 71 | return "Test Comment"; 72 | } 73 | 74 | @Override 75 | public void setComment(String s) { 76 | 77 | } 78 | 79 | @Override 80 | public String getHighlight() { 81 | return null; 82 | } 83 | 84 | @Override 85 | public void setHighlight(String s) { 86 | 87 | } 88 | 89 | @Override 90 | public IHttpService getHttpService() { 91 | return null; 92 | } 93 | 94 | @Override 95 | public void setHttpService(IHttpService iHttpService) { 96 | 97 | } 98 | 99 | @Override 100 | public String getHost() { 101 | return null; 102 | } 103 | 104 | @Override 105 | public int getPort() { 106 | return 0; 107 | } 108 | 109 | @Override 110 | public String getProtocol() { 111 | return null; 112 | } 113 | 114 | @Override 115 | public void setHost(String s) { 116 | 117 | } 118 | 119 | @Override 120 | public void setPort(int i) { 121 | 122 | } 123 | 124 | @Override 125 | public void setProtocol(String s) { 126 | 127 | } 128 | 129 | @Override 130 | public URL getUrl() { 131 | return null; 132 | } 133 | 134 | @Override 135 | public short getStatusCode() { 136 | return 0; 137 | } 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/rpm/ui/ResultTable.java: -------------------------------------------------------------------------------- 1 | package rpm.ui; 2 | 3 | import burp.*; 4 | import rpm.ResultEntry; 5 | import rpm.controller.ContentController; 6 | 7 | import javax.swing.*; 8 | import javax.swing.table.TableModel; 9 | import java.awt.event.InputEvent; 10 | import java.awt.event.MouseAdapter; 11 | import java.awt.event.MouseEvent; 12 | import java.util.List; 13 | 14 | class ResultTable extends JTable { 15 | ExtenderPopupMenu menu; 16 | CellRenderer cellRenderer = new CellRenderer(); 17 | 18 | @SuppressWarnings("deprecation") 19 | public ResultTable(TableModel tableModel, List results, ContentController contentController) { 20 | super(tableModel); 21 | this.setAutoCreateRowSorter(true); 22 | this.setDefaultRenderer(Object.class, cellRenderer); 23 | this.setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION); 24 | menu = new ExtenderPopupMenu(tableModel, this, results, cellRenderer); 25 | DefaultListSelectionModel selectionModel = new DefaultListSelectionModel() { 26 | @Override 27 | public void setSelectionInterval(int index0, int index1) { 28 | try { 29 | super.setSelectionInterval(index0, index1); 30 | // Set currently displayed item for the selected row 31 | if (index0 > results.size()) return; //try to prevent null pointers 32 | ResultEntry resultsEntry = results.get(convertRowIndexToModel(index0)); 33 | IHttpRequestResponsePersisted requestResponsePersisted = resultsEntry.getRequestResponse(); 34 | 35 | //This guard is required because responseViewer.setMessage() is very resource intensive and causes Burp to slow down a lot on huge responses 36 | if (contentController.getCurrentlyDisplayedItem() == null || contentController.getCurrentlyDisplayedItem() != requestResponsePersisted 37 | || contentController.getRequestViewer().getMessage().length == 0) { 38 | contentController.getRequestViewer().setMessage(requestResponsePersisted.getRequest(), true); 39 | 40 | //The response sometimes doesn't exist for some requests. Guard here to prevent null pointer 41 | if (requestResponsePersisted.getResponse() != null) { 42 | contentController.getResponseViewer().setMessage(requestResponsePersisted.getResponse(), false); 43 | } else { 44 | contentController.getResponseViewer().setMessage(new byte[0], false); 45 | } 46 | 47 | contentController.setCurrentlyDisplayedItem(requestResponsePersisted); 48 | } 49 | } catch (NullPointerException e1) { //debugging breakpoints 50 | BurpExtender.stderror.println("A null pointer exception occurred in the result table:"); 51 | BurpExtender.stderror.println(e1); 52 | e1.printStackTrace(); 53 | } catch (Exception e2) { 54 | BurpExtender.stderror.println("A exception occurred in the result table:"); 55 | BurpExtender.stderror.println(e2); 56 | e2.printStackTrace(); 57 | } 58 | } 59 | }; 60 | this.setSelectionModel(selectionModel); 61 | 62 | this.addMouseListener(new MouseAdapter() { 63 | @Override 64 | public void mouseClicked(MouseEvent e) { 65 | int rowIndex = getSelectedRow(); 66 | if (rowIndex < 0) 67 | return; 68 | if (isRightClick(e)) { 69 | menu.show(e.getComponent(), e.getX(), e.getY()); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | private static boolean isRightClick(MouseEvent e) { 76 | return (SwingUtilities.isRightMouseButton(e) || 77 | e.getButton() == MouseEvent.BUTTON3 || 78 | (System.getProperty("os.name").contains("Mac OS X") && 79 | (e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 && 80 | (e.getModifiers() & InputEvent.CTRL_MASK) != 0)); 81 | } 82 | 83 | public void setDefaultColumnSizes(){ 84 | getColumnModel().getColumn(0).setPreferredWidth(5); 85 | getColumnModel().getColumn(1).setPreferredWidth(20); 86 | getColumnModel().getColumn(2).setPreferredWidth(400); 87 | getColumnModel().getColumn(3).setPreferredWidth(30); 88 | getColumnModel().getColumn(4).setPreferredWidth(600); 89 | setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); 90 | } 91 | } -------------------------------------------------------------------------------- /src/test/java/burp/JSONParserTests.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import rpm.ResultEntry; 5 | import rpm.ui.JSONParser; 6 | 7 | import java.io.File; 8 | import java.net.URL; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | 12 | import static org.junit.jupiter.api.Assertions.assertNull; 13 | import static org.mockito.Mockito.mock; 14 | import static org.mockito.Mockito.when; 15 | 16 | class JSONParserTests { 17 | @Test 18 | void JacksonParserTest(){ 19 | //Jackson test to make sure sample results are printed to a local json file correctly 20 | Exception ex = null; 21 | try { 22 | ResultEntry result1 = new ResultEntry(1, 1, new URL("http://test.com"), requestResponsePersisted, "/body> password is welc0me1", "password"); 23 | ResultEntry result2 = new ResultEntry(2, 1, new URL("https://github.com/"), requestResponsePersisted, "/body> username is jack123", "username"); 24 | ResultEntry result3 = new ResultEntry(3, 2, new URL("https://www.lipsum.com/"), requestResponsePersisted, "port:3234", "port"); 25 | ResultEntry result4 = new ResultEntry(4, 3, new URL("http://test2.com"), requestResponsePersisted, "/body> password is welc0me2", "password"); 26 | ResultEntry result5 = new ResultEntry(5, 1, new URL("http://test3.com"), requestResponsePersisted, "asdasdsdfSDFAHtempsdgdg", "temp"); 27 | 28 | File output = new File("Z:\\Projects\\GitProjects_Working\\Response Pattern Matcher\\out\\test\\resources\\output.json"); 29 | //File output = new File("/Users/benson/Response-Pattern-Matcher/src/test/resources/output.json"); 30 | 31 | ArrayList results = new ArrayList<>(Arrays.asList(result1, result2, result3, result4, result5)); 32 | 33 | IBurpExtenderCallbacks mockCallbacks = mock(IBurpExtenderCallbacks.class); 34 | 35 | JSONParser parser = new JSONParser(mockCallbacks); 36 | 37 | when(mockCallbacks.getToolName(result1.getTool())).thenReturn("intruder"); 38 | when(mockCallbacks.getToolName(result2.getTool())).thenReturn("intruder"); 39 | when(mockCallbacks.getToolName(result3.getTool())).thenReturn("proxy"); 40 | when(mockCallbacks.getToolName(result4.getTool())).thenReturn("repeater"); 41 | when(mockCallbacks.getToolName(result5.getTool())).thenReturn("proxy"); 42 | 43 | parser.writeResultsToFile(output, results); 44 | } catch (Exception e) { 45 | ex = e; 46 | } 47 | 48 | assertNull(ex); 49 | } 50 | 51 | private final IHttpRequestResponsePersisted requestResponsePersisted = new IHttpRequestResponsePersisted() { 52 | @Override 53 | public void deleteTempFiles() { 54 | 55 | } 56 | 57 | @Override 58 | public byte[] getRequest() { 59 | return new byte[0]; 60 | } 61 | 62 | @Override 63 | public void setRequest(byte[] bytes) { 64 | 65 | } 66 | 67 | @Override 68 | public byte[] getResponse() { 69 | return new byte[0]; 70 | } 71 | 72 | @Override 73 | public void setResponse(byte[] bytes) { 74 | 75 | } 76 | 77 | @Override 78 | public String getComment() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public void setComment(String s) { 84 | 85 | } 86 | 87 | @Override 88 | public String getHighlight() { 89 | return null; 90 | } 91 | 92 | @Override 93 | public void setHighlight(String s) { 94 | 95 | } 96 | 97 | @Override 98 | public IHttpService getHttpService() { 99 | return null; 100 | } 101 | 102 | @Override 103 | public void setHttpService(IHttpService iHttpService) { 104 | 105 | } 106 | 107 | @Override 108 | public String getHost() { 109 | return null; 110 | } 111 | 112 | @Override 113 | public int getPort() { 114 | return 0; 115 | } 116 | 117 | @Override 118 | public String getProtocol() { 119 | return null; 120 | } 121 | 122 | @Override 123 | public void setHost(String s) { 124 | 125 | } 126 | 127 | @Override 128 | public void setPort(int i) { 129 | 130 | } 131 | 132 | @Override 133 | public void setProtocol(String s) { 134 | 135 | } 136 | 137 | @Override 138 | public URL getUrl() { 139 | return null; 140 | } 141 | 142 | @Override 143 | public short getStatusCode() { 144 | return 0; 145 | } 146 | }; 147 | } 148 | -------------------------------------------------------------------------------- /src/test/java/burp/PayloadsTableModelTests.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import com.coreyd97.BurpExtenderUtilities.Preferences; 4 | import org.junit.jupiter.api.Test; 5 | import org.mockito.Mockito; 6 | import rpm.Payload; 7 | import rpm.model.PayloadsTableModel; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import static org.junit.jupiter.api.Assertions.*; 13 | import static org.junit.jupiter.api.Assertions.assertFalse; 14 | import static org.mockito.Mockito.*; 15 | 16 | public class PayloadsTableModelTests { 17 | 18 | @Test 19 | void payloadTableModel_payloadContentForwardSlashStarCannotBeSetToTrueForIsRegex(){ 20 | List payloads = new ArrayList(); 21 | payloads.add(new Payload("admin", false, true)); 22 | payloads.add(new Payload("password", false, true)); 23 | payloads.add(new Payload("passcode", false, true)); 24 | payloads.add(new Payload("port.{0,7}\\d+", true, true)); 25 | payloads.add(new Payload("sql", false, true)); 26 | payloads.add(new Payload("