Skip to content

Commit

Permalink
Lib update, Exec-After feature, bug fixes
Browse files Browse the repository at this point in the history
Gradle libraries have been updated
Execute after has been added
Context menu has been updated to support copy headers
Extension name has been set to avoid .jar in the name
Variable pop up dialogs set their location according to Burp Suite's frame
  • Loading branch information
irsdl committed Jan 19, 2023
1 parent 7fe8585 commit fcac8f3
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 30 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ out/
*.burp
releases/
*.json
*.iml
*.iml
gradle-app.setting
.gradletasknamecache
.git
21 changes: 14 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,28 @@ repositories {
}

dependencies {
compileOnly 'net.portswigger.burp.extender:burp-extender-api:1.7.22'
compileOnly 'net.portswigger.burp.extender:burp-extender-api:2.3'
implementation 'com.github.CoreyD97:BurpExtenderUtilities:cd2b86250'
compileOnly 'com.formdev:flatlaf:1.1.2'
testRuntimeOnly files('/home/corey/BurpSuitePro/burpsuite_pro.jar')
compileOnly 'com.formdev:flatlaf:3.0'
//testRuntimeOnly files('/home/corey/BurpSuitePro/burpsuite_pro.jar')
}

jar {
baseName = project.name
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
jar{
archivesBaseName = project.name
from {
(configurations.runtimeClasspath).collect { it.isDirectory() ? it : zipTree(it) }
}{
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
exclude "META-INF/*.txt"
}
}

configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}

tasks.withType(Jar) {
destinationDir = file("$rootDir/releases")
destinationDirectory = file("$rootDir/releases")
}
36 changes: 33 additions & 3 deletions src/main/java/com/coreyd97/stepper/ContextMenuFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,43 @@ public List<JMenuItem> createMenuItems(IContextMenuInvocation invocation) {

menuItems.add(addStepMenu);


if(invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST){
menuItems.addAll(buildCopyHeaderMenuItems(invocation));
menuItems.addAll(buildVariableMenuItems(invocation));
}
return menuItems;
}

private List<JMenuItem> buildCopyHeaderMenuItems(IContextMenuInvocation invocation){
List<JMenuItem> menuItems = new ArrayList<>();

JMenu addStepHeaderToClipboardMenu = new JMenu("Copy Header To Clipboard");

for (StepSequence stepSequence : sequenceManager.getSequences()) {
JMenu sequenceItem = new JMenu(stepSequence.getTitle());

JMenuItem execBeforeMenuItem = new JMenuItem("Execute-Before Header");
execBeforeMenuItem.addActionListener(actionEvent -> {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new StringSelection(MessageProcessor.EXECUTE_BEFORE_HEADER+": " + stepSequence.getTitle()), null);
});
sequenceItem.add(execBeforeMenuItem);

JMenuItem execAfterMenuItem = new JMenuItem("Execute-After Header");
execAfterMenuItem.addActionListener(actionEvent -> {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
new StringSelection(MessageProcessor.EXECUTE_AFTER_HEADER+": " + stepSequence.getTitle()), null);
});
sequenceItem.add(execAfterMenuItem);

addStepHeaderToClipboardMenu.add(sequenceItem);
}

menuItems.add(addStepHeaderToClipboardMenu);

return menuItems;
}

private List<JMenuItem> buildVariableMenuItems(IContextMenuInvocation invocation){
List<JMenuItem> menuItems = new ArrayList<>();

Expand All @@ -92,8 +122,8 @@ private List<JMenuItem> buildVariableMenuItems(IContextMenuInvocation invocation
long varCount = sequenceVariableMap.values().stream().mapToInt(List::size).sum();

if(varCount > 0) {
JMenu addStepVariableToClipboardMenu = new JMenu("Add Stepper Variable To Clipboard");
JMenuItem insertVariable = new JMenuItem("Insert Stepper Variable At Cursor (NOT POSSIBLE TO IMPLEMENT)");
JMenu addStepVariableToClipboardMenu = new JMenu("Copy Variable To Clipboard");
//JMenuItem insertVariable = new JMenuItem("Insert Stepper Variable At Cursor (NOT POSSIBLE TO IMPLEMENT)");

if(isViewingSequenceStep){ //Only variables from a single sequence step
Collection<StepVariable> variables = sequenceVariableMap.values().stream()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/coreyd97/stepper/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class Globals {
public static final String EXTENSION_NAME = "Stepper";
public static final String VERSION = "1.4.1";
public static final String VERSION = "1.4.2";
public static final String PREF_STEP_SEQUENCES = "sequences";
public static final String PREF_PREV_VERSION = "previousVersion";
public static final String PREF_VARS_IN_ALL_TOOLS = "enableVarsInAll";
Expand Down
94 changes: 77 additions & 17 deletions src/main/java/com/coreyd97/stepper/MessageProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ public class MessageProcessor implements IHttpListener {

private final SequenceManager sequenceManager;
private final Preferences preferences;
public static final String EXECUTE_BEFORE_REGEX = "X-Stepper-Execute-Before:(.*)";
public static final String EXECUTE_AFTER_REGEX = "X-Stepper-Execute-After:(.*)";
public static final Pattern EXECUTE_BEFORE_PATTERN = Pattern.compile(EXECUTE_BEFORE_REGEX, Pattern.CASE_INSENSITIVE);
public static final Pattern EXECUTE_AFTER_PATTERN = Pattern.compile(EXECUTE_AFTER_REGEX, Pattern.CASE_INSENSITIVE);
public static final String EXECUTE_BEFORE_HEADER = "X-Stepper-Execute-Before";
public static final String EXECUTE_AFTER_HEADER = "X-Stepper-Execute-After";
public static final String EXECUTE_BEFORE_REGEX = EXECUTE_BEFORE_HEADER + ":(.*)";
public static final String EXECUTE_AFTER_REGEX = EXECUTE_AFTER_HEADER+":(.*)";
public static final String EXECUTE_AFTER_COMMENT_DELIMITER = "#%~%#";
public static final Pattern EXECUTE_BEFORE_HEADER_PATTERN = Pattern.compile("^" + EXECUTE_BEFORE_REGEX + "$", Pattern.CASE_INSENSITIVE);
public static final Pattern EXECUTE_AFTER_HEADER_PATTERN = Pattern.compile("^" + EXECUTE_AFTER_REGEX + "$", Pattern.CASE_INSENSITIVE);
public static final String STEPPER_IGNORE_HEADER = "X-Stepper-Ignore";
public static final Pattern STEPPER_IGNORE_PATTERN = Pattern.compile(STEPPER_IGNORE_HEADER, Pattern.CASE_INSENSITIVE);
public static final Pattern STEPPER_IGNORE_PATTERN = Pattern.compile("^"+STEPPER_IGNORE_HEADER, Pattern.CASE_INSENSITIVE);

public MessageProcessor(SequenceManager sequenceManager, Preferences preferences){
this.sequenceManager = sequenceManager;
Expand Down Expand Up @@ -58,17 +61,34 @@ public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequ
if(messageIsRequest){
byte[] request = messageInfo.getRequest();
System.out.println("Request: " + messageInfo.getRequest());
List<StepSequence> preExecSequences = extractPreExecSequencesFromRequest(requestInfo);
List<StepSequence> preExecSequences = extractExecSequencesFromRequest(requestInfo, EXECUTE_BEFORE_HEADER_PATTERN);
if(preExecSequences.size() > 0){
//Remove the headers from the request
request = removeHeaderMatchingPattern(request, EXECUTE_BEFORE_PATTERN);
request = removeHeaderMatchingPattern(request, EXECUTE_BEFORE_HEADER_PATTERN);

//Execute the sequences
for (StepSequence sequence : preExecSequences) {
sequence.executeBlocking();
}
}

List<StepSequence> postExecSequences = extractExecSequencesFromRequest(requestInfo, EXECUTE_AFTER_HEADER_PATTERN);

if(postExecSequences.size() > 0){
//Remove the headers from the request
request = removeHeaderMatchingPattern(request, EXECUTE_AFTER_HEADER_PATTERN);

//Joining the sequences as string to set them as a comment to catch them in the response
String postExecSequencesJoined = EXECUTE_AFTER_HEADER + ":";
for (StepSequence sequence : preExecSequences) {
postExecSequencesJoined += sequence.getTitle() + EXECUTE_AFTER_COMMENT_DELIMITER;
}

if(!postExecSequencesJoined.isEmpty()){
messageInfo.setComment(messageInfo.getComment() + postExecSequencesJoined);
}
}


HashMap<StepSequence, List<StepVariable>> allVariables = sequenceManager.getRollingVariablesFromAllSequences();

Expand All @@ -94,6 +114,17 @@ public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequ

//Save any changes made to the request.
messageInfo.setRequest(request);
}else{
// this is a response so we check for the comments
List<StepSequence> postExecSequences = extractExecSequencesFromComment(messageInfo.getComment(), EXECUTE_AFTER_HEADER_PATTERN);
if(postExecSequences.size() > 0){
//Execute the sequences
for (StepSequence sequence : postExecSequences) {
sequence.executeBlocking();
}
// remove the added comment from the request
messageInfo.setComment(messageInfo.getComment().replaceAll(EXECUTE_AFTER_REGEX+EXECUTE_AFTER_COMMENT_DELIMITER,""));
}
}
}
}
Expand Down Expand Up @@ -195,30 +226,59 @@ public static byte[] updateContentLength(byte[] request){
}

/**
* Locates the X-Stepper-Execute-Before header and returns the matching sequence.
* Locates the X-Stepper-Execute-Before or X-Stepper-Execute-After headers and returns the matching sequences.
* @param requestInfo
* @return Optional value of step sequence to execute before the request.
* @param pattern
* @return Optional value of step sequence to execute before or after the request.
*/
public List<StepSequence> extractPreExecSequencesFromRequest(IRequestInfo requestInfo){
public List<StepSequence> extractExecSequencesFromRequest(IRequestInfo requestInfo, Pattern pattern){
//Check if headers ask us to execute a request before the request.
List<String> requestHeaders = requestInfo.getHeaders();
ArrayList<StepSequence> postExecSequences = new ArrayList<>();
ArrayList<StepSequence> execSequences = new ArrayList<>();

for (Iterator<String> iterator = requestHeaders.iterator(); iterator.hasNext(); ) {
String header = iterator.next();
Matcher m = MessageProcessor.EXECUTE_BEFORE_PATTERN.matcher(header);
Matcher m = pattern.matcher(header);
if (m.matches()) {
Optional<StepSequence> preExecSequence = sequenceManager.getSequences().stream()
Optional<StepSequence> execSequence = sequenceManager.getSequences().stream()
.filter(sequence -> sequence.getTitle().equalsIgnoreCase(m.group(1).trim()))
.findFirst();

if(preExecSequence.isPresent())
postExecSequences.add(preExecSequence.get());
if(execSequence.isPresent())
execSequences.add(execSequence.get());
else
JOptionPane.showMessageDialog(Stepper.getUI().getUiComponent(), "Could not find pre-execution sequence named: \"" + m.group(1).trim() + "\".");
JOptionPane.showMessageDialog(Stepper.getUI().getUiComponent(), "Could not find execution sequence named: \"" + m.group(1).trim() + "\".");
}
}
return execSequences;
}

/**
* Locates the X-Stepper-Execute-After pattern in the comment and returns the matching sequences.
* @param comment
* @param pattern
* @return Optional value of step sequence to execute after the request.
*/
public List<StepSequence> extractExecSequencesFromComment(String comment, Pattern pattern){
ArrayList<StepSequence> execSequences = new ArrayList<>();
Matcher m = pattern.matcher(comment);
if (m.find()) {
String[] allSequences = m.group(1).split(EXECUTE_AFTER_COMMENT_DELIMITER);
for(String sequenceName : allSequences){
if(sequenceName != null && !sequenceName.isEmpty()){
Optional<StepSequence> execSequence = sequenceManager.getSequences().stream()
.filter(sequence -> sequence.getTitle().equalsIgnoreCase(sequenceName.trim()))
.findFirst();

if(execSequence.isPresent())
execSequences.add(execSequence.get());
else
JOptionPane.showMessageDialog(Stepper.getUI().getUiComponent(), "Could not find execution sequence named: \"" + m.group(1).trim() + "\".");
}
}
}
return postExecSequences;

return execSequences;
}

public static boolean hasHeaderMatchingPattern(IRequestInfo requestInfo, Pattern pattern){
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/coreyd97/stepper/Stepper.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,13 @@ public static SequenceManager getSequenceManager(){
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
Stepper.callbacks = callbacks;
Stepper.preferences = new StepperPreferenceFactory(Globals.EXTENSION_NAME, gsonProvider, callbacks).buildPreferences();

this.sequenceManager = new SequenceManager();
this.stateManager = new StateManager(sequenceManager, preferences);
this.stateManager.loadSavedSequences();
this.messageProcessor = new MessageProcessor(sequenceManager, preferences);

Stepper.callbacks.setExtensionName(Globals.EXTENSION_NAME);
Stepper.callbacks.registerMessageEditorTabFactory(new VariableReplacementsTabFactory(sequenceManager));
Stepper.callbacks.registerContextMenuFactory(new ContextMenuFactory(sequenceManager));
Stepper.callbacks.registerHttpListener(messageProcessor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public enum VariableType { PROMPT, REGEX }

public VariableCreationDialog(Frame owner, String title, VariableType type){
super(owner, title, true);

this.setLocation(owner.getLocation());
buildDialog(type);
pack();
}
Expand Down

0 comments on commit fcac8f3

Please sign in to comment.