Skip to content

Commit 78f2ad8

Browse files
committed
Huge 2.0 release. Changes below:
-------------------------------- Moved to the new Montoya APIs Switched to newest BurpSuiteGuiLibrary Refactored and commented code for sanity Performance and code QoL improvements
1 parent f5a7630 commit 78f2ad8

File tree

5 files changed

+324
-182
lines changed

5 files changed

+324
-182
lines changed

pom.xml

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,24 @@
66

77
<groupId>staticflow</groupId>
88
<artifactId>RepeaterSearch</artifactId>
9-
<version>1.0-SNAPSHOT</version>
10-
9+
<version>2.0-SNAPSHOT</version>
10+
<repositories>
11+
<repository>
12+
<id>jitpack.io</id>
13+
<url>https://jitpack.io</url>
14+
</repository>
15+
</repositories>
1116
<dependencies>
1217
<dependency>
13-
<groupId>net.portswigger.burp.extender</groupId>
14-
<artifactId>burp-extender-api</artifactId>
15-
<version>2.1</version>
18+
<groupId>net.portswigger.burp.extensions</groupId>
19+
<artifactId>montoya-api</artifactId>
20+
<version>2023.3</version>
1621
</dependency>
1722
<dependency>
18-
<groupId>staticflow</groupId>
23+
<groupId>com.github.Static-Flow</groupId>
1924
<artifactId>BurpSuiteGuiLibrary</artifactId>
20-
<version>1.0-SNAPSHOT</version>
21-
</dependency>
22-
<dependency>
23-
<groupId>org.javassist</groupId>
24-
<artifactId>javassist</artifactId>
25-
<version>3.27.0-GA</version>
25+
<version>2.1</version>
2626
</dependency>
27-
28-
2927
</dependencies>
3028

3129
<build>
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.staticflow;
2+
3+
import burp.api.montoya.MontoyaApi;
4+
import main.java.com.staticflow.BurpGuiControl;
5+
import javax.swing.*;
6+
import java.awt.*;
7+
import java.awt.event.*;
8+
9+
/**
10+
* This Singleton class holds all custom state for the extension and provides a central means of accessing it.
11+
*/
12+
public class ExtensionState {
13+
private static final String REPEATER = "Repeater";
14+
15+
16+
private final Component repeaterComponent;
17+
private final JTabbedPane repeaterTabbedPane;
18+
private MontoyaApi callbacks;
19+
20+
private static ExtensionState state;
21+
22+
/**
23+
* Initializes the {@code ExtensionState} Singleton.
24+
*
25+
* This constructor obtains a reference to the Burp Suite Repeater tab swing component using
26+
* {@link BurpGuiControl#getBaseBurpComponent}.
27+
* <br>
28+
* It then attaches a hierarchy listener to the Repeater tab component to determine when the Repeater tab
29+
* is in view.
30+
* <br>
31+
* When the Repeater tab is shown (using the {@link HierarchyEvent#SHOWING_CHANGED} flag of the hierarchy event), the
32+
* custom search bar created by this extension is set to be visible. This is because anytime a new tab is created in Repeater, Burp Suite recreates the
33+
* whole Repeater tab and JTabbedPane which for some magic swing reason sets our custom Component to be hidden.
34+
* <br>
35+
* Finally, this constructor obtains a reference to the {@link JTabbedPane} within the Repeater tab
36+
* component using {@link BurpGuiControl#findFirstComponentOfType}.
37+
*/
38+
private ExtensionState() {
39+
this.repeaterComponent = BurpGuiControl.getBaseBurpComponent(REPEATER);
40+
this.repeaterComponent.addHierarchyListener(e -> {
41+
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) {
42+
Container component = (Container) e.getComponent();
43+
if (component.isShowing()) {
44+
component.getComponent(0).setVisible(true);
45+
}
46+
}
47+
});
48+
this.repeaterTabbedPane = (JTabbedPane) BurpGuiControl.findFirstComponentOfType((Container) repeaterComponent,JTabbedPane.class);
49+
}
50+
51+
/*
52+
GETTERS/SETTERS BELOW
53+
*/
54+
static ExtensionState getInstance() {
55+
if (state == null) {
56+
state = new ExtensionState();
57+
}
58+
return state;
59+
}
60+
61+
public JTabbedPane getRepeaterTabbedPane() {
62+
return repeaterTabbedPane;
63+
}
64+
65+
public Component getRepeaterComponent() {
66+
return this.repeaterComponent;
67+
}
68+
69+
public MontoyaApi getCallbacks() {
70+
return this.callbacks;
71+
}
72+
73+
public void setCallbacks(MontoyaApi callbacks) {
74+
this.callbacks = callbacks;
75+
}
76+
77+
}
Lines changed: 27 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,180 +1,39 @@
11
package com.staticflow;
22

3-
import burp.IBurpExtender;
4-
import burp.IBurpExtenderCallbacks;
5-
import burp.IExtensionStateListener;
63

7-
import javax.swing.*;
8-
import java.awt.*;
9-
import java.awt.event.*;
10-
import java.util.regex.Matcher;
11-
import java.util.regex.Pattern;
12-
13-
public class RepeaterSearch implements IBurpExtender, IExtensionStateListener {
14-
15-
public static final String REPEATER = "Repeater";
16-
public static final String SEARCH = "Search";
17-
public static final String ENTER_QUERY = "Enter query...";
18-
private Component repeaterComponent;
19-
private IBurpExtenderCallbacks callbacks;
20-
private boolean searchResponseForText;
21-
private boolean searchRequestForText;
22-
private boolean useRegex;
4+
import burp.api.montoya.BurpExtension;
5+
import burp.api.montoya.MontoyaApi;
6+
import burp.api.montoya.extension.ExtensionUnloadingHandler;
7+
8+
/**
9+
* The entry point for a Burp Suite extension that adds a custom search bar to the Repeater tab.
10+
* This extension allows users to search through the request body and/or the response body of requests
11+
* using a simple string or a regular expression (regex).
12+
*
13+
* The `RepeaterSearch` class implements the `BurpExtension` and `ExtensionUnloadingHandler` interfaces,
14+
* allowing it to handle extension initialization and unloading events.
15+
*
16+
* Upon initialization, the `initialize` method registers the extension's unloading handler, sets the
17+
* necessary callbacks, and adds the search bar to the Repeater tab.
18+
*
19+
* When the extension is unloaded, the `extensionUnloaded` method is called to perform any necessary
20+
* clean-up operations.
21+
*
22+
* @see BurpExtension
23+
* @see ExtensionUnloadingHandler
24+
*/
25+
public class RepeaterSearch implements BurpExtension, ExtensionUnloadingHandler {
2326

2427
@Override
25-
public void registerExtenderCallbacks(IBurpExtenderCallbacks iBurpExtenderCallbacks) {
26-
this.searchRequestForText = true;
27-
this.callbacks = iBurpExtenderCallbacks;
28-
iBurpExtenderCallbacks.registerExtensionStateListener(this);
29-
this.repeaterComponent = BurpGuiControl.getBaseBurpComponent(REPEATER);
30-
JPanel combined = new JPanel(new GridBagLayout());
31-
JPanel searchBarPanel = new JPanel(new GridBagLayout());
32-
JPanel searchBarButtonsPanel = new JPanel();
33-
searchBarButtonsPanel.setLayout(new BoxLayout(searchBarButtonsPanel,
34-
BoxLayout.Y_AXIS));
35-
JButton searchButton = new JButton(SEARCH);
36-
JTextField searchBar = new JTextField(ENTER_QUERY);
37-
GridBagConstraints c = new GridBagConstraints();
38-
GridBagConstraints gbc = new GridBagConstraints();
39-
40-
c.gridx = 0;
41-
c.gridy = 0;
42-
c.weightx = 0.90;
43-
c.weighty = 0.05;
44-
c.fill = GridBagConstraints.BOTH;
45-
searchBar.addMouseListener(new MouseListener() {
46-
@Override
47-
public void mouseClicked(MouseEvent e) {
48-
if (searchBar.getText().equals(ENTER_QUERY)) {
49-
searchBar.setText("");
50-
}
51-
}
52-
53-
@Override
54-
public void mousePressed(MouseEvent e) {
55-
//UnNeeded
56-
}
57-
58-
@Override
59-
public void mouseReleased(MouseEvent e) {
60-
//UnNeeded
61-
}
62-
63-
@Override
64-
public void mouseEntered(MouseEvent e) {
65-
//UnNeeded
66-
}
67-
68-
@Override
69-
public void mouseExited(MouseEvent e) {
70-
if (searchBar.getText().isEmpty()) {
71-
searchBar.setText(ENTER_QUERY);
72-
}
73-
}
74-
});
75-
gbc.gridx = 0;
76-
gbc.gridy = 0;
77-
gbc.fill = GridBagConstraints.BOTH;
78-
gbc.weightx = 1;
79-
gbc.weighty = 0.50;
80-
searchBarPanel.add(searchBar,gbc);
81-
searchBar.addKeyListener(new KeyListener() {
82-
@Override
83-
public void keyTyped(KeyEvent e) {
84-
searchButton.setText(SEARCH);
85-
resetRepeaterTabs();
86-
}
87-
88-
@Override
89-
public void keyPressed(KeyEvent e) {
90-
//UnNeeded
91-
}
92-
93-
@Override
94-
public void keyReleased(KeyEvent e) {
95-
//UnNeeded
96-
}
97-
});
98-
searchButton.addActionListener(e -> {
99-
if(searchButton.getText().equals(SEARCH)) {
100-
searchRepeaterTabsForString(searchBar.getText());
101-
searchButton.setText("Clear");
102-
} else {
103-
resetRepeaterTabs();
104-
searchBar.setText(ENTER_QUERY);
105-
searchButton.setText(SEARCH);
106-
resetRepeaterTabs();
107-
}
108-
});
109-
searchBarButtonsPanel.add(searchButton);
110-
JCheckBox searchRequest = new JCheckBox("Request");
111-
searchRequest.setSelected(true);
112-
searchRequest.addChangeListener(e -> searchRequestForText = !searchRequestForText);
113-
searchBarButtonsPanel.add(searchRequest);
114-
JCheckBox searchResponse = new JCheckBox("Response");
115-
searchResponse.addChangeListener(e -> searchResponseForText = !searchResponseForText);
116-
searchBarButtonsPanel.add(searchResponse);
117-
JCheckBox searchRegex = new JCheckBox("Regex");
118-
searchRegex.addChangeListener(e -> useRegex = !useRegex);
119-
searchBarButtonsPanel.add(searchRegex);
120-
combined.add(searchBarPanel,c);
121-
c.gridx = 1;
122-
c.weightx = 0.10;
123-
combined.add(searchBarButtonsPanel,c);
124-
c.gridy = 1;
125-
c.gridx = 0;
126-
c.gridwidth = 2;
127-
c.weighty = 0.95;
128-
combined.add(repeaterComponent,c);
129-
iBurpExtenderCallbacks.customizeUiComponent(combined);
130-
BurpGuiControl.addBaseBurpComponent(REPEATER,combined);
28+
public void initialize(MontoyaApi api) {
29+
api.extension().registerUnloadingHandler(this);
30+
ExtensionState.getInstance().setCallbacks(api);
31+
Utils.addSearchBarToRepeaterTab();
13132
}
13233

13334
@Override
13435
public void extensionUnloaded() {
135-
resetRepeaterTabs();
136-
BurpGuiControl.replaceBaseBurpComponent(REPEATER,this.repeaterComponent);
137-
}
138-
139-
private void resetRepeaterTabs(){
140-
JTabbedPane repeaterTabs = ((JTabbedPane)this.repeaterComponent);
141-
for(int i=0; i < repeaterTabs.getTabCount()-1; i++) {
142-
repeaterTabs.setBackgroundAt(i,new Color(0xBBBBBB));
143-
144-
}
145-
}
146-
147-
private void searchRepeaterTabsForString(String search) {
148-
JTabbedPane repeaterTabs = ((JTabbedPane)this.repeaterComponent);
149-
for( int i=0; i < repeaterTabs.getTabCount()-1; i++) {
150-
try {
151-
if ( searchRequestForText ) {
152-
JTextArea requestTextArea =
153-
BurpGuiControl.getRepeaterTabRequestTextArea((Container) repeaterTabs.getComponentAt(i));
154-
if (searchTextArea(search,requestTextArea) ) {
155-
repeaterTabs.setBackgroundAt(i,new Color(0xff6633));
156-
}
157-
} else if ( searchResponseForText ) {
158-
JTextArea responseTextArea =
159-
BurpGuiControl.getRepeaterTabResponseTextArea((Container) repeaterTabs.getComponentAt(i));
160-
if (searchTextArea(search, responseTextArea)) {
161-
repeaterTabs.setBackgroundAt(i,new Color(0xff6633));
162-
}
163-
}
164-
}catch(ArrayIndexOutOfBoundsException e) {
165-
this.callbacks.printError(e.getMessage());
166-
}
167-
}
168-
}
169-
170-
private boolean searchTextArea(String search, JTextArea textArea) {
171-
if (useRegex) {
172-
Pattern pattern = Pattern.compile(search,Pattern.MULTILINE);
173-
Matcher matcher = pattern.matcher(textArea.getText());
174-
return matcher.find();
175-
} else {
176-
return textArea.getText().contains(search);
177-
}
36+
Utils.cleanUpExtension();
17837
}
17938

18039
}

0 commit comments

Comments
 (0)