-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
-------------------------------- Moved to the new Montoya APIs Switched to newest BurpSuiteGuiLibrary Refactored and commented code for sanity Performance and code QoL improvements
- Loading branch information
1 parent
f5a7630
commit 78f2ad8
Showing
5 changed files
with
324 additions
and
182 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.staticflow; | ||
|
||
import burp.api.montoya.MontoyaApi; | ||
import main.java.com.staticflow.BurpGuiControl; | ||
import javax.swing.*; | ||
import java.awt.*; | ||
import java.awt.event.*; | ||
|
||
/** | ||
* This Singleton class holds all custom state for the extension and provides a central means of accessing it. | ||
*/ | ||
public class ExtensionState { | ||
private static final String REPEATER = "Repeater"; | ||
|
||
|
||
private final Component repeaterComponent; | ||
private final JTabbedPane repeaterTabbedPane; | ||
private MontoyaApi callbacks; | ||
|
||
private static ExtensionState state; | ||
|
||
/** | ||
* Initializes the {@code ExtensionState} Singleton. | ||
* | ||
* This constructor obtains a reference to the Burp Suite Repeater tab swing component using | ||
* {@link BurpGuiControl#getBaseBurpComponent}. | ||
* <br> | ||
* It then attaches a hierarchy listener to the Repeater tab component to determine when the Repeater tab | ||
* is in view. | ||
* <br> | ||
* When the Repeater tab is shown (using the {@link HierarchyEvent#SHOWING_CHANGED} flag of the hierarchy event), the | ||
* 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 | ||
* whole Repeater tab and JTabbedPane which for some magic swing reason sets our custom Component to be hidden. | ||
* <br> | ||
* Finally, this constructor obtains a reference to the {@link JTabbedPane} within the Repeater tab | ||
* component using {@link BurpGuiControl#findFirstComponentOfType}. | ||
*/ | ||
private ExtensionState() { | ||
this.repeaterComponent = BurpGuiControl.getBaseBurpComponent(REPEATER); | ||
this.repeaterComponent.addHierarchyListener(e -> { | ||
if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { | ||
Container component = (Container) e.getComponent(); | ||
if (component.isShowing()) { | ||
component.getComponent(0).setVisible(true); | ||
} | ||
} | ||
}); | ||
this.repeaterTabbedPane = (JTabbedPane) BurpGuiControl.findFirstComponentOfType((Container) repeaterComponent,JTabbedPane.class); | ||
} | ||
|
||
/* | ||
GETTERS/SETTERS BELOW | ||
*/ | ||
static ExtensionState getInstance() { | ||
if (state == null) { | ||
state = new ExtensionState(); | ||
} | ||
return state; | ||
} | ||
|
||
public JTabbedPane getRepeaterTabbedPane() { | ||
return repeaterTabbedPane; | ||
} | ||
|
||
public Component getRepeaterComponent() { | ||
return this.repeaterComponent; | ||
} | ||
|
||
public MontoyaApi getCallbacks() { | ||
return this.callbacks; | ||
} | ||
|
||
public void setCallbacks(MontoyaApi callbacks) { | ||
this.callbacks = callbacks; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,180 +1,39 @@ | ||
package com.staticflow; | ||
|
||
import burp.IBurpExtender; | ||
import burp.IBurpExtenderCallbacks; | ||
import burp.IExtensionStateListener; | ||
|
||
import javax.swing.*; | ||
import java.awt.*; | ||
import java.awt.event.*; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
public class RepeaterSearch implements IBurpExtender, IExtensionStateListener { | ||
|
||
public static final String REPEATER = "Repeater"; | ||
public static final String SEARCH = "Search"; | ||
public static final String ENTER_QUERY = "Enter query..."; | ||
private Component repeaterComponent; | ||
private IBurpExtenderCallbacks callbacks; | ||
private boolean searchResponseForText; | ||
private boolean searchRequestForText; | ||
private boolean useRegex; | ||
import burp.api.montoya.BurpExtension; | ||
import burp.api.montoya.MontoyaApi; | ||
import burp.api.montoya.extension.ExtensionUnloadingHandler; | ||
|
||
/** | ||
* The entry point for a Burp Suite extension that adds a custom search bar to the Repeater tab. | ||
* This extension allows users to search through the request body and/or the response body of requests | ||
* using a simple string or a regular expression (regex). | ||
* | ||
* The `RepeaterSearch` class implements the `BurpExtension` and `ExtensionUnloadingHandler` interfaces, | ||
* allowing it to handle extension initialization and unloading events. | ||
* | ||
* Upon initialization, the `initialize` method registers the extension's unloading handler, sets the | ||
* necessary callbacks, and adds the search bar to the Repeater tab. | ||
* | ||
* When the extension is unloaded, the `extensionUnloaded` method is called to perform any necessary | ||
* clean-up operations. | ||
* | ||
* @see BurpExtension | ||
* @see ExtensionUnloadingHandler | ||
*/ | ||
public class RepeaterSearch implements BurpExtension, ExtensionUnloadingHandler { | ||
|
||
@Override | ||
public void registerExtenderCallbacks(IBurpExtenderCallbacks iBurpExtenderCallbacks) { | ||
this.searchRequestForText = true; | ||
this.callbacks = iBurpExtenderCallbacks; | ||
iBurpExtenderCallbacks.registerExtensionStateListener(this); | ||
this.repeaterComponent = BurpGuiControl.getBaseBurpComponent(REPEATER); | ||
JPanel combined = new JPanel(new GridBagLayout()); | ||
JPanel searchBarPanel = new JPanel(new GridBagLayout()); | ||
JPanel searchBarButtonsPanel = new JPanel(); | ||
searchBarButtonsPanel.setLayout(new BoxLayout(searchBarButtonsPanel, | ||
BoxLayout.Y_AXIS)); | ||
JButton searchButton = new JButton(SEARCH); | ||
JTextField searchBar = new JTextField(ENTER_QUERY); | ||
GridBagConstraints c = new GridBagConstraints(); | ||
GridBagConstraints gbc = new GridBagConstraints(); | ||
|
||
c.gridx = 0; | ||
c.gridy = 0; | ||
c.weightx = 0.90; | ||
c.weighty = 0.05; | ||
c.fill = GridBagConstraints.BOTH; | ||
searchBar.addMouseListener(new MouseListener() { | ||
@Override | ||
public void mouseClicked(MouseEvent e) { | ||
if (searchBar.getText().equals(ENTER_QUERY)) { | ||
searchBar.setText(""); | ||
} | ||
} | ||
|
||
@Override | ||
public void mousePressed(MouseEvent e) { | ||
//UnNeeded | ||
} | ||
|
||
@Override | ||
public void mouseReleased(MouseEvent e) { | ||
//UnNeeded | ||
} | ||
|
||
@Override | ||
public void mouseEntered(MouseEvent e) { | ||
//UnNeeded | ||
} | ||
|
||
@Override | ||
public void mouseExited(MouseEvent e) { | ||
if (searchBar.getText().isEmpty()) { | ||
searchBar.setText(ENTER_QUERY); | ||
} | ||
} | ||
}); | ||
gbc.gridx = 0; | ||
gbc.gridy = 0; | ||
gbc.fill = GridBagConstraints.BOTH; | ||
gbc.weightx = 1; | ||
gbc.weighty = 0.50; | ||
searchBarPanel.add(searchBar,gbc); | ||
searchBar.addKeyListener(new KeyListener() { | ||
@Override | ||
public void keyTyped(KeyEvent e) { | ||
searchButton.setText(SEARCH); | ||
resetRepeaterTabs(); | ||
} | ||
|
||
@Override | ||
public void keyPressed(KeyEvent e) { | ||
//UnNeeded | ||
} | ||
|
||
@Override | ||
public void keyReleased(KeyEvent e) { | ||
//UnNeeded | ||
} | ||
}); | ||
searchButton.addActionListener(e -> { | ||
if(searchButton.getText().equals(SEARCH)) { | ||
searchRepeaterTabsForString(searchBar.getText()); | ||
searchButton.setText("Clear"); | ||
} else { | ||
resetRepeaterTabs(); | ||
searchBar.setText(ENTER_QUERY); | ||
searchButton.setText(SEARCH); | ||
resetRepeaterTabs(); | ||
} | ||
}); | ||
searchBarButtonsPanel.add(searchButton); | ||
JCheckBox searchRequest = new JCheckBox("Request"); | ||
searchRequest.setSelected(true); | ||
searchRequest.addChangeListener(e -> searchRequestForText = !searchRequestForText); | ||
searchBarButtonsPanel.add(searchRequest); | ||
JCheckBox searchResponse = new JCheckBox("Response"); | ||
searchResponse.addChangeListener(e -> searchResponseForText = !searchResponseForText); | ||
searchBarButtonsPanel.add(searchResponse); | ||
JCheckBox searchRegex = new JCheckBox("Regex"); | ||
searchRegex.addChangeListener(e -> useRegex = !useRegex); | ||
searchBarButtonsPanel.add(searchRegex); | ||
combined.add(searchBarPanel,c); | ||
c.gridx = 1; | ||
c.weightx = 0.10; | ||
combined.add(searchBarButtonsPanel,c); | ||
c.gridy = 1; | ||
c.gridx = 0; | ||
c.gridwidth = 2; | ||
c.weighty = 0.95; | ||
combined.add(repeaterComponent,c); | ||
iBurpExtenderCallbacks.customizeUiComponent(combined); | ||
BurpGuiControl.addBaseBurpComponent(REPEATER,combined); | ||
public void initialize(MontoyaApi api) { | ||
api.extension().registerUnloadingHandler(this); | ||
ExtensionState.getInstance().setCallbacks(api); | ||
Utils.addSearchBarToRepeaterTab(); | ||
} | ||
|
||
@Override | ||
public void extensionUnloaded() { | ||
resetRepeaterTabs(); | ||
BurpGuiControl.replaceBaseBurpComponent(REPEATER,this.repeaterComponent); | ||
} | ||
|
||
private void resetRepeaterTabs(){ | ||
JTabbedPane repeaterTabs = ((JTabbedPane)this.repeaterComponent); | ||
for(int i=0; i < repeaterTabs.getTabCount()-1; i++) { | ||
repeaterTabs.setBackgroundAt(i,new Color(0xBBBBBB)); | ||
|
||
} | ||
} | ||
|
||
private void searchRepeaterTabsForString(String search) { | ||
JTabbedPane repeaterTabs = ((JTabbedPane)this.repeaterComponent); | ||
for( int i=0; i < repeaterTabs.getTabCount()-1; i++) { | ||
try { | ||
if ( searchRequestForText ) { | ||
JTextArea requestTextArea = | ||
BurpGuiControl.getRepeaterTabRequestTextArea((Container) repeaterTabs.getComponentAt(i)); | ||
if (searchTextArea(search,requestTextArea) ) { | ||
repeaterTabs.setBackgroundAt(i,new Color(0xff6633)); | ||
} | ||
} else if ( searchResponseForText ) { | ||
JTextArea responseTextArea = | ||
BurpGuiControl.getRepeaterTabResponseTextArea((Container) repeaterTabs.getComponentAt(i)); | ||
if (searchTextArea(search, responseTextArea)) { | ||
repeaterTabs.setBackgroundAt(i,new Color(0xff6633)); | ||
} | ||
} | ||
}catch(ArrayIndexOutOfBoundsException e) { | ||
this.callbacks.printError(e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
private boolean searchTextArea(String search, JTextArea textArea) { | ||
if (useRegex) { | ||
Pattern pattern = Pattern.compile(search,Pattern.MULTILINE); | ||
Matcher matcher = pattern.matcher(textArea.getText()); | ||
return matcher.find(); | ||
} else { | ||
return textArea.getText().contains(search); | ||
} | ||
Utils.cleanUpExtension(); | ||
} | ||
|
||
} |
Oops, something went wrong.