├── README.md ├── images ├── BreakpointList.png └── contextMenu.png ├── pom.xml └── src ├── burp └── BurpExtender.java └── main └── java └── com └── staticflow ├── BorContextMenu.java ├── BorExtensionUI.form ├── BorExtensionUI.java ├── BorProxyListener.java ├── BreakOnRequestExtension.java └── ExtensionState.java /README.md: -------------------------------------------------------------------------------- 1 | # BOR - Break On Request 2 | BOR is a Burp Suite extension that provides a custom context menu for marking requests to be stopped by the interceptor. 3 | 4 | The Burp Suite Proxy Interceptor is a handy tool for catching important/interesting requests for tampering before they are sent to a target. 5 | When deciding what to intercept you have two options: 6 | 7 | A) turn on the global intercept and continuely click "Forward" until you reach the request you want. 8 | 9 | 10 | B) Setup intecept rules in the Proxy Options tab. 11 | 12 | Both have downsides, in the case of option A, it can become very tedious with applications that send a lot of requests and your target request is not first, 13 | and option B requires hand crafting match rules to ensure you only intercept the request you want. 14 | 15 | 16 | With BOR the only step required to mark a request for interception is a right click on the request and selecting the `Create Breakpoint For Request` context menu! 17 | 18 | # UI Examples 19 | 20 | ## Context Menu 21 | ![Context Menu](/images/contextMenu.png?raw=true) 22 | 23 | 24 | ## Breakpoint List 25 | ![Context Menu](/images/BreakpointList.png?raw=true) 26 | 27 | ## Potential Next Features 28 | - [ ] Other interception breakpoint format such as regex, headers, etc 29 | - [ ] Breakpoints for Responses 30 | 31 | 32 | ### Thanks to Weedon for the suggestion to make this! 33 | -------------------------------------------------------------------------------- /images/BreakpointList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Static-Flow/BOR/7128fa15a59eb4035ff15c535c89d4987a971578/images/BreakpointList.png -------------------------------------------------------------------------------- /images/contextMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Static-Flow/BOR/7128fa15a59eb4035ff15c535c89d4987a971578/images/contextMenu.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.staticflow 8 | BOR 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | net.portswigger.burp.extender 14 | burp-extender-api 15 | 2.3 16 | 17 | 18 | 19 | 20 | 21 | ${project.basedir}/src/main/java 22 | BOR 23 | 24 | 25 | 26 | org.codehaus.mojo 27 | build-helper-maven-plugin 28 | 3.2.0 29 | 30 | 31 | generate-sources 32 | 33 | add-source 34 | 35 | 36 | 37 | src/burp 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-eclipse-plugin 47 | 2.9 48 | 49 | true 50 | false 51 | 52 | 53 | 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-compiler-plugin 58 | 2.3.2 59 | 60 | 1.8 61 | 1.8 62 | 63 | 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-assembly-plugin 69 | 2.4.1 70 | 71 | 72 | false 73 | 74 | jar-with-dependencies 75 | 76 | 77 | 78 | 79 | 80 | make-assembly 81 | 82 | package 83 | 84 | single 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | 4 | import com.staticflow.BreakOnRequestExtension; 5 | 6 | 7 | /** 8 | * This is required by Burp Extensions. Extension code is in {@link BreakOnRequestExtension} 9 | */ 10 | public class BurpExtender extends BreakOnRequestExtension { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/BorContextMenu.java: -------------------------------------------------------------------------------- 1 | package com.staticflow; 2 | 3 | import burp.IContextMenuFactory; 4 | import burp.IContextMenuInvocation; 5 | import burp.IHttpRequestResponse; 6 | 7 | import javax.swing.*; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | 12 | /** 13 | * Custom context menu where one click breakpoints are made. When clicked it generates the URL for the request and adds 14 | * it as a new interception breakpoint. 15 | */ 16 | public class BorContextMenu implements IContextMenuFactory { 17 | 18 | @Override 19 | public List createMenuItems(IContextMenuInvocation iContextMenuInvocation) { 20 | //check if this extension should display the custom context menu 21 | if (ExtensionState.getInstance().shouldShowMenu(iContextMenuInvocation.getInvocationContext())) { 22 | //make the new menu 23 | JMenuItem menu = new JMenuItem("Create Breakpoint For Request"); 24 | menu.addActionListener(e -> { 25 | //for every message selected 26 | for(IHttpRequestResponse message : iContextMenuInvocation.getSelectedMessages()) { 27 | //convert IHttpRequestResponse to URL string 28 | String potentialBreakpoint = ExtensionState.getInstance().convertToBreakpoint(message); 29 | //if this url is not already a breakpoint 30 | if( !ExtensionState.getInstance().getBreakpoints().contains(potentialBreakpoint) ) 31 | //add it to the list of breakpoints 32 | ExtensionState.getInstance().getBreakpoints().addElement(potentialBreakpoint); 33 | else 34 | //else alert user they tried to to add a breakpoint twice 35 | JOptionPane.showMessageDialog(ExtensionState.getInstance().getBorExtensionUI(), 36 | "Breakpoint for URL: "+potentialBreakpoint+ " already exists."); 37 | } 38 | }); 39 | return Collections.singletonList(menu); 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/BorExtensionUI.form: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/BorExtensionUI.java: -------------------------------------------------------------------------------- 1 | package com.staticflow; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | 6 | /** 7 | * Custom UI for the `BOR` extension 8 | */ 9 | public class BorExtensionUI extends JPanel { 10 | private JPanel mainPanel; 11 | private JList breakpointList; 12 | private JScrollPane breakpointScrollPane; 13 | private JButton deleteSelectedBreakpointsButton; 14 | 15 | 16 | { 17 | // GUI initializer generated by IntelliJ IDEA GUI Designer 18 | // >>> IMPORTANT!! <<< 19 | // DO NOT EDIT OR ADD ANY CODE HERE! 20 | $$$setupUI$$$(); 21 | } 22 | 23 | /** 24 | * Method generated by IntelliJ IDEA GUI Designer 25 | * >>> IMPORTANT!! <<< 26 | * DO NOT edit this method OR call it in your code! 27 | * 28 | * @noinspection ALL 29 | */ 30 | private void $$$setupUI$$$() { 31 | createUIComponents(); 32 | mainPanel.setLayout(new BorderLayout(0, 0)); 33 | mainPanel.setMinimumSize(new Dimension(800, 500)); 34 | mainPanel.setPreferredSize(new Dimension(800, 500)); 35 | deleteSelectedBreakpointsButton.setText("Delete Selected Breakpoints"); 36 | mainPanel.add(deleteSelectedBreakpointsButton, BorderLayout.NORTH); 37 | breakpointScrollPane = new JScrollPane(); 38 | mainPanel.add(breakpointScrollPane, BorderLayout.CENTER); 39 | breakpointScrollPane.setViewportView(breakpointList); 40 | } 41 | 42 | /** 43 | * @noinspection ALL 44 | */ 45 | public JComponent $$$getRootComponent$$$() { 46 | return mainPanel; 47 | } 48 | 49 | public JList getBreakpointList() { 50 | return breakpointList; 51 | } 52 | 53 | private void createUIComponents() { 54 | mainPanel = new JPanel(); 55 | deleteSelectedBreakpointsButton = new JButton(); 56 | deleteSelectedBreakpointsButton.addActionListener(e -> { 57 | int index = breakpointList.getSelectedIndices().length - 1; 58 | 59 | while (breakpointList.getSelectedIndices().length != 0) { 60 | ExtensionState.getInstance().getBreakpoints().removeElementAt(breakpointList.getSelectedIndices()[index--]); 61 | } 62 | }); 63 | breakpointList = new JList<>(); 64 | add(mainPanel); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/BorProxyListener.java: -------------------------------------------------------------------------------- 1 | package com.staticflow; 2 | 3 | import burp.IInterceptedProxyMessage; 4 | import burp.IProxyListener; 5 | 6 | /** 7 | * Custom proxy listener that sends every outgoing request that matches a breakpoint to the Interceptor for modification 8 | */ 9 | public class BorProxyListener implements IProxyListener { 10 | @Override 11 | public void processProxyMessage(boolean isRequest, IInterceptedProxyMessage iInterceptedProxyMessage) { 12 | //if proxy message is request 13 | if (isRequest) { 14 | //and the current list of breakpoints contains the request url 15 | if (ExtensionState.getInstance().getBreakpoints().contains( 16 | ExtensionState.getInstance().convertToBreakpoint(iInterceptedProxyMessage.getMessageInfo()) 17 | )) { 18 | //mark it for interception 19 | iInterceptedProxyMessage.setInterceptAction(IInterceptedProxyMessage.ACTION_DO_INTERCEPT); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/BreakOnRequestExtension.java: -------------------------------------------------------------------------------- 1 | package com.staticflow; 2 | 3 | import burp.IBurpExtender; 4 | import burp.IBurpExtenderCallbacks; 5 | import burp.IExtensionStateListener; 6 | import burp.ITab; 7 | 8 | import java.awt.*; 9 | 10 | 11 | /** 12 | * This extension provides a custom context menu for adding interception "breakpoints" for URLs. 13 | * The context menus work on any request viewer, i.e. Repeater/Proxy/SiteMap. Current breakpoints 14 | * are listed in the custom UI tab `BOR`. 15 | */ 16 | public class BreakOnRequestExtension implements IBurpExtender, IExtensionStateListener, ITab { 17 | 18 | /* 19 | Register all the custom handlers with Burp 20 | */ 21 | @Override 22 | public void registerExtenderCallbacks(IBurpExtenderCallbacks iBurpExtenderCallbacks) { 23 | ExtensionState.getInstance().setCallbacks(iBurpExtenderCallbacks); 24 | iBurpExtenderCallbacks.registerProxyListener(ExtensionState.getInstance().getProxyListener()); 25 | iBurpExtenderCallbacks.registerContextMenuFactory(ExtensionState.getInstance().getContextMenu()); 26 | iBurpExtenderCallbacks.addSuiteTab(this); 27 | iBurpExtenderCallbacks.setExtensionName("BOR - Break On Request"); 28 | } 29 | 30 | /* 31 | Always clean up after yourself 32 | */ 33 | @Override 34 | public void extensionUnloaded() { 35 | ExtensionState.getInstance().getCallbacks().removeProxyListener(ExtensionState.getInstance().getProxyListener()); 36 | ExtensionState.getInstance().getCallbacks().removeContextMenuFactory(ExtensionState.getInstance().getContextMenu()); 37 | } 38 | 39 | @Override 40 | public String getTabCaption() { 41 | return "BOR"; 42 | } 43 | 44 | @Override 45 | public Component getUiComponent() { 46 | return ExtensionState.getInstance().getBorExtensionUI(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/staticflow/ExtensionState.java: -------------------------------------------------------------------------------- 1 | package com.staticflow; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IContextMenuInvocation; 5 | import burp.IHttpRequestResponse; 6 | import burp.IRequestInfo; 7 | 8 | import javax.swing.*; 9 | 10 | /** 11 | * Singleton class for holding the state of the Extension. 12 | */ 13 | public class ExtensionState { 14 | 15 | //The singleton 16 | private static ExtensionState state = null; 17 | //The Burp Suite Callback functions 18 | private IBurpExtenderCallbacks callbacks; 19 | // bit vector for the contexts in which this extension should show the custom menu 20 | private static int validContextMenuBitVector = 21 | 1<< IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST | 22 | 1<< IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_REQUEST; 23 | // custom proxy listener to catch requests that match any of the current breakpoints 24 | private BorProxyListener proxyListener; 25 | // custom context menu 26 | private BorContextMenu contextMenu; 27 | // list model that holds user generated breakpoints 28 | private DefaultListModel breakpoints; 29 | // custom ui 30 | private BorExtensionUI borExtensionUI; 31 | 32 | /* 33 | Initialize Extension State 34 | */ 35 | private ExtensionState() { 36 | breakpoints = new DefaultListModel<>(); 37 | proxyListener = new BorProxyListener(); 38 | contextMenu = new BorContextMenu(); 39 | borExtensionUI = new BorExtensionUI(); 40 | borExtensionUI.getBreakpointList().setModel(breakpoints); 41 | } 42 | 43 | static ExtensionState getInstance() { 44 | if (state == null) 45 | state = new ExtensionState(); 46 | return state; 47 | } 48 | 49 | IBurpExtenderCallbacks getCallbacks() { 50 | return callbacks; 51 | } 52 | 53 | void setCallbacks(IBurpExtenderCallbacks callbacks) { 54 | this.callbacks = callbacks; 55 | } 56 | 57 | /* 58 | Little bit of bit vector magic here to save a bunch of if branches. 59 | The `validContextMenuBitVector` constant contains a vector of all valid 60 | context int's that this extension menu should be shown for. 61 | For example, if valid contexts were 0,3,and 5, then the vector is: 62 | 1 << 0 | 1<< 3 | 1 << 5 63 | To check if a supplied context int is valid, simply check if the bit is set: 64 | validContextMenuBitVector & (1 << context) 65 | If it is set the result will be NON zero. 66 | */ 67 | boolean shouldShowMenu(int context) { 68 | return (validContextMenuBitVector & (1 << context)) != 0; 69 | } 70 | 71 | BorProxyListener getProxyListener() { 72 | return proxyListener; 73 | } 74 | 75 | DefaultListModel getBreakpoints() { 76 | return breakpoints; 77 | } 78 | 79 | BorContextMenu getContextMenu() { 80 | return contextMenu; 81 | } 82 | 83 | /* 84 | Convert `IHttpRequestResponse` to URL string. Combines the protocol, host, and URL path. 85 | Note: While it seems like it would work, `getCallbacks().getHelpers().analyzeRequest(requestResponse).getUrl()` 86 | does not actually return a URL that matches what you would see in the browser and so won't work as a breakpoint. 87 | */ 88 | String convertToBreakpoint(IHttpRequestResponse requestResponse) { 89 | IRequestInfo info = callbacks.getHelpers().analyzeRequest(requestResponse); 90 | return String.format("%s://%s%s",requestResponse.getHttpService().getProtocol(),requestResponse.getHttpService().getHost(),info.getUrl().getPath()); 91 | } 92 | 93 | public BorExtensionUI getBorExtensionUI() { 94 | return borExtensionUI; 95 | } 96 | } 97 | --------------------------------------------------------------------------------