├── 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 | 
22 |
23 |
24 | ## Breakpoint List
25 | 
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 |
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 |
--------------------------------------------------------------------------------