diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..2eac001
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.externalToolBuilders/MakeHTTPSmugglerJAR.launch b/.externalToolBuilders/MakeHTTPSmugglerJAR.launch
new file mode 100644
index 0000000..6e45db7
--- /dev/null
+++ b/.externalToolBuilders/MakeHTTPSmugglerJAR.launch
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..031206a
--- /dev/null
+++ b/.project
@@ -0,0 +1,27 @@
+
+
+ HTTP Smuggler
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ auto,full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/MakeHTTPSmugglerJAR.launch
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..417bbde
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//src/mutation/HttpEncoding.java=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..3a21537
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..6b30308
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java
new file mode 100644
index 0000000..560ba37
--- /dev/null
+++ b/src/burp/BurpExtender.java
@@ -0,0 +1,262 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package burp;
+
+import java.awt.Component;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingUtilities;
+
+import mutation.HTTPEncodingObject;
+
+public class BurpExtender implements IBurpExtender, ITab, IHttpListener
+{
+
+ private PrintWriter _stdout;
+ private PrintWriter _stderr;
+ private JTabbedPane _topTabs;
+ private IBurpExtenderCallbacks _callbacks;
+ private JTabbedPane topTabs;
+
+ public void registerExtenderCallbacks (IBurpExtenderCallbacks callbacks)
+ {
+ _callbacks = callbacks;
+ // obtain our output stream
+ _stdout = new PrintWriter(_callbacks.getStdout(), true);
+ _stderr = new PrintWriter(_callbacks.getStderr(), true);
+
+ // set our extension name
+ _callbacks.setExtensionName("HTTP Smuggler");
+
+ // register ourselves as an HTTP listener
+ callbacks.registerHttpListener(BurpExtender.this);
+
+ // create our UI
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ topTabs = new JTabbedPane();
+
+ topTabs.addTab("Scope", null, new myui.ScopeTab(callbacks, _stdout, _stderr), null);
+ topTabs.addTab("Encoding", null, new myui.EncodingTab(callbacks, _stdout, _stderr), null);
+ topTabs.addTab("About", null, new myui.AboutTab(callbacks, _stdout, _stderr), null);
+
+ // customize our UI components
+ callbacks.customizeUiComponent(topTabs);
+ helper.UIStuff.updateJCheckBoxBackground(topTabs);
+
+ // add the custom tab to Burp's UI
+ callbacks.addSuiteTab(BurpExtender.this);
+ }
+ });
+
+ }
+
+ @Override
+ public String getTabCaption()
+ {
+ return "HTTP Smuggler Settings";
+ }
+
+ @Override
+ public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
+ if(messageIsRequest) {
+ /* to calculate the scope, OR has not been implemented yet*/
+ boolean isDisabled = false;
+ boolean isInScope = false;
+ boolean isTargetInScope = true;
+ boolean isURLPathInScope = true;
+ boolean isHeaderInScope = true;
+
+ IRequestInfo analyzedReq = _callbacks.getHelpers().analyzeRequest(messageInfo);
+ URL uUrl = analyzedReq.getUrl();
+ /* find the right scope based on the settings*/
+ int targetScopeOption =(int) loadExtensionSettingHelper("targetScopeOption","int",0);
+ int pathRegExOption =(int) loadExtensionSettingHelper("pathRegExOption","int",0);
+ String pathRegEx =(String) loadExtensionSettingHelper("pathRegEx","string","");
+ int headerRegExOption =(int) loadExtensionSettingHelper("headerRegExOption","int",0);
+ String headerRegEx =(String) loadExtensionSettingHelper("headerRegEx","string","");
+
+ boolean chckbxAllTools =(boolean) loadExtensionSettingHelper("chckbxAllTools","bool",false);
+ boolean chckbxProxy =(boolean) loadExtensionSettingHelper("chckbxProxy","bool",false);
+ boolean chckbxScanner =(boolean) loadExtensionSettingHelper("chckbxScanner","bool",false);
+ boolean chckbxIntruder =(boolean) loadExtensionSettingHelper("chckbxIntruder","bool",false);
+ boolean chckbxRepeator =(boolean) loadExtensionSettingHelper("chckbxRepeator","bool",true);
+ boolean chckbxExtender =(boolean) loadExtensionSettingHelper("chckbxExtender","bool",false);
+ boolean chckbxTarget =(boolean) loadExtensionSettingHelper("chckbxTarget","bool",false);
+ boolean chckbxSequencer =(boolean) loadExtensionSettingHelper("chckbxSequencer","bool",false);
+ boolean chckbxSpider =(boolean) loadExtensionSettingHelper("chckbxSpider","bool",false);
+
+ if(targetScopeOption==1 && pathRegExOption==1 && headerRegExOption==1) {
+ //evrything is disabled
+ isDisabled = true;
+ }
+
+ if(!isDisabled) {
+ if(targetScopeOption < 1 && !_callbacks.isInScope(uUrl)) {
+ isTargetInScope = false;
+ }
+
+
+ if(isTargetInScope && pathRegExOption < 1 && !pathRegEx.isEmpty()){
+ // AND rule for path/url regex
+ Pattern pathPattern = Pattern.compile(pathRegEx);
+ Matcher matcher_pathURL = pathPattern.matcher(uUrl.toString());
+ if (!matcher_pathURL.find())
+ {
+ isURLPathInScope = false;
+ }
+ }
+
+ if(isTargetInScope && isURLPathInScope && headerRegExOption < 1 && !headerRegEx.isEmpty()){
+ // AND rule for header regex
+ Pattern headerPattern = Pattern.compile(headerRegEx);
+
+ StringBuilder sb = new StringBuilder();
+ for (String headerLine : analyzedReq.getHeaders())
+ {
+ sb.append(headerLine);
+ sb.append("\r\n");
+ }
+ Matcher matcher_header = headerPattern.matcher(sb.toString());
+ if (!matcher_header.find())
+ {
+ isHeaderInScope = false;
+ }
+ }
+
+
+
+ if (isTargetInScope && isURLPathInScope && isHeaderInScope){
+ // check the tool!
+ if(chckbxAllTools){
+ isInScope = true;
+ }else if(chckbxProxy && toolFlag==_callbacks.TOOL_PROXY){
+ isInScope = true;
+ }else if(chckbxIntruder && toolFlag==_callbacks.TOOL_INTRUDER){
+ isInScope = true;
+ }else if(chckbxRepeator && toolFlag==_callbacks.TOOL_REPEATER){
+ isInScope = true;
+ }else if(chckbxScanner && toolFlag==_callbacks.TOOL_SCANNER){
+ isInScope = true;
+ }else if(chckbxSequencer && toolFlag==_callbacks.TOOL_SEQUENCER){
+ isInScope = true;
+ }else if(chckbxSpider && toolFlag==_callbacks.TOOL_SPIDER){
+ isInScope = true;
+ }else if(chckbxExtender && toolFlag==_callbacks.TOOL_EXTENDER){
+ isInScope = true;
+ }else if(chckbxTarget && toolFlag==_callbacks.TOOL_TARGET){
+ isInScope = true;
+ }
+ }
+
+
+ if (isInScope){
+ //logIt(toolFlag, messageIsRequest, messageInfo, null);
+ mutation.HttpEncoding httpEcnoding = new mutation.HttpEncoding(_callbacks,_stdout,_stderr,true);
+ try {
+ String newHTTPMessage = httpEcnoding.encodeHTTPMessage(messageInfo.getRequest(), loadHTTPEncodingObjectFromExtensionSetting());
+ if(newHTTPMessage.isEmpty()) {
+ _stdout.println("Message was not encoded - perhaps it was not eligible or there was an error (see the error tab)");
+ _stdout.println("Enable the debug mode to see more details");
+ }else {
+ byte[] requestByte = newHTTPMessage.getBytes("ISO-8859-1");
+ messageInfo.setRequest(requestByte);
+ }
+ } catch (UnsupportedEncodingException e) {
+ _stderr.println(e.getMessage());
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public Component getUiComponent() {
+ return topTabs;
+ }
+
+ private Object loadExtensionSettingHelper(String name, String type, Object defaultValue) {
+ Object value = null;
+ try {
+ String temp_value = _callbacks.loadExtensionSetting(name);
+ if(temp_value!=null && !temp_value.equals("")) {
+ switch(type.toLowerCase()){
+ case "int":
+ case "integer":
+ value = Integer.valueOf(temp_value);
+ break;
+ case "bool":
+ case "boolean":
+ value = Boolean.valueOf(temp_value);
+ break;
+ default:
+ value = temp_value;
+ break;
+ }
+ }
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ }
+
+ if(value==null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+ private HTTPEncodingObject loadHTTPEncodingObjectFromExtensionSetting() {
+ HTTPEncodingObject currentHTTPEncodingObject = new HTTPEncodingObject();
+ currentHTTPEncodingObject.setPreventReEncoding((boolean) loadExtensionSettingHelper("preventReEncoding", "bool", true));
+ currentHTTPEncodingObject.setEncodeMicrosoftURLEncode((boolean) loadExtensionSettingHelper("encodeMicrosoftURLEncode", "bool", false));
+ currentHTTPEncodingObject.setEncodeDespiteErrors((boolean) loadExtensionSettingHelper("encodeDespiteErrors", "bool", false));
+ currentHTTPEncodingObject.setAddACharToEmptyBody((boolean) loadExtensionSettingHelper("addACharToEmptyBody", "bool", true));
+ currentHTTPEncodingObject.setReplaceGETwithPOST((boolean) loadExtensionSettingHelper("replaceGETwithPOST", "bool", false));
+ currentHTTPEncodingObject.setEncodable_QS((boolean) loadExtensionSettingHelper("isEncodable_QS", "bool", true));
+ currentHTTPEncodingObject.setEncodable_body((boolean) loadExtensionSettingHelper("isEncodable_body", "bool", true));
+ currentHTTPEncodingObject.setEncodable_QS_delimiter((boolean) loadExtensionSettingHelper("isEncodable_QS_delimiter", "bool", false));
+ currentHTTPEncodingObject.setEncodable_urlencoded_body_delimiter((boolean) loadExtensionSettingHelper("isEncodable_urlencoded_body_delimiter", "bool", false));
+ currentHTTPEncodingObject.setEncodable_QS_equal_sign((boolean) loadExtensionSettingHelper("isEncodable_QS_equal_sign", "bool", false));
+ currentHTTPEncodingObject.setEncodable_urlencoded_body_equal_sign((boolean) loadExtensionSettingHelper("isEncodable_urlencoded_body_equal_sign", "bool", false));
+ currentHTTPEncodingObject.setURLEncoded_incoming_QS((boolean) loadExtensionSettingHelper("isURLEncoded_incoming_QS", "bool", true));
+ currentHTTPEncodingObject.setURLEncoded_incoming_body((boolean) loadExtensionSettingHelper("isURLEncoded_incoming_body", "bool", true));
+ currentHTTPEncodingObject.setURLEncoded_outgoing_QS((boolean) loadExtensionSettingHelper("isURLEncoded_outgoing_QS", "bool", true));
+ currentHTTPEncodingObject.setURLEncoded_outgoing_body((boolean) loadExtensionSettingHelper("isURLEncoded_outgoing_body", "bool", true));
+ currentHTTPEncodingObject.setAllChar_URLEncoded_outgoing_QS((boolean) loadExtensionSettingHelper("isAllChar_URLEncoded_outgoing_QS", "bool", true));
+ currentHTTPEncodingObject.setAllChar_URLEncoded_outgoing_body((boolean) loadExtensionSettingHelper("isAllChar_URLEncoded_outgoing_body", "bool", true));
+ currentHTTPEncodingObject.setTrimSpacesInContentTypeHeaderValues((boolean) loadExtensionSettingHelper("trimSpacesInContentTypeHeaderValues", "bool", true));
+ currentHTTPEncodingObject.setEncodeNameValueOnlyMultipart((boolean) loadExtensionSettingHelper("encodeNameValueOnlyMultipart", "bool", false));
+ currentHTTPEncodingObject.setUse_incoming_charset_for_request_encoding((boolean) loadExtensionSettingHelper("use_incoming_charset_for_request_encoding", "bool", true));
+
+ currentHTTPEncodingObject.setDelimiter_QS((String) loadExtensionSettingHelper("delimiter_QS", "string", "?"));
+ currentHTTPEncodingObject.setDelimiter_QS_param((String) loadExtensionSettingHelper("delimiter_QS_param", "string", "&"));
+ currentHTTPEncodingObject.setQS_equalSign((String) loadExtensionSettingHelper("QS_equalSign", "string", "="));
+ currentHTTPEncodingObject.setDelimiter_urlencoded_body_param((String) loadExtensionSettingHelper("delimiter_urlencoded_body_param", "string", "&"));
+ currentHTTPEncodingObject.setBody_param_equalSign((String) loadExtensionSettingHelper("body_param_equalSign", "string", "="));
+ currentHTTPEncodingObject.setOutgoing_request_encoding((String) loadExtensionSettingHelper("outgoing_request_encoding", "string", "ibm500"));
+ currentHTTPEncodingObject.setIncoming_request_encoding((String) loadExtensionSettingHelper("incoming_request_encoding", "string", "utf-8"));
+
+ return currentHTTPEncodingObject;
+ }
+
+}
\ No newline at end of file
diff --git a/src/burp/IBurpCollaboratorClientContext.java b/src/burp/IBurpCollaboratorClientContext.java
new file mode 100644
index 0000000..0ffe19a
--- /dev/null
+++ b/src/burp/IBurpCollaboratorClientContext.java
@@ -0,0 +1,97 @@
+package burp;
+
+/*
+ * @(#)IBurpCollaboratorClientContext.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * This interface represents an instance of a Burp Collaborator client context,
+ * which can be used to generate Burp Collaborator payloads and poll the
+ * Collaborator server for any network interactions that result from using those
+ * payloads. Extensions can obtain new instances of this class by calling
+ * IBurpExtenderCallbacks.createBurpCollaboratorClientContext()
.
+ * Note that each Burp Collaborator client context is tied to the Collaborator
+ * server configuration that was in place at the time the context was created.
+ */
+public interface IBurpCollaboratorClientContext
+{
+
+ /**
+ * This method is used to generate new Burp Collaborator payloads.
+ *
+ * @param includeCollaboratorServerLocation Specifies whether to include the
+ * Collaborator server location in the generated payload.
+ * @return The payload that was generated.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ String generatePayload(boolean includeCollaboratorServerLocation);
+
+ /**
+ * This method is used to retrieve all interactions received by the
+ * Collaborator server resulting from payloads that were generated for this
+ * context.
+ *
+ * @return The Collaborator interactions that have occurred resulting from
+ * payloads that were generated for this context.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ List fetchAllCollaboratorInteractions();
+
+ /**
+ * This method is used to retrieve interactions received by the Collaborator
+ * server resulting from a single payload that was generated for this
+ * context.
+ *
+ * @param payload The payload for which interactions will be retrieved.
+ * @return The Collaborator interactions that have occurred resulting from
+ * the given payload.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ List fetchCollaboratorInteractionsFor(String payload);
+
+ /**
+ * This method is used to retrieve all interactions made by Burp Infiltrator
+ * instrumentation resulting from payloads that were generated for this
+ * context.
+ *
+ * @return The interactions triggered by the Burp Infiltrator
+ * instrumentation that have occurred resulting from payloads that were
+ * generated for this context.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ List fetchAllInfiltratorInteractions();
+
+ /**
+ * This method is used to retrieve interactions made by Burp Infiltrator
+ * instrumentation resulting from a single payload that was generated for
+ * this context.
+ *
+ * @param payload The payload for which interactions will be retrieved.
+ * @return The interactions triggered by the Burp Infiltrator
+ * instrumentation that have occurred resulting from the given payload.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ List fetchInfiltratorInteractionsFor(String payload);
+
+ /**
+ * This method is used to retrieve the network location of the Collaborator
+ * server.
+ *
+ * @return The hostname or IP address of the Collaborator server.
+ *
+ * @throws IllegalStateException if Burp Collaborator is disabled
+ */
+ String getCollaboratorServerLocation();
+}
diff --git a/src/burp/IBurpCollaboratorInteraction.java b/src/burp/IBurpCollaboratorInteraction.java
new file mode 100644
index 0000000..4299c7b
--- /dev/null
+++ b/src/burp/IBurpCollaboratorInteraction.java
@@ -0,0 +1,41 @@
+package burp;
+
+/*
+ * @(#)IBurpCollaboratorInteraction.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.Map;
+
+/**
+ * This interface represents a network interaction that occurred with the Burp
+ * Collaborator server.
+ */
+public interface IBurpCollaboratorInteraction
+{
+
+ /**
+ * This method is used to retrieve a property of the interaction. Properties
+ * of all interactions are: interaction_id, type, client_ip, and time_stamp.
+ * Properties of DNS interactions are: query_type and raw_query. The
+ * raw_query value is Base64-encoded. Properties of HTTP interactions are:
+ * protocol, request, and response. The request and response values are
+ * Base64-encoded.
+ *
+ * @param name The name of the property to retrieve.
+ * @return A string representing the property value, or null if not present.
+ */
+ String getProperty(String name);
+
+ /**
+ * This method is used to retrieve a map containing all properties of the
+ * interaction.
+ *
+ * @return A map containing all properties of the interaction.
+ */
+ Map getProperties();
+}
diff --git a/src/burp/IBurpExtender.java b/src/burp/IBurpExtender.java
new file mode 100644
index 0000000..8cb7390
--- /dev/null
+++ b/src/burp/IBurpExtender.java
@@ -0,0 +1,31 @@
+package burp;
+
+/*
+ * @(#)IBurpExtender.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * All extensions must implement this interface.
+ *
+ * Implementations must be called BurpExtender, in the package burp, must be
+ * declared public, and must provide a default (public, no-argument)
+ * constructor.
+ */
+public interface IBurpExtender
+{
+ /**
+ * This method is invoked when the extension is loaded. It registers an
+ * instance of the
+ * IBurpExtenderCallbacks
interface, providing methods that may
+ * be invoked by the extension to perform various actions.
+ *
+ * @param callbacks An
+ * IBurpExtenderCallbacks
object.
+ */
+ void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks);
+}
diff --git a/src/burp/IBurpExtenderCallbacks.java b/src/burp/IBurpExtenderCallbacks.java
new file mode 100644
index 0000000..03c8db0
--- /dev/null
+++ b/src/burp/IBurpExtenderCallbacks.java
@@ -0,0 +1,1088 @@
+package burp;
+
+/*
+ * @(#)IBurpExtenderCallbacks.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.Component;
+import java.io.OutputStream;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This interface is used by Burp Suite to pass to extensions a set of callback
+ * methods that can be used by extensions to perform various actions within
+ * Burp.
+ *
+ * When an extension is loaded, Burp invokes its
+ * registerExtenderCallbacks()
method and passes an instance of the
+ * IBurpExtenderCallbacks
interface. The extension may then invoke
+ * the methods of this interface as required in order to extend Burp's
+ * functionality.
+ */
+public interface IBurpExtenderCallbacks
+{
+
+ /**
+ * Flag used to identify Burp Suite as a whole.
+ */
+ int TOOL_SUITE = 0x00000001;
+ /**
+ * Flag used to identify the Burp Target tool.
+ */
+ int TOOL_TARGET = 0x00000002;
+ /**
+ * Flag used to identify the Burp Proxy tool.
+ */
+ int TOOL_PROXY = 0x00000004;
+ /**
+ * Flag used to identify the Burp Spider tool.
+ */
+ int TOOL_SPIDER = 0x00000008;
+ /**
+ * Flag used to identify the Burp Scanner tool.
+ */
+ int TOOL_SCANNER = 0x00000010;
+ /**
+ * Flag used to identify the Burp Intruder tool.
+ */
+ int TOOL_INTRUDER = 0x00000020;
+ /**
+ * Flag used to identify the Burp Repeater tool.
+ */
+ int TOOL_REPEATER = 0x00000040;
+ /**
+ * Flag used to identify the Burp Sequencer tool.
+ */
+ int TOOL_SEQUENCER = 0x00000080;
+ /**
+ * Flag used to identify the Burp Decoder tool.
+ */
+ int TOOL_DECODER = 0x00000100;
+ /**
+ * Flag used to identify the Burp Comparer tool.
+ */
+ int TOOL_COMPARER = 0x00000200;
+ /**
+ * Flag used to identify the Burp Extender tool.
+ */
+ int TOOL_EXTENDER = 0x00000400;
+
+ /**
+ * This method is used to set the display name for the current extension,
+ * which will be displayed within the user interface for the Extender tool.
+ *
+ * @param name The extension name.
+ */
+ void setExtensionName(String name);
+
+ /**
+ * This method is used to obtain an IExtensionHelpers
object,
+ * which can be used by the extension to perform numerous useful tasks.
+ *
+ * @return An object containing numerous helper methods, for tasks such as
+ * building and analyzing HTTP requests.
+ */
+ IExtensionHelpers getHelpers();
+
+ /**
+ * This method is used to obtain the current extension's standard output
+ * stream. Extensions should write all output to this stream, allowing the
+ * Burp user to configure how that output is handled from within the UI.
+ *
+ * @return The extension's standard output stream.
+ */
+ OutputStream getStdout();
+
+ /**
+ * This method is used to obtain the current extension's standard error
+ * stream. Extensions should write all error messages to this stream,
+ * allowing the Burp user to configure how that output is handled from
+ * within the UI.
+ *
+ * @return The extension's standard error stream.
+ */
+ OutputStream getStderr();
+
+ /**
+ * This method prints a line of output to the current extension's standard
+ * output stream.
+ *
+ * @param output The message to print.
+ */
+ void printOutput(String output);
+
+ /**
+ * This method prints a line of output to the current extension's standard
+ * error stream.
+ *
+ * @param error The message to print.
+ */
+ void printError(String error);
+
+ /**
+ * This method is used to register a listener which will be notified of
+ * changes to the extension's state. Note: Any extensions that start
+ * background threads or open system resources (such as files or database
+ * connections) should register a listener and terminate threads / close
+ * resources when the extension is unloaded.
+ *
+ * @param listener An object created by the extension that implements the
+ * IExtensionStateListener
interface.
+ */
+ void registerExtensionStateListener(IExtensionStateListener listener);
+
+ /**
+ * This method is used to retrieve the extension state listeners that are
+ * registered by the extension.
+ *
+ * @return A list of extension state listeners that are currently registered
+ * by this extension.
+ */
+ List getExtensionStateListeners();
+
+ /**
+ * This method is used to remove an extension state listener that has been
+ * registered by the extension.
+ *
+ * @param listener The extension state listener to be removed.
+ */
+ void removeExtensionStateListener(IExtensionStateListener listener);
+
+ /**
+ * This method is used to register a listener which will be notified of
+ * requests and responses made by any Burp tool. Extensions can perform
+ * custom analysis or modification of these messages by registering an HTTP
+ * listener.
+ *
+ * @param listener An object created by the extension that implements the
+ * IHttpListener
interface.
+ */
+ void registerHttpListener(IHttpListener listener);
+
+ /**
+ * This method is used to retrieve the HTTP listeners that are registered by
+ * the extension.
+ *
+ * @return A list of HTTP listeners that are currently registered by this
+ * extension.
+ */
+ List getHttpListeners();
+
+ /**
+ * This method is used to remove an HTTP listener that has been registered
+ * by the extension.
+ *
+ * @param listener The HTTP listener to be removed.
+ */
+ void removeHttpListener(IHttpListener listener);
+
+ /**
+ * This method is used to register a listener which will be notified of
+ * requests and responses being processed by the Proxy tool. Extensions can
+ * perform custom analysis or modification of these messages, and control
+ * in-UI message interception, by registering a proxy listener.
+ *
+ * @param listener An object created by the extension that implements the
+ * IProxyListener
interface.
+ */
+ void registerProxyListener(IProxyListener listener);
+
+ /**
+ * This method is used to retrieve the Proxy listeners that are registered
+ * by the extension.
+ *
+ * @return A list of Proxy listeners that are currently registered by this
+ * extension.
+ */
+ List getProxyListeners();
+
+ /**
+ * This method is used to remove a Proxy listener that has been registered
+ * by the extension.
+ *
+ * @param listener The Proxy listener to be removed.
+ */
+ void removeProxyListener(IProxyListener listener);
+
+ /**
+ * This method is used to register a listener which will be notified of new
+ * issues that are reported by the Scanner tool. Extensions can perform
+ * custom analysis or logging of Scanner issues by registering a Scanner
+ * listener.
+ *
+ * @param listener An object created by the extension that implements the
+ * IScannerListener
interface.
+ */
+ void registerScannerListener(IScannerListener listener);
+
+ /**
+ * This method is used to retrieve the Scanner listeners that are registered
+ * by the extension.
+ *
+ * @return A list of Scanner listeners that are currently registered by this
+ * extension.
+ */
+ List getScannerListeners();
+
+ /**
+ * This method is used to remove a Scanner listener that has been registered
+ * by the extension.
+ *
+ * @param listener The Scanner listener to be removed.
+ */
+ void removeScannerListener(IScannerListener listener);
+
+ /**
+ * This method is used to register a listener which will be notified of
+ * changes to Burp's suite-wide target scope.
+ *
+ * @param listener An object created by the extension that implements the
+ * IScopeChangeListener
interface.
+ */
+ void registerScopeChangeListener(IScopeChangeListener listener);
+
+ /**
+ * This method is used to retrieve the scope change listeners that are
+ * registered by the extension.
+ *
+ * @return A list of scope change listeners that are currently registered by
+ * this extension.
+ */
+ List getScopeChangeListeners();
+
+ /**
+ * This method is used to remove a scope change listener that has been
+ * registered by the extension.
+ *
+ * @param listener The scope change listener to be removed.
+ */
+ void removeScopeChangeListener(IScopeChangeListener listener);
+
+ /**
+ * This method is used to register a factory for custom context menu items.
+ * When the user invokes a context menu anywhere within Burp, the factory
+ * will be passed details of the invocation event, and asked to provide any
+ * custom context menu items that should be shown.
+ *
+ * @param factory An object created by the extension that implements the
+ * IContextMenuFactory
interface.
+ */
+ void registerContextMenuFactory(IContextMenuFactory factory);
+
+ /**
+ * This method is used to retrieve the context menu factories that are
+ * registered by the extension.
+ *
+ * @return A list of context menu factories that are currently registered by
+ * this extension.
+ */
+ List getContextMenuFactories();
+
+ /**
+ * This method is used to remove a context menu factory that has been
+ * registered by the extension.
+ *
+ * @param factory The context menu factory to be removed.
+ */
+ void removeContextMenuFactory(IContextMenuFactory factory);
+
+ /**
+ * This method is used to register a factory for custom message editor tabs.
+ * For each message editor that already exists, or is subsequently created,
+ * within Burp, the factory will be asked to provide a new instance of an
+ * IMessageEditorTab
object, which can provide custom rendering
+ * or editing of HTTP messages.
+ *
+ * @param factory An object created by the extension that implements the
+ * IMessageEditorTabFactory
interface.
+ */
+ void registerMessageEditorTabFactory(IMessageEditorTabFactory factory);
+
+ /**
+ * This method is used to retrieve the message editor tab factories that are
+ * registered by the extension.
+ *
+ * @return A list of message editor tab factories that are currently
+ * registered by this extension.
+ */
+ List getMessageEditorTabFactories();
+
+ /**
+ * This method is used to remove a message editor tab factory that has been
+ * registered by the extension.
+ *
+ * @param factory The message editor tab factory to be removed.
+ */
+ void removeMessageEditorTabFactory(IMessageEditorTabFactory factory);
+
+ /**
+ * This method is used to register a provider of Scanner insertion points.
+ * For each base request that is actively scanned, Burp will ask the
+ * provider to provide any custom scanner insertion points that are
+ * appropriate for the request.
+ *
+ * @param provider An object created by the extension that implements the
+ * IScannerInsertionPointProvider
interface.
+ */
+ void registerScannerInsertionPointProvider(
+ IScannerInsertionPointProvider provider);
+
+ /**
+ * This method is used to retrieve the Scanner insertion point providers
+ * that are registered by the extension.
+ *
+ * @return A list of Scanner insertion point providers that are currently
+ * registered by this extension.
+ */
+ List getScannerInsertionPointProviders();
+
+ /**
+ * This method is used to remove a Scanner insertion point provider that has
+ * been registered by the extension.
+ *
+ * @param provider The Scanner insertion point provider to be removed.
+ */
+ void removeScannerInsertionPointProvider(
+ IScannerInsertionPointProvider provider);
+
+ /**
+ * This method is used to register a custom Scanner check. When performing
+ * scanning, Burp will ask the check to perform active or passive scanning
+ * on the base request, and report any Scanner issues that are identified.
+ *
+ * @param check An object created by the extension that implements the
+ * IScannerCheck
interface.
+ */
+ void registerScannerCheck(IScannerCheck check);
+
+ /**
+ * This method is used to retrieve the Scanner checks that are registered by
+ * the extension.
+ *
+ * @return A list of Scanner checks that are currently registered by this
+ * extension.
+ */
+ List getScannerChecks();
+
+ /**
+ * This method is used to remove a Scanner check that has been registered by
+ * the extension.
+ *
+ * @param check The Scanner check to be removed.
+ */
+ void removeScannerCheck(IScannerCheck check);
+
+ /**
+ * This method is used to register a factory for Intruder payloads. Each
+ * registered factory will be available within the Intruder UI for the user
+ * to select as the payload source for an attack. When this is selected, the
+ * factory will be asked to provide a new instance of an
+ * IIntruderPayloadGenerator
object, which will be used to
+ * generate payloads for the attack.
+ *
+ * @param factory An object created by the extension that implements the
+ * IIntruderPayloadGeneratorFactory
interface.
+ */
+ void registerIntruderPayloadGeneratorFactory(
+ IIntruderPayloadGeneratorFactory factory);
+
+ /**
+ * This method is used to retrieve the Intruder payload generator factories
+ * that are registered by the extension.
+ *
+ * @return A list of Intruder payload generator factories that are currently
+ * registered by this extension.
+ */
+ List
+ getIntruderPayloadGeneratorFactories();
+
+ /**
+ * This method is used to remove an Intruder payload generator factory that
+ * has been registered by the extension.
+ *
+ * @param factory The Intruder payload generator factory to be removed.
+ */
+ void removeIntruderPayloadGeneratorFactory(
+ IIntruderPayloadGeneratorFactory factory);
+
+ /**
+ * This method is used to register a custom Intruder payload processor. Each
+ * registered processor will be available within the Intruder UI for the
+ * user to select as the action for a payload processing rule.
+ *
+ * @param processor An object created by the extension that implements the
+ * IIntruderPayloadProcessor
interface.
+ */
+ void registerIntruderPayloadProcessor(IIntruderPayloadProcessor processor);
+
+ /**
+ * This method is used to retrieve the Intruder payload processors that are
+ * registered by the extension.
+ *
+ * @return A list of Intruder payload processors that are currently
+ * registered by this extension.
+ */
+ List getIntruderPayloadProcessors();
+
+ /**
+ * This method is used to remove an Intruder payload processor that has been
+ * registered by the extension.
+ *
+ * @param processor The Intruder payload processor to be removed.
+ */
+ void removeIntruderPayloadProcessor(IIntruderPayloadProcessor processor);
+
+ /**
+ * This method is used to register a custom session handling action. Each
+ * registered action will be available within the session handling rule UI
+ * for the user to select as a rule action. Users can choose to invoke an
+ * action directly in its own right, or following execution of a macro.
+ *
+ * @param action An object created by the extension that implements the
+ * ISessionHandlingAction
interface.
+ */
+ void registerSessionHandlingAction(ISessionHandlingAction action);
+
+ /**
+ * This method is used to retrieve the session handling actions that are
+ * registered by the extension.
+ *
+ * @return A list of session handling actions that are currently registered
+ * by this extension.
+ */
+ List getSessionHandlingActions();
+
+ /**
+ * This method is used to remove a session handling action that has been
+ * registered by the extension.
+ *
+ * @param action The extension session handling action to be removed.
+ */
+ void removeSessionHandlingAction(ISessionHandlingAction action);
+
+ /**
+ * This method is used to unload the extension from Burp Suite.
+ */
+ void unloadExtension();
+
+ /**
+ * This method is used to add a custom tab to the main Burp Suite window.
+ *
+ * @param tab An object created by the extension that implements the
+ * ITab
interface.
+ */
+ void addSuiteTab(ITab tab);
+
+ /**
+ * This method is used to remove a previously-added tab from the main Burp
+ * Suite window.
+ *
+ * @param tab An object created by the extension that implements the
+ * ITab
interface.
+ */
+ void removeSuiteTab(ITab tab);
+
+ /**
+ * This method is used to customize UI components in line with Burp's UI
+ * style, including font size, colors, table line spacing, etc. The action
+ * is performed recursively on any child components of the passed-in
+ * component.
+ *
+ * @param component The UI component to be customized.
+ */
+ void customizeUiComponent(Component component);
+
+ /**
+ * This method is used to create a new instance of Burp's HTTP message
+ * editor, for the extension to use in its own UI.
+ *
+ * @param controller An object created by the extension that implements the
+ * IMessageEditorController
interface. This parameter is
+ * optional and may be null
. If it is provided, then the
+ * message editor will query the controller when required to obtain details
+ * about the currently displayed message, including the
+ * IHttpService
for the message, and the associated request or
+ * response message. If a controller is not provided, then the message
+ * editor will not support context menu actions, such as sending requests to
+ * other Burp tools.
+ * @param editable Indicates whether the editor created should be editable,
+ * or used only for message viewing.
+ * @return An object that implements the IMessageEditor
+ * interface, and which the extension can use in its own UI.
+ */
+ IMessageEditor createMessageEditor(IMessageEditorController controller,
+ boolean editable);
+
+ /**
+ * This method returns the command line arguments that were passed to Burp
+ * on startup.
+ *
+ * @return The command line arguments that were passed to Burp on startup.
+ */
+ String[] getCommandLineArguments();
+
+ /**
+ * This method is used to save configuration settings for the extension in a
+ * persistent way that survives reloads of the extension and of Burp Suite.
+ * Saved settings can be retrieved using the method
+ * loadExtensionSetting()
.
+ *
+ * @param name The name of the setting.
+ * @param value The value of the setting. If this value is null
+ * then any existing setting with the specified name will be removed.
+ */
+ void saveExtensionSetting(String name, String value);
+
+ /**
+ * This method is used to load configuration settings for the extension that
+ * were saved using the method saveExtensionSetting()
.
+ *
+ * @param name The name of the setting.
+ * @return The value of the setting, or null
if no value is
+ * set.
+ */
+ String loadExtensionSetting(String name);
+
+ /**
+ * This method is used to create a new instance of Burp's plain text editor,
+ * for the extension to use in its own UI.
+ *
+ * @return An object that implements the ITextEditor
interface,
+ * and which the extension can use in its own UI.
+ */
+ ITextEditor createTextEditor();
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Repeater
+ * tool. The request will be displayed in the user interface, but will not
+ * be issued until the user initiates this action.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @param tabCaption An optional caption which will appear on the Repeater
+ * tab containing the request. If this value is null
then a
+ * default tab index will be displayed.
+ */
+ void sendToRepeater(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request,
+ String tabCaption);
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Intruder
+ * tool. The request will be displayed in the user interface, and markers
+ * for attack payloads will be placed into default locations within the
+ * request.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ */
+ void sendToIntruder(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request);
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Intruder
+ * tool. The request will be displayed in the user interface, and markers
+ * for attack payloads will be placed into the specified locations within
+ * the request.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @param payloadPositionOffsets A list of index pairs representing the
+ * payload positions to be used. Each item in the list must be an int[2]
+ * array containing the start and end offsets for the payload position.
+ */
+ void sendToIntruder(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request,
+ List payloadPositionOffsets);
+
+ /**
+ * This method can be used to send data to the Comparer tool.
+ *
+ * @param data The data to be sent to Comparer.
+ */
+ void sendToComparer(byte[] data);
+
+ /**
+ * This method can be used to send a seed URL to the Burp Spider tool. If
+ * the URL is not within the current Spider scope, the user will be asked if
+ * they wish to add the URL to the scope. If the Spider is not currently
+ * running, it will be started. The seed URL will be requested, and the
+ * Spider will process the application's response in the normal way.
+ *
+ * @param url The new seed URL to begin spidering from.
+ */
+ void sendToSpider(
+ java.net.URL url);
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Scanner tool
+ * to perform an active vulnerability scan. If the request is not within the
+ * current active scanning scope, the user will be asked if they wish to
+ * proceed with the scan.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @return The resulting scan queue item.
+ */
+ IScanQueueItem doActiveScan(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request);
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Scanner tool
+ * to perform an active vulnerability scan, based on a custom list of
+ * insertion points that are to be scanned. If the request is not within the
+ * current active scanning scope, the user will be asked if they wish to
+ * proceed with the scan.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @param insertionPointOffsets A list of index pairs representing the
+ * positions of the insertion points that should be scanned. Each item in
+ * the list must be an int[2] array containing the start and end offsets for
+ * the insertion point.
+ * @return The resulting scan queue item.
+ */
+ IScanQueueItem doActiveScan(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request,
+ List insertionPointOffsets);
+
+ /**
+ * This method can be used to send an HTTP request to the Burp Scanner tool
+ * to perform a passive vulnerability scan.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @param response The full HTTP response.
+ */
+ void doPassiveScan(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request,
+ byte[] response);
+
+ /**
+ * This method can be used to issue HTTP requests and retrieve their
+ * responses.
+ *
+ * @param httpService The HTTP service to which the request should be sent.
+ * @param request The full HTTP request.
+ * @return An object that implements the IHttpRequestResponse
+ * interface, and which the extension can query to obtain the details of the
+ * response.
+ */
+ IHttpRequestResponse makeHttpRequest(IHttpService httpService,
+ byte[] request);
+
+ /**
+ * This method can be used to issue HTTP requests and retrieve their
+ * responses.
+ *
+ * @param host The hostname of the remote HTTP server.
+ * @param port The port of the remote HTTP server.
+ * @param useHttps Flags whether the protocol is HTTPS or HTTP.
+ * @param request The full HTTP request.
+ * @return The full response retrieved from the remote server.
+ */
+ byte[] makeHttpRequest(
+ String host,
+ int port,
+ boolean useHttps,
+ byte[] request);
+
+ /**
+ * This method can be used to query whether a specified URL is within the
+ * current Suite-wide scope.
+ *
+ * @param url The URL to query.
+ * @return Returns true
if the URL is within the current
+ * Suite-wide scope.
+ */
+ boolean isInScope(java.net.URL url);
+
+ /**
+ * This method can be used to include the specified URL in the Suite-wide
+ * scope.
+ *
+ * @param url The URL to include in the Suite-wide scope.
+ */
+ void includeInScope(java.net.URL url);
+
+ /**
+ * This method can be used to exclude the specified URL from the Suite-wide
+ * scope.
+ *
+ * @param url The URL to exclude from the Suite-wide scope.
+ */
+ void excludeFromScope(java.net.URL url);
+
+ /**
+ * This method can be used to display a specified message in the Burp Suite
+ * alerts tab.
+ *
+ * @param message The alert message to display.
+ */
+ void issueAlert(String message);
+
+ /**
+ * This method returns details of all items in the Proxy history.
+ *
+ * @return The contents of the Proxy history.
+ */
+ IHttpRequestResponse[] getProxyHistory();
+
+ /**
+ * This method returns details of items in the site map.
+ *
+ * @param urlPrefix This parameter can be used to specify a URL prefix, in
+ * order to extract a specific subset of the site map. The method performs a
+ * simple case-sensitive text match, returning all site map items whose URL
+ * begins with the specified prefix. If this parameter is null, the entire
+ * site map is returned.
+ *
+ * @return Details of items in the site map.
+ */
+ IHttpRequestResponse[] getSiteMap(String urlPrefix);
+
+ /**
+ * This method returns all of the current scan issues for URLs matching the
+ * specified literal prefix.
+ *
+ * @param urlPrefix This parameter can be used to specify a URL prefix, in
+ * order to extract a specific subset of scan issues. The method performs a
+ * simple case-sensitive text match, returning all scan issues whose URL
+ * begins with the specified prefix. If this parameter is null, all issues
+ * are returned.
+ * @return Details of the scan issues.
+ */
+ IScanIssue[] getScanIssues(String urlPrefix);
+
+ /**
+ * This method is used to generate a report for the specified Scanner
+ * issues. The report format can be specified. For all other reporting
+ * options, the default settings that appear in the reporting UI wizard are
+ * used.
+ *
+ * @param format The format to be used in the report. Accepted values are
+ * HTML and XML.
+ * @param issues The Scanner issues to be reported.
+ * @param file The file to which the report will be saved.
+ */
+ void generateScanReport(String format, IScanIssue[] issues,
+ java.io.File file);
+
+ /**
+ * This method is used to retrieve the contents of Burp's session handling
+ * cookie jar. Extensions that provide an
+ * ISessionHandlingAction
can query and update the cookie jar
+ * in order to handle unusual session handling mechanisms.
+ *
+ * @return A list of ICookie
objects representing the contents
+ * of Burp's session handling cookie jar.
+ */
+ List getCookieJarContents();
+
+ /**
+ * This method is used to update the contents of Burp's session handling
+ * cookie jar. Extensions that provide an
+ * ISessionHandlingAction
can query and update the cookie jar
+ * in order to handle unusual session handling mechanisms.
+ *
+ * @param cookie An ICookie
object containing details of the
+ * cookie to be updated. If the cookie jar already contains a cookie that
+ * matches the specified domain and name, then that cookie will be updated
+ * with the new value and expiration, unless the new value is
+ * null
, in which case the cookie will be removed. If the
+ * cookie jar does not already contain a cookie that matches the specified
+ * domain and name, then the cookie will be added.
+ */
+ void updateCookieJar(ICookie cookie);
+
+ /**
+ * This method can be used to add an item to Burp's site map with the
+ * specified request/response details. This will overwrite the details of
+ * any existing matching item in the site map.
+ *
+ * @param item Details of the item to be added to the site map
+ */
+ void addToSiteMap(IHttpRequestResponse item);
+
+ /**
+ * This method can be used to restore Burp's state from a specified saved
+ * state file. This method blocks until the restore operation is completed,
+ * and must not be called from the event dispatch thread.
+ *
+ * @param file The file containing Burp's saved state.
+ * @deprecated State files have been replaced with Burp project files.
+ */
+ @Deprecated
+ void restoreState(java.io.File file);
+
+ /**
+ * This method can be used to save Burp's state to a specified file. This
+ * method blocks until the save operation is completed, and must not be
+ * called from the event dispatch thread.
+ *
+ * @param file The file to save Burp's state in.
+ * @deprecated State files have been replaced with Burp project files.
+ */
+ @Deprecated
+ void saveState(java.io.File file);
+
+ /**
+ * This method is no longer supported. Please use saveConfigAsJson() instead.
+ *
+ * @return A Map of name/value Strings reflecting Burp's current
+ * configuration.
+ * @deprecated Use saveConfigAsJson()
instead.
+ */
+ @Deprecated
+ Map saveConfig();
+
+ /**
+ * This method is no longer supported. Please use loadConfigFromJson() instead.
+ *
+ * @param config A map of name/value Strings to use as Burp's new
+ * configuration.
+ * @deprecated Use loadConfigFromJson()
instead.
+ */
+ @Deprecated
+ void loadConfig(Map config);
+
+ /**
+ * This method causes Burp to save its current project-level configuration
+ * in JSON format. This is the same format that can be saved and loaded via
+ * the Burp user interface. To include only certain sections of the
+ * configuration, you can optionally supply the path to each section that
+ * should be included, for example: "project_options.connections". If no
+ * paths are provided, then the entire configuration will be saved.
+ *
+ * @param configPaths A list of Strings representing the path to each
+ * configuration section that should be included.
+ * @return A String representing the current configuration in JSON format.
+ */
+ String saveConfigAsJson(String... configPaths);
+
+ /**
+ * This method causes Burp to load a new project-level configuration from
+ * the JSON String provided. This is the same format that can be saved and
+ * loaded via the Burp user interface. Partial configurations are
+ * acceptable, and any settings not specified will be left unmodified.
+ *
+ * Any user-level configuration options contained in the input will be
+ * ignored.
+ *
+ * @param config A JSON String containing the new configuration.
+ */
+ void loadConfigFromJson(String config);
+
+ /**
+ * This method sets the master interception mode for Burp Proxy.
+ *
+ * @param enabled Indicates whether interception of Proxy messages should be
+ * enabled.
+ */
+ void setProxyInterceptionEnabled(boolean enabled);
+
+ /**
+ * This method retrieves information about the version of Burp in which the
+ * extension is running. It can be used by extensions to dynamically adjust
+ * their behavior depending on the functionality and APIs supported by the
+ * current version.
+ *
+ * @return An array of Strings comprised of: the product name (e.g. Burp
+ * Suite Professional), the major version (e.g. 1.5), the minor version
+ * (e.g. 03)
+ */
+ String[] getBurpVersion();
+
+ /**
+ * This method retrieves the absolute path name of the file from which the
+ * current extension was loaded.
+ *
+ * @return The absolute path name of the file from which the current
+ * extension was loaded.
+ */
+ String getExtensionFilename();
+
+ /**
+ * This method determines whether the current extension was loaded as a BApp
+ * (a Burp App from the BApp Store).
+ *
+ * @return Returns true if the current extension was loaded as a BApp.
+ */
+ boolean isExtensionBapp();
+
+ /**
+ * This method can be used to shut down Burp programmatically, with an
+ * optional prompt to the user. If the method returns, the user canceled the
+ * shutdown prompt.
+ *
+ * @param promptUser Indicates whether to prompt the user to confirm the
+ * shutdown.
+ */
+ void exitSuite(boolean promptUser);
+
+ /**
+ * This method is used to create a temporary file on disk containing the
+ * provided data. Extensions can use temporary files for long-term storage
+ * of runtime data, avoiding the need to retain that data in memory.
+ *
+ * @param buffer The data to be saved to a temporary file.
+ * @return An object that implements the ITempFile
interface.
+ */
+ ITempFile saveToTempFile(byte[] buffer);
+
+ /**
+ * This method is used to save the request and response of an
+ * IHttpRequestResponse
object to temporary files, so that they
+ * are no longer held in memory. Extensions can used this method to convert
+ * IHttpRequestResponse
objects into a form suitable for
+ * long-term storage.
+ *
+ * @param httpRequestResponse The IHttpRequestResponse
object
+ * whose request and response messages are to be saved to temporary files.
+ * @return An object that implements the
+ * IHttpRequestResponsePersisted
interface.
+ */
+ IHttpRequestResponsePersisted saveBuffersToTempFiles(
+ IHttpRequestResponse httpRequestResponse);
+
+ /**
+ * This method is used to apply markers to an HTTP request or response, at
+ * offsets into the message that are relevant for some particular purpose.
+ * Markers are used in various situations, such as specifying Intruder
+ * payload positions, Scanner insertion points, and highlights in Scanner
+ * issues.
+ *
+ * @param httpRequestResponse The IHttpRequestResponse
object
+ * to which the markers should be applied.
+ * @param requestMarkers A list of index pairs representing the offsets of
+ * markers to be applied to the request message. Each item in the list must
+ * be an int[2] array containing the start and end offsets for the marker.
+ * The markers in the list should be in sequence and not overlapping. This
+ * parameter is optional and may be null
if no request markers
+ * are required.
+ * @param responseMarkers A list of index pairs representing the offsets of
+ * markers to be applied to the response message. Each item in the list must
+ * be an int[2] array containing the start and end offsets for the marker.
+ * The markers in the list should be in sequence and not overlapping. This
+ * parameter is optional and may be null
if no response markers
+ * are required.
+ * @return An object that implements the
+ * IHttpRequestResponseWithMarkers
interface.
+ */
+ IHttpRequestResponseWithMarkers applyMarkers(
+ IHttpRequestResponse httpRequestResponse,
+ List requestMarkers,
+ List responseMarkers);
+
+ /**
+ * This method is used to obtain the descriptive name for the Burp tool
+ * identified by the tool flag provided.
+ *
+ * @param toolFlag A flag identifying a Burp tool ( TOOL_PROXY
,
+ * TOOL_SCANNER
, etc.). Tool flags are defined within this
+ * interface.
+ * @return The descriptive name for the specified tool.
+ */
+ String getToolName(int toolFlag);
+
+ /**
+ * This method is used to register a new Scanner issue. Note:
+ * Wherever possible, extensions should implement custom Scanner checks
+ * using IScannerCheck
and report issues via those checks, so
+ * as to integrate with Burp's user-driven workflow, and ensure proper
+ * consolidation of duplicate reported issues. This method is only designed
+ * for tasks outside of the normal testing workflow, such as importing
+ * results from other scanning tools.
+ *
+ * @param issue An object created by the extension that implements the
+ * IScanIssue
interface.
+ */
+ void addScanIssue(IScanIssue issue);
+
+ /**
+ * This method is used to create a new Burp Collaborator client context,
+ * which can be used to generate Burp Collaborator payloads and poll the
+ * Collaborator server for any network interactions that result from using
+ * those payloads.
+ *
+ * @return A new instance of IBurpCollaboratorClientContext
+ * that can be used to generate Collaborator payloads and retrieve
+ * interactions.
+ */
+ IBurpCollaboratorClientContext createBurpCollaboratorClientContext();
+
+ /**
+ * This method parses the specified request and returns details of each
+ * request parameter.
+ *
+ * @param request The request to be parsed.
+ * @return An array of: String[] { name, value, type }
+ * containing details of the parameters contained within the request.
+ * @deprecated Use IExtensionHelpers.analyzeRequest()
instead.
+ */
+ @Deprecated
+ String[][] getParameters(byte[] request);
+
+ /**
+ * This method parses the specified request and returns details of each HTTP
+ * header.
+ *
+ * @param message The request to be parsed.
+ * @return An array of HTTP headers.
+ * @deprecated Use IExtensionHelpers.analyzeRequest()
or
+ * IExtensionHelpers.analyzeResponse()
instead.
+ */
+ @Deprecated
+ String[] getHeaders(byte[] message);
+
+ /**
+ * This method can be used to register a new menu item which will appear on
+ * the various context menus that are used throughout Burp Suite to handle
+ * user-driven actions.
+ *
+ * @param menuItemCaption The caption to be displayed on the menu item.
+ * @param menuItemHandler The handler to be invoked when the user clicks on
+ * the menu item.
+ * @deprecated Use registerContextMenuFactory()
instead.
+ */
+ @Deprecated
+ void registerMenuItem(
+ String menuItemCaption,
+ IMenuItemHandler menuItemHandler);
+}
diff --git a/src/burp/IContextMenuFactory.java b/src/burp/IContextMenuFactory.java
new file mode 100644
index 0000000..1ff9f0f
--- /dev/null
+++ b/src/burp/IContextMenuFactory.java
@@ -0,0 +1,39 @@
+package burp;
+
+/*
+ * @(#)IContextMenuFactory.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+
+import javax.swing.JMenuItem;
+import java.util.List;
+
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerContextMenuFactory()
to register
+ * a factory for custom context menu items.
+ */
+public interface IContextMenuFactory
+{
+ /**
+ * This method will be called by Burp when the user invokes a context menu
+ * anywhere within Burp. The factory can then provide any custom context
+ * menu items that should be displayed in the context menu, based on the
+ * details of the menu invocation.
+ *
+ * @param invocation An object that implements the
+ * IContextMenuInvocation
interface, which the extension can
+ * query to obtain details of the context menu invocation.
+ * @return A list of custom menu items (which may include sub-menus,
+ * checkbox menu items, etc.) that should be displayed. Extensions may
+ * return
+ * null
from this method, to indicate that no menu items are
+ * required.
+ */
+ List createMenuItems(IContextMenuInvocation invocation);
+}
diff --git a/src/burp/IContextMenuInvocation.java b/src/burp/IContextMenuInvocation.java
new file mode 100644
index 0000000..032d107
--- /dev/null
+++ b/src/burp/IContextMenuInvocation.java
@@ -0,0 +1,156 @@
+package burp;
+
+/*
+ * @(#)IContextMenuInvocation.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.event.InputEvent;
+
+/**
+ * This interface is used when Burp calls into an extension-provided
+ * IContextMenuFactory
with details of a context menu invocation.
+ * The custom context menu factory can query this interface to obtain details of
+ * the invocation event, in order to determine what menu items should be
+ * displayed.
+ */
+public interface IContextMenuInvocation
+{
+ /**
+ * Used to indicate that the context menu is being invoked in a request
+ * editor.
+ */
+ static final byte CONTEXT_MESSAGE_EDITOR_REQUEST = 0;
+ /**
+ * Used to indicate that the context menu is being invoked in a response
+ * editor.
+ */
+ static final byte CONTEXT_MESSAGE_EDITOR_RESPONSE = 1;
+ /**
+ * Used to indicate that the context menu is being invoked in a non-editable
+ * request viewer.
+ */
+ static final byte CONTEXT_MESSAGE_VIEWER_REQUEST = 2;
+ /**
+ * Used to indicate that the context menu is being invoked in a non-editable
+ * response viewer.
+ */
+ static final byte CONTEXT_MESSAGE_VIEWER_RESPONSE = 3;
+ /**
+ * Used to indicate that the context menu is being invoked in the Target
+ * site map tree.
+ */
+ static final byte CONTEXT_TARGET_SITE_MAP_TREE = 4;
+ /**
+ * Used to indicate that the context menu is being invoked in the Target
+ * site map table.
+ */
+ static final byte CONTEXT_TARGET_SITE_MAP_TABLE = 5;
+ /**
+ * Used to indicate that the context menu is being invoked in the Proxy
+ * history.
+ */
+ static final byte CONTEXT_PROXY_HISTORY = 6;
+ /**
+ * Used to indicate that the context menu is being invoked in the Scanner
+ * results.
+ */
+ static final byte CONTEXT_SCANNER_RESULTS = 7;
+ /**
+ * Used to indicate that the context menu is being invoked in the Intruder
+ * payload positions editor.
+ */
+ static final byte CONTEXT_INTRUDER_PAYLOAD_POSITIONS = 8;
+ /**
+ * Used to indicate that the context menu is being invoked in an Intruder
+ * attack results.
+ */
+ static final byte CONTEXT_INTRUDER_ATTACK_RESULTS = 9;
+ /**
+ * Used to indicate that the context menu is being invoked in a search
+ * results window.
+ */
+ static final byte CONTEXT_SEARCH_RESULTS = 10;
+
+ /**
+ * This method can be used to retrieve the native Java input event that was
+ * the trigger for the context menu invocation.
+ *
+ * @return The InputEvent
that was the trigger for the context
+ * menu invocation.
+ */
+ InputEvent getInputEvent();
+
+ /**
+ * This method can be used to retrieve the Burp tool within which the
+ * context menu was invoked.
+ *
+ * @return A flag indicating the Burp tool within which the context menu was
+ * invoked. Burp tool flags are defined in the
+ * IBurpExtenderCallbacks
interface.
+ */
+ int getToolFlag();
+
+ /**
+ * This method can be used to retrieve the context within which the menu was
+ * invoked.
+ *
+ * @return An index indicating the context within which the menu was
+ * invoked. The indices used are defined within this interface.
+ */
+ byte getInvocationContext();
+
+ /**
+ * This method can be used to retrieve the bounds of the user's selection
+ * into the current message, if applicable.
+ *
+ * @return An int[2] array containing the start and end offsets of the
+ * user's selection in the current message. If the user has not made any
+ * selection in the current message, both offsets indicate the position of
+ * the caret within the editor. If the menu is not being invoked from a
+ * message editor, the method returns null
.
+ */
+ int[] getSelectionBounds();
+
+ /**
+ * This method can be used to retrieve details of the HTTP requests /
+ * responses that were shown or selected by the user when the context menu
+ * was invoked.
+ *
+ * Note: For performance reasons, the objects returned from this
+ * method are tied to the originating context of the messages within the
+ * Burp UI. For example, if a context menu is invoked on the Proxy intercept
+ * panel, then the
+ * IHttpRequestResponse
returned by this method will reflect
+ * the current contents of the interception panel, and this will change when
+ * the current message has been forwarded or dropped. If your extension
+ * needs to store details of the message for which the context menu has been
+ * invoked, then you should query those details from the
+ * IHttpRequestResponse
at the time of invocation, or you
+ * should use
+ * IBurpExtenderCallbacks.saveBuffersToTempFiles()
to create a
+ * persistent read-only copy of the
+ * IHttpRequestResponse
.
+ *
+ * @return An array of IHttpRequestResponse
objects
+ * representing the items that were shown or selected by the user when the
+ * context menu was invoked. This method returns null
if no
+ * messages are applicable to the invocation.
+ */
+ IHttpRequestResponse[] getSelectedMessages();
+
+ /**
+ * This method can be used to retrieve details of the Scanner issues that
+ * were selected by the user when the context menu was invoked.
+ *
+ * @return An array of IScanIssue
objects representing the
+ * issues that were selected by the user when the context menu was invoked.
+ * This method returns null
if no Scanner issues are applicable
+ * to the invocation.
+ */
+ IScanIssue[] getSelectedIssues();
+}
diff --git a/src/burp/ICookie.java b/src/burp/ICookie.java
new file mode 100644
index 0000000..8c3aaa1
--- /dev/null
+++ b/src/burp/ICookie.java
@@ -0,0 +1,61 @@
+package burp;
+
+/*
+ * @(#)ICookie.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.Date;
+
+/**
+ * This interface is used to hold details about an HTTP cookie.
+ */
+public interface ICookie
+{
+ /**
+ * This method is used to retrieve the domain for which the cookie is in
+ * scope.
+ *
+ * @return The domain for which the cookie is in scope. Note: For
+ * cookies that have been analyzed from responses (by calling
+ * IExtensionHelpers.analyzeResponse()
and then
+ * IResponseInfo.getCookies()
, the domain will be
+ * null
if the response did not explicitly set a domain
+ * attribute for the cookie.
+ */
+ String getDomain();
+
+ /**
+ * This method is used to retrieve the path for which the cookie is in
+ * scope.
+ *
+ * @return The path for which the cookie is in scope or null if none is set.
+ */
+ String getPath();
+
+ /**
+ * This method is used to retrieve the expiration time for the cookie.
+ *
+ * @return The expiration time for the cookie, or
+ * null
if none is set (i.e., for non-persistent session
+ * cookies).
+ */
+ Date getExpiration();
+
+ /**
+ * This method is used to retrieve the name of the cookie.
+ *
+ * @return The name of the cookie.
+ */
+ String getName();
+
+ /**
+ * This method is used to retrieve the value of the cookie.
+ * @return The value of the cookie.
+ */
+ String getValue();
+}
diff --git a/src/burp/IExtensionHelpers.java b/src/burp/IExtensionHelpers.java
new file mode 100644
index 0000000..49beb97
--- /dev/null
+++ b/src/burp/IExtensionHelpers.java
@@ -0,0 +1,356 @@
+package burp;
+
+/*
+ * @(#)IExtensionHelpers.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.net.URL;
+import java.util.List;
+
+/**
+ * This interface contains a number of helper methods, which extensions can use
+ * to assist with various common tasks that arise for Burp extensions.
+ *
+ * Extensions can call IBurpExtenderCallbacks.getHelpers
to obtain
+ * an instance of this interface.
+ */
+public interface IExtensionHelpers
+{
+
+ /**
+ * This method can be used to analyze an HTTP request, and obtain various
+ * key details about it.
+ *
+ * @param request An IHttpRequestResponse
object containing the
+ * request to be analyzed.
+ * @return An IRequestInfo
object that can be queried to obtain
+ * details about the request.
+ */
+ IRequestInfo analyzeRequest(IHttpRequestResponse request);
+
+ /**
+ * This method can be used to analyze an HTTP request, and obtain various
+ * key details about it.
+ *
+ * @param httpService The HTTP service associated with the request. This is
+ * optional and may be null
, in which case the resulting
+ * IRequestInfo
object will not include the full request URL.
+ * @param request The request to be analyzed.
+ * @return An IRequestInfo
object that can be queried to obtain
+ * details about the request.
+ */
+ IRequestInfo analyzeRequest(IHttpService httpService, byte[] request);
+
+ /**
+ * This method can be used to analyze an HTTP request, and obtain various
+ * key details about it. The resulting IRequestInfo
object will
+ * not include the full request URL. To obtain the full URL, use one of the
+ * other overloaded analyzeRequest()
methods.
+ *
+ * @param request The request to be analyzed.
+ * @return An IRequestInfo
object that can be queried to obtain
+ * details about the request.
+ */
+ IRequestInfo analyzeRequest(byte[] request);
+
+ /**
+ * This method can be used to analyze an HTTP response, and obtain various
+ * key details about it.
+ *
+ * @param response The response to be analyzed.
+ * @return An IResponseInfo
object that can be queried to
+ * obtain details about the response.
+ */
+ IResponseInfo analyzeResponse(byte[] response);
+
+ /**
+ * This method can be used to retrieve details of a specified parameter
+ * within an HTTP request. Note: Use analyzeRequest()
to
+ * obtain details of all parameters within the request.
+ *
+ * @param request The request to be inspected for the specified parameter.
+ * @param parameterName The name of the parameter to retrieve.
+ * @return An IParameter
object that can be queried to obtain
+ * details about the parameter, or null
if the parameter was
+ * not found.
+ */
+ IParameter getRequestParameter(byte[] request, String parameterName);
+
+ /**
+ * This method can be used to URL-decode the specified data.
+ *
+ * @param data The data to be decoded.
+ * @return The decoded data.
+ */
+ String urlDecode(String data);
+
+ /**
+ * This method can be used to URL-encode the specified data. Any characters
+ * that do not need to be encoded within HTTP requests are not encoded.
+ *
+ * @param data The data to be encoded.
+ * @return The encoded data.
+ */
+ String urlEncode(String data);
+
+ /**
+ * This method can be used to URL-decode the specified data.
+ *
+ * @param data The data to be decoded.
+ * @return The decoded data.
+ */
+ byte[] urlDecode(byte[] data);
+
+ /**
+ * This method can be used to URL-encode the specified data. Any characters
+ * that do not need to be encoded within HTTP requests are not encoded.
+ *
+ * @param data The data to be encoded.
+ * @return The encoded data.
+ */
+ byte[] urlEncode(byte[] data);
+
+ /**
+ * This method can be used to Base64-decode the specified data.
+ *
+ * @param data The data to be decoded.
+ * @return The decoded data.
+ */
+ byte[] base64Decode(String data);
+
+ /**
+ * This method can be used to Base64-decode the specified data.
+ *
+ * @param data The data to be decoded.
+ * @return The decoded data.
+ */
+ byte[] base64Decode(byte[] data);
+
+ /**
+ * This method can be used to Base64-encode the specified data.
+ *
+ * @param data The data to be encoded.
+ * @return The encoded data.
+ */
+ String base64Encode(String data);
+
+ /**
+ * This method can be used to Base64-encode the specified data.
+ *
+ * @param data The data to be encoded.
+ * @return The encoded data.
+ */
+ String base64Encode(byte[] data);
+
+ /**
+ * This method can be used to convert data from String form into an array of
+ * bytes. The conversion does not reflect any particular character set, and
+ * a character with the hex representation 0xWXYZ will always be converted
+ * into a byte with the representation 0xYZ. It performs the opposite
+ * conversion to the method bytesToString()
, and byte-based
+ * data that is converted to a String and back again using these two methods
+ * is guaranteed to retain its integrity (which may not be the case with
+ * conversions that reflect a given character set).
+ *
+ * @param data The data to be converted.
+ * @return The converted data.
+ */
+ byte[] stringToBytes(String data);
+
+ /**
+ * This method can be used to convert data from an array of bytes into
+ * String form. The conversion does not reflect any particular character
+ * set, and a byte with the representation 0xYZ will always be converted
+ * into a character with the hex representation 0x00YZ. It performs the
+ * opposite conversion to the method stringToBytes()
, and
+ * byte-based data that is converted to a String and back again using these
+ * two methods is guaranteed to retain its integrity (which may not be the
+ * case with conversions that reflect a given character set).
+ *
+ * @param data The data to be converted.
+ * @return The converted data.
+ */
+ String bytesToString(byte[] data);
+
+ /**
+ * This method searches a piece of data for the first occurrence of a
+ * specified pattern. It works on byte-based data in a way that is similar
+ * to the way the native Java method String.indexOf()
works on
+ * String-based data.
+ *
+ * @param data The data to be searched.
+ * @param pattern The pattern to be searched for.
+ * @param caseSensitive Flags whether or not the search is case-sensitive.
+ * @param from The offset within data
where the search should
+ * begin.
+ * @param to The offset within data
where the search should
+ * end.
+ * @return The offset of the first occurrence of the pattern within the
+ * specified bounds, or -1 if no match is found.
+ */
+ int indexOf(byte[] data,
+ byte[] pattern,
+ boolean caseSensitive,
+ int from,
+ int to);
+
+ /**
+ * This method builds an HTTP message containing the specified headers and
+ * message body. If applicable, the Content-Length header will be added or
+ * updated, based on the length of the body.
+ *
+ * @param headers A list of headers to include in the message.
+ * @param body The body of the message, of null
if the message
+ * has an empty body.
+ * @return The resulting full HTTP message.
+ */
+ byte[] buildHttpMessage(List headers, byte[] body);
+
+ /**
+ * This method creates a GET request to the specified URL. The headers used
+ * in the request are determined by the Request headers settings as
+ * configured in Burp Spider's options.
+ *
+ * @param url The URL to which the request should be made.
+ * @return A request to the specified URL.
+ */
+ byte[] buildHttpRequest(URL url);
+
+ /**
+ * This method adds a new parameter to an HTTP request, and if appropriate
+ * updates the Content-Length header.
+ *
+ * @param request The request to which the parameter should be added.
+ * @param parameter An IParameter
object containing details of
+ * the parameter to be added. Supported parameter types are:
+ * PARAM_URL
, PARAM_BODY
and
+ * PARAM_COOKIE
.
+ * @return A new HTTP request with the new parameter added.
+ */
+ byte[] addParameter(byte[] request, IParameter parameter);
+
+ /**
+ * This method removes a parameter from an HTTP request, and if appropriate
+ * updates the Content-Length header.
+ *
+ * @param request The request from which the parameter should be removed.
+ * @param parameter An IParameter
object containing details of
+ * the parameter to be removed. Supported parameter types are:
+ * PARAM_URL
, PARAM_BODY
and
+ * PARAM_COOKIE
.
+ * @return A new HTTP request with the parameter removed.
+ */
+ byte[] removeParameter(byte[] request, IParameter parameter);
+
+ /**
+ * This method updates the value of a parameter within an HTTP request, and
+ * if appropriate updates the Content-Length header. Note: This
+ * method can only be used to update the value of an existing parameter of a
+ * specified type. If you need to change the type of an existing parameter,
+ * you should first call removeParameter()
to remove the
+ * parameter with the old type, and then call addParameter()
to
+ * add a parameter with the new type.
+ *
+ * @param request The request containing the parameter to be updated.
+ * @param parameter An IParameter
object containing details of
+ * the parameter to be updated. Supported parameter types are:
+ * PARAM_URL
, PARAM_BODY
and
+ * PARAM_COOKIE
.
+ * @return A new HTTP request with the parameter updated.
+ */
+ byte[] updateParameter(byte[] request, IParameter parameter);
+
+ /**
+ * This method can be used to toggle a request's method between GET and
+ * POST. Parameters are relocated between the URL query string and message
+ * body as required, and the Content-Length header is created or removed as
+ * applicable.
+ *
+ * @param request The HTTP request whose method should be toggled.
+ * @return A new HTTP request using the toggled method.
+ */
+ byte[] toggleRequestMethod(byte[] request);
+
+ /**
+ * This method constructs an IHttpService
object based on the
+ * details provided.
+ *
+ * @param host The HTTP service host.
+ * @param port The HTTP service port.
+ * @param protocol The HTTP service protocol.
+ * @return An IHttpService
object based on the details
+ * provided.
+ */
+ IHttpService buildHttpService(String host, int port, String protocol);
+
+ /**
+ * This method constructs an IHttpService
object based on the
+ * details provided.
+ *
+ * @param host The HTTP service host.
+ * @param port The HTTP service port.
+ * @param useHttps Flags whether the HTTP service protocol is HTTPS or HTTP.
+ * @return An IHttpService
object based on the details
+ * provided.
+ */
+ IHttpService buildHttpService(String host, int port, boolean useHttps);
+
+ /**
+ * This method constructs an IParameter
object based on the
+ * details provided.
+ *
+ * @param name The parameter name.
+ * @param value The parameter value.
+ * @param type The parameter type, as defined in the IParameter
+ * interface.
+ * @return An IParameter
object based on the details provided.
+ */
+ IParameter buildParameter(String name, String value, byte type);
+
+ /**
+ * This method constructs an IScannerInsertionPoint
object
+ * based on the details provided. It can be used to quickly create a simple
+ * insertion point based on a fixed payload location within a base request.
+ *
+ * @param insertionPointName The name of the insertion point.
+ * @param baseRequest The request from which to build scan requests.
+ * @param from The offset of the start of the payload location.
+ * @param to The offset of the end of the payload location.
+ * @return An IScannerInsertionPoint
object based on the
+ * details provided.
+ */
+ IScannerInsertionPoint makeScannerInsertionPoint(
+ String insertionPointName,
+ byte[] baseRequest,
+ int from,
+ int to);
+
+ /**
+ * This method analyzes one or more responses to identify variations in a
+ * number of attributes and returns an IResponseVariations
+ * object that can be queried to obtain details of the variations.
+ *
+ * @param responses The responses to analyze.
+ * @return An IResponseVariations
object representing the
+ * variations in the responses.
+ */
+ IResponseVariations analyzeResponseVariations(byte[]... responses);
+
+ /**
+ * This method analyzes one or more responses to identify the number of
+ * occurrences of the specified keywords and returns an
+ * IResponseKeywords
object that can be queried to obtain
+ * details of the number of occurrences of each keyword.
+ *
+ * @param keywords The keywords to look for.
+ * @param responses The responses to analyze.
+ * @return An IResponseKeywords
object representing the counts
+ * of the keywords appearing in the responses.
+ */
+ IResponseKeywords analyzeResponseKeywords(List keywords, byte[]... responses);
+}
diff --git a/src/burp/IExtensionStateListener.java b/src/burp/IExtensionStateListener.java
new file mode 100644
index 0000000..dad60ee
--- /dev/null
+++ b/src/burp/IExtensionStateListener.java
@@ -0,0 +1,27 @@
+package burp;
+
+/*
+ * @(#)IExtensionStateListener.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerExtensionStateListener()
to
+ * register an extension state listener. The listener will be notified of
+ * changes to the extension's state. Note: Any extensions that start
+ * background threads or open system resources (such as files or database
+ * connections) should register a listener and terminate threads / close
+ * resources when the extension is unloaded.
+ */
+public interface IExtensionStateListener
+{
+ /**
+ * This method is called when the extension is unloaded.
+ */
+ void extensionUnloaded();
+}
diff --git a/src/burp/IHttpListener.java b/src/burp/IHttpListener.java
new file mode 100644
index 0000000..b781c12
--- /dev/null
+++ b/src/burp/IHttpListener.java
@@ -0,0 +1,37 @@
+package burp;
+
+/*
+ * @(#)IHttpListener.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerHttpListener()
to register an
+ * HTTP listener. The listener will be notified of requests and responses made
+ * by any Burp tool. Extensions can perform custom analysis or modification of
+ * these messages by registering an HTTP listener.
+ */
+public interface IHttpListener
+{
+ /**
+ * This method is invoked when an HTTP request is about to be issued, and
+ * when an HTTP response has been received.
+ *
+ * @param toolFlag A flag indicating the Burp tool that issued the request.
+ * Burp tool flags are defined in the
+ * IBurpExtenderCallbacks
interface.
+ * @param messageIsRequest Flags whether the method is being invoked for a
+ * request or response.
+ * @param messageInfo Details of the request / response to be processed.
+ * Extensions can call the setter methods on this object to update the
+ * current message and so modify Burp's behavior.
+ */
+ void processHttpMessage(int toolFlag,
+ boolean messageIsRequest,
+ IHttpRequestResponse messageInfo);
+}
diff --git a/src/burp/IHttpRequestResponse.java b/src/burp/IHttpRequestResponse.java
new file mode 100644
index 0000000..7a239de
--- /dev/null
+++ b/src/burp/IHttpRequestResponse.java
@@ -0,0 +1,102 @@
+package burp;
+
+/*
+ * @(#)IHttpRequestResponse.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to retrieve and update details about HTTP messages.
+ *
+ * Note: The setter methods generally can only be used before the message
+ * has been processed, and not in read-only contexts. The getter methods
+ * relating to response details can only be used after the request has been
+ * issued.
+ */
+public interface IHttpRequestResponse
+{
+ /**
+ * This method is used to retrieve the request message.
+ *
+ * @return The request message.
+ */
+ byte[] getRequest();
+
+ /**
+ * This method is used to update the request message.
+ *
+ * @param message The new request message.
+ */
+ void setRequest(byte[] message);
+
+ /**
+ * This method is used to retrieve the response message.
+ *
+ * @return The response message.
+ */
+ byte[] getResponse();
+
+ /**
+ * This method is used to update the response message.
+ *
+ * @param message The new response message.
+ */
+ void setResponse(byte[] message);
+
+ /**
+ * This method is used to retrieve the user-annotated comment for this item,
+ * if applicable.
+ *
+ * @return The user-annotated comment for this item, or null if none is set.
+ */
+ String getComment();
+
+ /**
+ * This method is used to update the user-annotated comment for this item.
+ *
+ * @param comment The comment to be assigned to this item.
+ */
+ void setComment(String comment);
+
+ /**
+ * This method is used to retrieve the user-annotated highlight for this
+ * item, if applicable.
+ *
+ * @return The user-annotated highlight for this item, or null if none is
+ * set.
+ */
+ String getHighlight();
+
+ /**
+ * This method is used to update the user-annotated highlight for this item.
+ *
+ * @param color The highlight color to be assigned to this item. Accepted
+ * values are: red, orange, yellow, green, cyan, blue, pink, magenta, gray,
+ * or a null String to clear any existing highlight.
+ */
+ void setHighlight(String color);
+
+ /**
+ * This method is used to retrieve the HTTP service for this request /
+ * response.
+ *
+ * @return An
+ * IHttpService
object containing details of the HTTP service.
+ */
+ IHttpService getHttpService();
+
+ /**
+ * This method is used to update the HTTP service for this request /
+ * response.
+ *
+ * @param httpService An
+ * IHttpService
object containing details of the new HTTP
+ * service.
+ */
+ void setHttpService(IHttpService httpService);
+
+}
diff --git a/src/burp/IHttpRequestResponsePersisted.java b/src/burp/IHttpRequestResponsePersisted.java
new file mode 100644
index 0000000..6ba9f6f
--- /dev/null
+++ b/src/burp/IHttpRequestResponsePersisted.java
@@ -0,0 +1,25 @@
+package burp;
+
+/*
+ * @(#)IHttpRequestResponsePersisted.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used for an
+ * IHttpRequestResponse
object whose request and response messages
+ * have been saved to temporary files using
+ * IBurpExtenderCallbacks.saveBuffersToTempFiles()
.
+ */
+public interface IHttpRequestResponsePersisted extends IHttpRequestResponse
+{
+ /**
+ * This method is deprecated and no longer performs any action.
+ */
+ @Deprecated
+ void deleteTempFiles();
+}
diff --git a/src/burp/IHttpRequestResponseWithMarkers.java b/src/burp/IHttpRequestResponseWithMarkers.java
new file mode 100644
index 0000000..de06e9b
--- /dev/null
+++ b/src/burp/IHttpRequestResponseWithMarkers.java
@@ -0,0 +1,44 @@
+package burp;
+
+/*
+ * @(#)IHttpRequestResponseWithMarkers.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * This interface is used for an
+ * IHttpRequestResponse
object that has had markers applied.
+ * Extensions can create instances of this interface using
+ * IBurpExtenderCallbacks.applyMarkers()
, or provide their own
+ * implementation. Markers are used in various situations, such as specifying
+ * Intruder payload positions, Scanner insertion points, and highlights in
+ * Scanner issues.
+ */
+public interface IHttpRequestResponseWithMarkers extends IHttpRequestResponse
+{
+ /**
+ * This method returns the details of the request markers.
+ *
+ * @return A list of index pairs representing the offsets of markers for the
+ * request message. Each item in the list is an int[2] array containing the
+ * start and end offsets for the marker. The method may return
+ * null
if no request markers are defined.
+ */
+ List getRequestMarkers();
+
+ /**
+ * This method returns the details of the response markers.
+ *
+ * @return A list of index pairs representing the offsets of markers for the
+ * response message. Each item in the list is an int[2] array containing the
+ * start and end offsets for the marker. The method may return
+ * null
if no response markers are defined.
+ */
+ List getResponseMarkers();
+}
diff --git a/src/burp/IHttpService.java b/src/burp/IHttpService.java
new file mode 100644
index 0000000..d137838
--- /dev/null
+++ b/src/burp/IHttpService.java
@@ -0,0 +1,39 @@
+package burp;
+
+/*
+ * @(#)IHttpService.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to provide details about an HTTP service, to which
+ * HTTP requests can be sent.
+ */
+public interface IHttpService
+{
+ /**
+ * This method returns the hostname or IP address for the service.
+ *
+ * @return The hostname or IP address for the service.
+ */
+ String getHost();
+
+ /**
+ * This method returns the port number for the service.
+ *
+ * @return The port number for the service.
+ */
+ int getPort();
+
+ /**
+ * This method returns the protocol for the service.
+ *
+ * @return The protocol for the service. Expected values are "http" or
+ * "https".
+ */
+ String getProtocol();
+}
diff --git a/src/burp/IInterceptedProxyMessage.java b/src/burp/IInterceptedProxyMessage.java
new file mode 100644
index 0000000..cf44f4f
--- /dev/null
+++ b/src/burp/IInterceptedProxyMessage.java
@@ -0,0 +1,116 @@
+package burp;
+
+/*
+ * @(#)IInterceptedProxyMessage.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.net.InetAddress;
+
+/**
+ * This interface is used to represent an HTTP message that has been intercepted
+ * by Burp Proxy. Extensions can register an
+ * IProxyListener
to receive details of proxy messages using this
+ * interface. *
+ */
+public interface IInterceptedProxyMessage
+{
+ /**
+ * This action causes Burp Proxy to follow the current interception rules to
+ * determine the appropriate action to take for the message.
+ */
+ static final int ACTION_FOLLOW_RULES = 0;
+ /**
+ * This action causes Burp Proxy to present the message to the user for
+ * manual review or modification.
+ */
+ static final int ACTION_DO_INTERCEPT = 1;
+ /**
+ * This action causes Burp Proxy to forward the message to the remote server
+ * or client, without presenting it to the user.
+ */
+ static final int ACTION_DONT_INTERCEPT = 2;
+ /**
+ * This action causes Burp Proxy to drop the message.
+ */
+ static final int ACTION_DROP = 3;
+ /**
+ * This action causes Burp Proxy to follow the current interception rules to
+ * determine the appropriate action to take for the message, and then make a
+ * second call to processProxyMessage.
+ */
+ static final int ACTION_FOLLOW_RULES_AND_REHOOK = 0x10;
+ /**
+ * This action causes Burp Proxy to present the message to the user for
+ * manual review or modification, and then make a second call to
+ * processProxyMessage.
+ */
+ static final int ACTION_DO_INTERCEPT_AND_REHOOK = 0x11;
+ /**
+ * This action causes Burp Proxy to skip user interception, and then make a
+ * second call to processProxyMessage.
+ */
+ static final int ACTION_DONT_INTERCEPT_AND_REHOOK = 0x12;
+
+ /**
+ * This method retrieves a unique reference number for this
+ * request/response.
+ *
+ * @return An identifier that is unique to a single request/response pair.
+ * Extensions can use this to correlate details of requests and responses
+ * and perform processing on the response message accordingly.
+ */
+ int getMessageReference();
+
+ /**
+ * This method retrieves details of the intercepted message.
+ *
+ * @return An IHttpRequestResponse
object containing details of
+ * the intercepted message.
+ */
+ IHttpRequestResponse getMessageInfo();
+
+ /**
+ * This method retrieves the currently defined interception action. The
+ * default action is
+ * ACTION_FOLLOW_RULES
. If multiple proxy listeners are
+ * registered, then other listeners may already have modified the
+ * interception action before it reaches the current listener. This method
+ * can be used to determine whether this has occurred.
+ *
+ * @return The currently defined interception action. Possible values are
+ * defined within this interface.
+ */
+ int getInterceptAction();
+
+ /**
+ * This method is used to update the interception action.
+ *
+ * @param interceptAction The new interception action. Possible values are
+ * defined within this interface.
+ */
+ void setInterceptAction(int interceptAction);
+
+ /**
+ * This method retrieves the name of the Burp Proxy listener that is
+ * processing the intercepted message.
+ *
+ * @return The name of the Burp Proxy listener that is processing the
+ * intercepted message. The format is the same as that shown in the Proxy
+ * Listeners UI - for example, "127.0.0.1:8080".
+ */
+ String getListenerInterface();
+
+ /**
+ * This method retrieves the client IP address from which the request for
+ * the intercepted message was received.
+ *
+ * @return The client IP address from which the request for the intercepted
+ * message was received.
+ */
+ InetAddress getClientIpAddress();
+}
diff --git a/src/burp/IIntruderAttack.java b/src/burp/IIntruderAttack.java
new file mode 100644
index 0000000..8aa6b6b
--- /dev/null
+++ b/src/burp/IIntruderAttack.java
@@ -0,0 +1,31 @@
+package burp;
+
+/*
+ * @(#)IIntruderAttack.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to hold details about an Intruder attack.
+ */
+public interface IIntruderAttack
+{
+ /**
+ * This method is used to retrieve the HTTP service for the attack.
+ *
+ * @return The HTTP service for the attack.
+ */
+ IHttpService getHttpService();
+
+ /**
+ * This method is used to retrieve the request template for the attack.
+ *
+ * @return The request template for the attack.
+ */
+ byte[] getRequestTemplate();
+
+}
diff --git a/src/burp/IIntruderPayloadGenerator.java b/src/burp/IIntruderPayloadGenerator.java
new file mode 100644
index 0000000..7458620
--- /dev/null
+++ b/src/burp/IIntruderPayloadGenerator.java
@@ -0,0 +1,50 @@
+package burp;
+
+/*
+ * @(#)IIntruderPayloadGenerator.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used for custom Intruder payload generators. Extensions
+ * that have registered an
+ * IIntruderPayloadGeneratorFactory
must return a new instance of
+ * this interface when required as part of a new Intruder attack.
+ */
+public interface IIntruderPayloadGenerator
+{
+ /**
+ * This method is used by Burp to determine whether the payload generator is
+ * able to provide any further payloads.
+ *
+ * @return Extensions should return
+ * false
when all the available payloads have been used up,
+ * otherwise
+ * true
.
+ */
+ boolean hasMorePayloads();
+
+ /**
+ * This method is used by Burp to obtain the value of the next payload.
+ *
+ * @param baseValue The base value of the current payload position. This
+ * value may be
+ * null
if the concept of a base value is not applicable (e.g.
+ * in a battering ram attack).
+ * @return The next payload to use in the attack.
+ */
+ byte[] getNextPayload(byte[] baseValue);
+
+ /**
+ * This method is used by Burp to reset the state of the payload generator
+ * so that the next call to
+ * getNextPayload()
returns the first payload again. This
+ * method will be invoked when an attack uses the same payload generator for
+ * more than one payload position, for example in a sniper attack.
+ */
+ void reset();
+}
diff --git a/src/burp/IIntruderPayloadGeneratorFactory.java b/src/burp/IIntruderPayloadGeneratorFactory.java
new file mode 100644
index 0000000..b0ef9f0
--- /dev/null
+++ b/src/burp/IIntruderPayloadGeneratorFactory.java
@@ -0,0 +1,40 @@
+package burp;
+
+/*
+ * @(#)IIntruderPayloadGeneratorFactory.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerIntruderPayloadGeneratorFactory()
+ * to register a factory for custom Intruder payloads.
+ */
+public interface IIntruderPayloadGeneratorFactory
+{
+ /**
+ * This method is used by Burp to obtain the name of the payload generator.
+ * This will be displayed as an option within the Intruder UI when the user
+ * selects to use extension-generated payloads.
+ *
+ * @return The name of the payload generator.
+ */
+ String getGeneratorName();
+
+ /**
+ * This method is used by Burp when the user starts an Intruder attack that
+ * uses this payload generator.
+ *
+ * @param attack An
+ * IIntruderAttack
object that can be queried to obtain details
+ * about the attack in which the payload generator will be used.
+ * @return A new instance of
+ * IIntruderPayloadGenerator
that will be used to generate
+ * payloads for the attack.
+ */
+ IIntruderPayloadGenerator createNewInstance(IIntruderAttack attack);
+}
diff --git a/src/burp/IIntruderPayloadProcessor.java b/src/burp/IIntruderPayloadProcessor.java
new file mode 100644
index 0000000..bf993c9
--- /dev/null
+++ b/src/burp/IIntruderPayloadProcessor.java
@@ -0,0 +1,45 @@
+package burp;
+
+/*
+ * @(#)IIntruderPayloadProcessor.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerIntruderPayloadProcessor()
to
+ * register a custom Intruder payload processor.
+ */
+public interface IIntruderPayloadProcessor
+{
+ /**
+ * This method is used by Burp to obtain the name of the payload processor.
+ * This will be displayed as an option within the Intruder UI when the user
+ * selects to use an extension-provided payload processor.
+ *
+ * @return The name of the payload processor.
+ */
+ String getProcessorName();
+
+ /**
+ * This method is invoked by Burp each time the processor should be applied
+ * to an Intruder payload.
+ *
+ * @param currentPayload The value of the payload to be processed.
+ * @param originalPayload The value of the original payload prior to
+ * processing by any already-applied processing rules.
+ * @param baseValue The base value of the payload position, which will be
+ * replaced with the current payload.
+ * @return The value of the processed payload. This may be
+ * null
to indicate that the current payload should be skipped,
+ * and the attack will move directly to the next payload.
+ */
+ byte[] processPayload(
+ byte[] currentPayload,
+ byte[] originalPayload,
+ byte[] baseValue);
+}
diff --git a/src/burp/IMenuItemHandler.java b/src/burp/IMenuItemHandler.java
new file mode 100644
index 0000000..34313df
--- /dev/null
+++ b/src/burp/IMenuItemHandler.java
@@ -0,0 +1,36 @@
+package burp;
+
+/*
+ * @(#)IMenuItemHandler.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerMenuItem()
to register a custom
+ * context menu item.
+ *
+ * @deprecated Use
+ * IContextMenuFactory
instead.
+ */
+@Deprecated
+public interface IMenuItemHandler
+{
+ /**
+ * This method is invoked by Burp Suite when the user clicks on a custom
+ * menu item which the extension has registered with Burp.
+ *
+ * @param menuItemCaption The caption of the menu item which was clicked.
+ * This parameter enables extensions to provide a single implementation
+ * which handles multiple different menu items.
+ * @param messageInfo Details of the HTTP message(s) for which the context
+ * menu was displayed.
+ */
+ void menuItemClicked(
+ String menuItemCaption,
+ IHttpRequestResponse[] messageInfo);
+}
diff --git a/src/burp/IMessageEditor.java b/src/burp/IMessageEditor.java
new file mode 100644
index 0000000..3d9b75a
--- /dev/null
+++ b/src/burp/IMessageEditor.java
@@ -0,0 +1,77 @@
+package burp;
+
+/*
+ * @(#)IMessageEditor.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.Component;
+
+/**
+ * This interface is used to provide extensions with an instance of Burp's HTTP
+ * message editor, for the extension to use in its own UI. Extensions should
+ * call IBurpExtenderCallbacks.createMessageEditor()
to obtain an
+ * instance of this interface.
+ */
+public interface IMessageEditor
+{
+
+ /**
+ * This method returns the UI component of the editor, for extensions to add
+ * to their own UI.
+ *
+ * @return The UI component of the editor.
+ */
+ Component getComponent();
+
+ /**
+ * This method is used to display an HTTP message in the editor.
+ *
+ * @param message The HTTP message to be displayed.
+ * @param isRequest Flags whether the message is an HTTP request or
+ * response.
+ */
+ void setMessage(byte[] message, boolean isRequest);
+
+ /**
+ * This method is used to retrieve the currently displayed message, which
+ * may have been modified by the user.
+ *
+ * @return The currently displayed HTTP message.
+ */
+ byte[] getMessage();
+
+ /**
+ * This method is used to determine whether the current message has been
+ * modified by the user.
+ *
+ * @return An indication of whether the current message has been modified by
+ * the user since it was first displayed.
+ */
+ boolean isMessageModified();
+
+ /**
+ * This method returns the data that is currently selected by the user.
+ *
+ * @return The data that is currently selected by the user, or
+ * null
if no selection is made.
+ */
+ byte[] getSelectedData();
+
+ /**
+ * This method can be used to retrieve the bounds of the user's selection
+ * into the displayed message, if applicable.
+ *
+ * @return An int[2] array containing the start and end offsets of the
+ * user's selection within the displayed message. If the user has not made
+ * any selection in the current message, both offsets indicate the position
+ * of the caret within the editor. For some editor views, the concept of
+ * selection within the message does not apply, in which case this method
+ * returns null.
+ */
+ int[] getSelectionBounds();
+}
diff --git a/src/burp/IMessageEditorController.java b/src/burp/IMessageEditorController.java
new file mode 100644
index 0000000..df0eb16
--- /dev/null
+++ b/src/burp/IMessageEditorController.java
@@ -0,0 +1,49 @@
+package burp;
+
+/*
+ * @(#)IMessageEditorController.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used by an
+ * IMessageEditor
to obtain details about the currently displayed
+ * message. Extensions that create instances of Burp's HTTP message editor can
+ * optionally provide an implementation of
+ * IMessageEditorController
, which the editor will invoke when it
+ * requires further information about the current message (for example, to send
+ * it to another Burp tool). Extensions that provide custom editor tabs via an
+ * IMessageEditorTabFactory
will receive a reference to an
+ * IMessageEditorController
object for each tab instance they
+ * generate, which the tab can invoke if it requires further information about
+ * the current message.
+ */
+public interface IMessageEditorController
+{
+ /**
+ * This method is used to retrieve the HTTP service for the current message.
+ *
+ * @return The HTTP service for the current message.
+ */
+ IHttpService getHttpService();
+
+ /**
+ * This method is used to retrieve the HTTP request associated with the
+ * current message (which may itself be a response).
+ *
+ * @return The HTTP request associated with the current message.
+ */
+ byte[] getRequest();
+
+ /**
+ * This method is used to retrieve the HTTP response associated with the
+ * current message (which may itself be a request).
+ *
+ * @return The HTTP response associated with the current message.
+ */
+ byte[] getResponse();
+}
diff --git a/src/burp/IMessageEditorTab.java b/src/burp/IMessageEditorTab.java
new file mode 100644
index 0000000..38965ec
--- /dev/null
+++ b/src/burp/IMessageEditorTab.java
@@ -0,0 +1,103 @@
+package burp;
+
+/*
+ * @(#)IMessageEditorTab.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.Component;
+
+/**
+ * Extensions that register an
+ * IMessageEditorTabFactory
must return instances of this
+ * interface, which Burp will use to create custom tabs within its HTTP message
+ * editors.
+ */
+public interface IMessageEditorTab
+{
+ /**
+ * This method returns the caption that should appear on the custom tab when
+ * it is displayed. Note: Burp invokes this method once when the tab
+ * is first generated, and the same caption will be used every time the tab
+ * is displayed.
+ *
+ * @return The caption that should appear on the custom tab when it is
+ * displayed.
+ */
+ String getTabCaption();
+
+ /**
+ * This method returns the component that should be used as the contents of
+ * the custom tab when it is displayed. Note: Burp invokes this
+ * method once when the tab is first generated, and the same component will
+ * be used every time the tab is displayed.
+ *
+ * @return The component that should be used as the contents of the custom
+ * tab when it is displayed.
+ */
+ Component getUiComponent();
+
+ /**
+ * The hosting editor will invoke this method before it displays a new HTTP
+ * message, so that the custom tab can indicate whether it should be enabled
+ * for that message.
+ *
+ * @param content The message that is about to be displayed, or a zero-length
+ * array if the existing message is to be cleared.
+ * @param isRequest Indicates whether the message is a request or a
+ * response.
+ * @return The method should return
+ * true
if the custom tab is able to handle the specified
+ * message, and so will be displayed within the editor. Otherwise, the tab
+ * will be hidden while this message is displayed.
+ */
+ boolean isEnabled(byte[] content, boolean isRequest);
+
+ /**
+ * The hosting editor will invoke this method to display a new message or to
+ * clear the existing message. This method will only be called with a new
+ * message if the tab has already returned
+ * true
to a call to
+ * isEnabled()
with the same message details.
+ *
+ * @param content The message that is to be displayed, or
+ * null
if the tab should clear its contents and disable any
+ * editable controls.
+ * @param isRequest Indicates whether the message is a request or a
+ * response.
+ */
+ void setMessage(byte[] content, boolean isRequest);
+
+ /**
+ * This method returns the currently displayed message.
+ *
+ * @return The currently displayed message.
+ */
+ byte[] getMessage();
+
+ /**
+ * This method is used to determine whether the currently displayed message
+ * has been modified by the user. The hosting editor will always call
+ * getMessage()
before calling this method, so any pending
+ * edits should be completed within
+ * getMessage()
.
+ *
+ * @return The method should return
+ * true
if the user has modified the current message since it
+ * was first displayed.
+ */
+ boolean isModified();
+
+ /**
+ * This method is used to retrieve the data that is currently selected by
+ * the user.
+ *
+ * @return The data that is currently selected by the user. This may be
+ * null
if no selection is currently made.
+ */
+ byte[] getSelectedData();
+}
diff --git a/src/burp/IMessageEditorTabFactory.java b/src/burp/IMessageEditorTabFactory.java
new file mode 100644
index 0000000..6aae96e
--- /dev/null
+++ b/src/burp/IMessageEditorTabFactory.java
@@ -0,0 +1,38 @@
+package burp;
+
+/*
+ * @(#)IMessageEditorTabFactory.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerMessageEditorTabFactory()
to
+ * register a factory for custom message editor tabs. This allows extensions to
+ * provide custom rendering or editing of HTTP messages, within Burp's own HTTP
+ * editor.
+ */
+public interface IMessageEditorTabFactory
+{
+ /**
+ * Burp will call this method once for each HTTP message editor, and the
+ * factory should provide a new instance of an
+ * IMessageEditorTab
object.
+ *
+ * @param controller An
+ * IMessageEditorController
object, which the new tab can query
+ * to retrieve details about the currently displayed message. This may be
+ * null
for extension-invoked message editors where the
+ * extension has not provided an editor controller.
+ * @param editable Indicates whether the hosting editor is editable or
+ * read-only.
+ * @return A new
+ * IMessageEditorTab
object for use within the message editor.
+ */
+ IMessageEditorTab createNewInstance(IMessageEditorController controller,
+ boolean editable);
+}
diff --git a/src/burp/IParameter.java b/src/burp/IParameter.java
new file mode 100644
index 0000000..7651bde
--- /dev/null
+++ b/src/burp/IParameter.java
@@ -0,0 +1,104 @@
+package burp;
+
+/*
+ * @(#)IParameter.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to hold details about an HTTP request parameter.
+ */
+public interface IParameter
+{
+ /**
+ * Used to indicate a parameter within the URL query string.
+ */
+ static final byte PARAM_URL = 0;
+ /**
+ * Used to indicate a parameter within the message body.
+ */
+ static final byte PARAM_BODY = 1;
+ /**
+ * Used to indicate an HTTP cookie.
+ */
+ static final byte PARAM_COOKIE = 2;
+ /**
+ * Used to indicate an item of data within an XML structure.
+ */
+ static final byte PARAM_XML = 3;
+ /**
+ * Used to indicate the value of a tag attribute within an XML structure.
+ */
+ static final byte PARAM_XML_ATTR = 4;
+ /**
+ * Used to indicate the value of a parameter attribute within a multi-part
+ * message body (such as the name of an uploaded file).
+ */
+ static final byte PARAM_MULTIPART_ATTR = 5;
+ /**
+ * Used to indicate an item of data within a JSON structure.
+ */
+ static final byte PARAM_JSON = 6;
+
+ /**
+ * This method is used to retrieve the parameter type.
+ *
+ * @return The parameter type. The available types are defined within this
+ * interface.
+ */
+ byte getType();
+
+ /**
+ * This method is used to retrieve the parameter name.
+ *
+ * @return The parameter name.
+ */
+ String getName();
+
+ /**
+ * This method is used to retrieve the parameter value.
+ *
+ * @return The parameter value.
+ */
+ String getValue();
+
+ /**
+ * This method is used to retrieve the start offset of the parameter name
+ * within the HTTP request.
+ *
+ * @return The start offset of the parameter name within the HTTP request,
+ * or -1 if the parameter is not associated with a specific request.
+ */
+ int getNameStart();
+
+ /**
+ * This method is used to retrieve the end offset of the parameter name
+ * within the HTTP request.
+ *
+ * @return The end offset of the parameter name within the HTTP request, or
+ * -1 if the parameter is not associated with a specific request.
+ */
+ int getNameEnd();
+
+ /**
+ * This method is used to retrieve the start offset of the parameter value
+ * within the HTTP request.
+ *
+ * @return The start offset of the parameter value within the HTTP request,
+ * or -1 if the parameter is not associated with a specific request.
+ */
+ int getValueStart();
+
+ /**
+ * This method is used to retrieve the end offset of the parameter value
+ * within the HTTP request.
+ *
+ * @return The end offset of the parameter value within the HTTP request, or
+ * -1 if the parameter is not associated with a specific request.
+ */
+ int getValueEnd();
+}
diff --git a/src/burp/IProxyListener.java b/src/burp/IProxyListener.java
new file mode 100644
index 0000000..e8fb903
--- /dev/null
+++ b/src/burp/IProxyListener.java
@@ -0,0 +1,37 @@
+package burp;
+
+/*
+ * @(#)IProxyListener.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerProxyListener()
to register a
+ * Proxy listener. The listener will be notified of requests and responses being
+ * processed by the Proxy tool. Extensions can perform custom analysis or
+ * modification of these messages, and control in-UI message interception, by
+ * registering a proxy listener.
+ */
+public interface IProxyListener
+{
+ /**
+ * This method is invoked when an HTTP message is being processed by the
+ * Proxy.
+ *
+ * @param messageIsRequest Indicates whether the HTTP message is a request
+ * or a response.
+ * @param message An
+ * IInterceptedProxyMessage
object that extensions can use to
+ * query and update details of the message, and control whether the message
+ * should be intercepted and displayed to the user for manual review or
+ * modification.
+ */
+ void processProxyMessage(
+ boolean messageIsRequest,
+ IInterceptedProxyMessage message);
+}
diff --git a/src/burp/IRequestInfo.java b/src/burp/IRequestInfo.java
new file mode 100644
index 0000000..9737e1f
--- /dev/null
+++ b/src/burp/IRequestInfo.java
@@ -0,0 +1,95 @@
+package burp;
+
+/*
+ * @(#)IRequestInfo.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.net.URL;
+import java.util.List;
+
+/**
+ * This interface is used to retrieve key details about an HTTP request.
+ * Extensions can obtain an
+ * IRequestInfo
object for a given request by calling
+ * IExtensionHelpers.analyzeRequest()
.
+ */
+public interface IRequestInfo
+{
+ /**
+ * Used to indicate that there is no content.
+ */
+ static final byte CONTENT_TYPE_NONE = 0;
+ /**
+ * Used to indicate URL-encoded content.
+ */
+ static final byte CONTENT_TYPE_URL_ENCODED = 1;
+ /**
+ * Used to indicate multi-part content.
+ */
+ static final byte CONTENT_TYPE_MULTIPART = 2;
+ /**
+ * Used to indicate XML content.
+ */
+ static final byte CONTENT_TYPE_XML = 3;
+ /**
+ * Used to indicate JSON content.
+ */
+ static final byte CONTENT_TYPE_JSON = 4;
+ /**
+ * Used to indicate AMF content.
+ */
+ static final byte CONTENT_TYPE_AMF = 5;
+ /**
+ * Used to indicate unknown content.
+ */
+ static final byte CONTENT_TYPE_UNKNOWN = -1;
+
+ /**
+ * This method is used to obtain the HTTP method used in the request.
+ *
+ * @return The HTTP method used in the request.
+ */
+ String getMethod();
+
+ /**
+ * This method is used to obtain the URL in the request.
+ *
+ * @return The URL in the request.
+ */
+ URL getUrl();
+
+ /**
+ * This method is used to obtain the HTTP headers contained in the request.
+ *
+ * @return The HTTP headers contained in the request.
+ */
+ List getHeaders();
+
+ /**
+ * This method is used to obtain the parameters contained in the request.
+ *
+ * @return The parameters contained in the request.
+ */
+ List getParameters();
+
+ /**
+ * This method is used to obtain the offset within the request where the
+ * message body begins.
+ *
+ * @return The offset within the request where the message body begins.
+ */
+ int getBodyOffset();
+
+ /**
+ * This method is used to obtain the content type of the message body.
+ *
+ * @return An indication of the content type of the message body. Available
+ * types are defined within this interface.
+ */
+ byte getContentType();
+}
diff --git a/src/burp/IResponseInfo.java b/src/burp/IResponseInfo.java
new file mode 100644
index 0000000..a887d2f
--- /dev/null
+++ b/src/burp/IResponseInfo.java
@@ -0,0 +1,73 @@
+package burp;
+
+/*
+ * @(#)IResponseInfo.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * This interface is used to retrieve key details about an HTTP response.
+ * Extensions can obtain an
+ * IResponseInfo
object for a given response by calling
+ * IExtensionHelpers.analyzeResponse()
.
+ */
+public interface IResponseInfo
+{
+ /**
+ * This method is used to obtain the HTTP headers contained in the response.
+ *
+ * @return The HTTP headers contained in the response.
+ */
+ List getHeaders();
+
+ /**
+ * This method is used to obtain the offset within the response where the
+ * message body begins.
+ *
+ * @return The offset within the response where the message body begins.
+ */
+ int getBodyOffset();
+
+ /**
+ * This method is used to obtain the HTTP status code contained in the
+ * response.
+ *
+ * @return The HTTP status code contained in the response.
+ */
+ short getStatusCode();
+
+ /**
+ * This method is used to obtain details of the HTTP cookies set in the
+ * response.
+ *
+ * @return A list of ICookie
objects representing the cookies
+ * set in the response, if any.
+ */
+ List getCookies();
+
+ /**
+ * This method is used to obtain the MIME type of the response, as stated in
+ * the HTTP headers.
+ *
+ * @return A textual label for the stated MIME type, or an empty String if
+ * this is not known or recognized. The possible labels are the same as
+ * those used in the main Burp UI.
+ */
+ String getStatedMimeType();
+
+ /**
+ * This method is used to obtain the MIME type of the response, as inferred
+ * from the contents of the HTTP message body.
+ *
+ * @return A textual label for the inferred MIME type, or an empty String if
+ * this is not known or recognized. The possible labels are the same as
+ * those used in the main Burp UI.
+ */
+ String getInferredMimeType();
+}
diff --git a/src/burp/IResponseKeywords.java b/src/burp/IResponseKeywords.java
new file mode 100644
index 0000000..924e9dc
--- /dev/null
+++ b/src/burp/IResponseKeywords.java
@@ -0,0 +1,58 @@
+package burp;
+
+/*
+ * @(#)IResponseKeywords.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * This interface is used to represent the counts of keywords appearing in a
+ * number of HTTP responses.
+ */
+public interface IResponseKeywords
+{
+
+ /**
+ * This method is used to obtain the list of keywords whose counts vary
+ * between the analyzed responses.
+ *
+ * @return The keywords whose counts vary between the analyzed responses.
+ */
+ List getVariantKeywords();
+
+ /**
+ * This method is used to obtain the list of keywords whose counts do not
+ * vary between the analyzed responses.
+ *
+ * @return The keywords whose counts do not vary between the analyzed
+ * responses.
+ */
+ List getInvariantKeywords();
+
+ /**
+ * This method is used to obtain the number of occurrences of an individual
+ * keyword in a response.
+ *
+ * @param keyword The keyword whose count will be retrieved.
+ * @param responseIndex The index of the response. Note responses are
+ * indexed from zero in the order they were originally supplied to the
+ * IExtensionHelpers.analyzeResponseKeywords()
and
+ * IResponseKeywords.updateWith()
methods.
+ * @return The number of occurrences of the specified keyword for the
+ * specified response.
+ */
+ int getKeywordCount(String keyword, int responseIndex);
+
+ /**
+ * This method is used to update the analysis based on additional responses.
+ *
+ * @param responses The new responses to include in the analysis.
+ */
+ void updateWith(byte[]... responses);
+}
diff --git a/src/burp/IResponseVariations.java b/src/burp/IResponseVariations.java
new file mode 100644
index 0000000..39cee40
--- /dev/null
+++ b/src/burp/IResponseVariations.java
@@ -0,0 +1,62 @@
+package burp;
+
+/*
+ * @(#)IResponseVariations.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * This interface is used to represent variations between a number HTTP
+ * responses, according to various attributes.
+ */
+public interface IResponseVariations
+{
+
+ /**
+ * This method is used to obtain the list of attributes that vary between
+ * the analyzed responses.
+ *
+ * @return The attributes that vary between the analyzed responses.
+ */
+ List getVariantAttributes();
+
+ /**
+ * This method is used to obtain the list of attributes that do not vary
+ * between the analyzed responses.
+ *
+ * @return The attributes that do not vary between the analyzed responses.
+ */
+ List getInvariantAttributes();
+
+ /**
+ * This method is used to obtain the value of an individual attribute in a
+ * response. Note that the values of some attributes are intrinsically
+ * meaningful (e.g. a word count) while the values of others are less so
+ * (e.g. a checksum of the HTML tag names).
+ *
+ * @param attributeName The name of the attribute whose value will be
+ * retrieved. Extension authors can obtain the list of supported attributes
+ * by generating an IResponseVariations
object for a single
+ * response and calling
+ * IResponseVariations.getInvariantAttributes()
.
+ * @param responseIndex The index of the response. Note that responses are
+ * indexed from zero in the order they were originally supplied to the
+ * IExtensionHelpers.analyzeResponseVariations()
and
+ * IResponseVariations.updateWith()
methods.
+ * @return The value of the specified attribute for the specified response.
+ */
+ int getAttributeValue(String attributeName, int responseIndex);
+
+ /**
+ * This method is used to update the analysis based on additional responses.
+ *
+ * @param responses The new responses to include in the analysis.
+ */
+ void updateWith(byte[]... responses);
+}
diff --git a/src/burp/IScanIssue.java b/src/burp/IScanIssue.java
new file mode 100644
index 0000000..9529cbb
--- /dev/null
+++ b/src/burp/IScanIssue.java
@@ -0,0 +1,123 @@
+package burp;
+
+/*
+ * @(#)IScanIssue.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to retrieve details of Scanner issues. Extensions can
+ * obtain details of issues by registering an IScannerListener
or
+ * by calling IBurpExtenderCallbacks.getScanIssues()
. Extensions
+ * can also add custom Scanner issues by registering an
+ * IScannerCheck
or calling
+ * IBurpExtenderCallbacks.addScanIssue()
, and providing their own
+ * implementations of this interface. Note that issue descriptions and other
+ * text generated by extensions are subject to an HTML whitelist that allows
+ * only formatting tags and simple hyperlinks.
+ */
+public interface IScanIssue
+{
+
+ /**
+ * This method returns the URL for which the issue was generated.
+ *
+ * @return The URL for which the issue was generated.
+ */
+ java.net.URL getUrl();
+
+ /**
+ * This method returns the name of the issue type.
+ *
+ * @return The name of the issue type (e.g. "SQL injection").
+ */
+ String getIssueName();
+
+ /**
+ * This method returns a numeric identifier of the issue type. See the Burp
+ * Scanner help documentation for a listing of all the issue types.
+ *
+ * @return A numeric identifier of the issue type.
+ */
+ int getIssueType();
+
+ /**
+ * This method returns the issue severity level.
+ *
+ * @return The issue severity level. Expected values are "High", "Medium",
+ * "Low", "Information" or "False positive".
+ *
+ */
+ String getSeverity();
+
+ /**
+ * This method returns the issue confidence level.
+ *
+ * @return The issue confidence level. Expected values are "Certain", "Firm"
+ * or "Tentative".
+ */
+ String getConfidence();
+
+ /**
+ * This method returns a background description for this type of issue.
+ *
+ * @return A background description for this type of issue, or
+ * null
if none applies. A limited set of HTML tags may be
+ * used.
+ */
+ String getIssueBackground();
+
+ /**
+ * This method returns a background description of the remediation for this
+ * type of issue.
+ *
+ * @return A background description of the remediation for this type of
+ * issue, or null
if none applies. A limited set of HTML tags
+ * may be used.
+ */
+ String getRemediationBackground();
+
+ /**
+ * This method returns detailed information about this specific instance of
+ * the issue.
+ *
+ * @return Detailed information about this specific instance of the issue,
+ * or null
if none applies. A limited set of HTML tags may be
+ * used.
+ */
+ String getIssueDetail();
+
+ /**
+ * This method returns detailed information about the remediation for this
+ * specific instance of the issue.
+ *
+ * @return Detailed information about the remediation for this specific
+ * instance of the issue, or null
if none applies. A limited
+ * set of HTML tags may be used.
+ */
+ String getRemediationDetail();
+
+ /**
+ * This method returns the HTTP messages on the basis of which the issue was
+ * generated.
+ *
+ * @return The HTTP messages on the basis of which the issue was generated.
+ * Note: The items in this array should be instances of
+ * IHttpRequestResponseWithMarkers
if applicable, so that
+ * details of the relevant portions of the request and response messages are
+ * available.
+ */
+ IHttpRequestResponse[] getHttpMessages();
+
+ /**
+ * This method returns the HTTP service for which the issue was generated.
+ *
+ * @return The HTTP service for which the issue was generated.
+ */
+ IHttpService getHttpService();
+
+}
diff --git a/src/burp/IScanQueueItem.java b/src/burp/IScanQueueItem.java
new file mode 100644
index 0000000..47d9f34
--- /dev/null
+++ b/src/burp/IScanQueueItem.java
@@ -0,0 +1,80 @@
+package burp;
+
+/*
+ * @(#)IScanQueueItem.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to retrieve details of items in the Burp Scanner
+ * active scan queue. Extensions can obtain references to scan queue items by
+ * calling
+ * IBurpExtenderCallbacks.doActiveScan()
.
+ */
+public interface IScanQueueItem
+{
+ /**
+ * This method returns a description of the status of the scan queue item.
+ *
+ * @return A description of the status of the scan queue item.
+ */
+ String getStatus();
+
+ /**
+ * This method returns an indication of the percentage completed for the
+ * scan queue item.
+ *
+ * @return An indication of the percentage completed for the scan queue
+ * item.
+ */
+ byte getPercentageComplete();
+
+ /**
+ * This method returns the number of requests that have been made for the
+ * scan queue item.
+ *
+ * @return The number of requests that have been made for the scan queue
+ * item.
+ */
+ int getNumRequests();
+
+ /**
+ * This method returns the number of network errors that have occurred for
+ * the scan queue item.
+ *
+ * @return The number of network errors that have occurred for the scan
+ * queue item.
+ */
+ int getNumErrors();
+
+ /**
+ * This method returns the number of attack insertion points being used for
+ * the scan queue item.
+ *
+ * @return The number of attack insertion points being used for the scan
+ * queue item.
+ */
+ int getNumInsertionPoints();
+
+ /**
+ * This method allows the scan queue item to be canceled.
+ */
+ void cancel();
+
+ /**
+ * This method returns details of the issues generated for the scan queue
+ * item. Note: different items within the scan queue may contain
+ * duplicated versions of the same issues - for example, if the same request
+ * has been scanned multiple times. Duplicated issues are consolidated in
+ * the main view of scan results. Extensions can register an
+ * IScannerListener
to get details only of unique, newly
+ * discovered Scanner issues post-consolidation.
+ *
+ * @return Details of the issues generated for the scan queue item.
+ */
+ IScanIssue[] getIssues();
+}
diff --git a/src/burp/IScannerCheck.java b/src/burp/IScannerCheck.java
new file mode 100644
index 0000000..976f3d7
--- /dev/null
+++ b/src/burp/IScannerCheck.java
@@ -0,0 +1,83 @@
+package burp;
+
+/*
+ * @(#)IScannerCheck.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerScannerCheck()
to register a
+ * custom Scanner check. When performing scanning, Burp will ask the check to
+ * perform active or passive scanning on the base request, and report any
+ * Scanner issues that are identified.
+ */
+public interface IScannerCheck
+{
+
+ /**
+ * The Scanner invokes this method for each base request / response that is
+ * passively scanned. Note: Extensions should only analyze the
+ * HTTP messages provided during passive scanning, and should not make any
+ * new HTTP requests of their own.
+ *
+ * @param baseRequestResponse The base HTTP request / response that should
+ * be passively scanned.
+ * @return A list of IScanIssue
objects, or null
+ * if no issues are identified.
+ */
+ List doPassiveScan(IHttpRequestResponse baseRequestResponse);
+
+ /**
+ * The Scanner invokes this method for each insertion point that is actively
+ * scanned. Extensions may issue HTTP requests as required to carry out
+ * active scanning, and should use the
+ * IScannerInsertionPoint
object provided to build scan
+ * requests for particular payloads.
+ * Note:
+ * Scan checks should submit raw non-encoded payloads to insertion points,
+ * and the insertion point has responsibility for performing any data
+ * encoding that is necessary given the nature and location of the insertion
+ * point.
+ *
+ * @param baseRequestResponse The base HTTP request / response that should
+ * be actively scanned.
+ * @param insertionPoint An IScannerInsertionPoint
object that
+ * can be queried to obtain details of the insertion point being tested, and
+ * can be used to build scan requests for particular payloads.
+ * @return A list of IScanIssue
objects, or null
+ * if no issues are identified.
+ */
+ List doActiveScan(
+ IHttpRequestResponse baseRequestResponse,
+ IScannerInsertionPoint insertionPoint);
+
+ /**
+ * The Scanner invokes this method when the custom Scanner check has
+ * reported multiple issues for the same URL path. This can arise either
+ * because there are multiple distinct vulnerabilities, or because the same
+ * (or a similar) request has been scanned more than once. The custom check
+ * should determine whether the issues are duplicates. In most cases, where
+ * a check uses distinct issue names or descriptions for distinct issues,
+ * the consolidation process will simply be a matter of comparing these
+ * features for the two issues.
+ *
+ * @param existingIssue An issue that was previously reported by this
+ * Scanner check.
+ * @param newIssue An issue at the same URL path that has been newly
+ * reported by this Scanner check.
+ * @return An indication of which issue(s) should be reported in the main
+ * Scanner results. The method should return -1
to report the
+ * existing issue only, 0
to report both issues, and
+ * 1
to report the new issue only.
+ */
+ int consolidateDuplicateIssues(
+ IScanIssue existingIssue,
+ IScanIssue newIssue);
+}
diff --git a/src/burp/IScannerInsertionPoint.java b/src/burp/IScannerInsertionPoint.java
new file mode 100644
index 0000000..3b98369
--- /dev/null
+++ b/src/burp/IScannerInsertionPoint.java
@@ -0,0 +1,174 @@
+package burp;
+
+/*
+ * @(#)IScannerInsertionPoint.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to define an insertion point for use by active Scanner
+ * checks. Extensions can obtain instances of this interface by registering an
+ * IScannerCheck
, or can create instances for use by Burp's own
+ * scan checks by registering an
+ * IScannerInsertionPointProvider
.
+ */
+public interface IScannerInsertionPoint
+{
+
+ /**
+ * Used to indicate where the payload is inserted into the value of a URL
+ * parameter.
+ */
+ static final byte INS_PARAM_URL = 0x00;
+ /**
+ * Used to indicate where the payload is inserted into the value of a body
+ * parameter.
+ */
+ static final byte INS_PARAM_BODY = 0x01;
+ /**
+ * Used to indicate where the payload is inserted into the value of an HTTP
+ * cookie.
+ */
+ static final byte INS_PARAM_COOKIE = 0x02;
+ /**
+ * Used to indicate where the payload is inserted into the value of an item
+ * of data within an XML data structure.
+ */
+ static final byte INS_PARAM_XML = 0x03;
+ /**
+ * Used to indicate where the payload is inserted into the value of a tag
+ * attribute within an XML structure.
+ */
+ static final byte INS_PARAM_XML_ATTR = 0x04;
+ /**
+ * Used to indicate where the payload is inserted into the value of a
+ * parameter attribute within a multi-part message body (such as the name of
+ * an uploaded file).
+ */
+ static final byte INS_PARAM_MULTIPART_ATTR = 0x05;
+ /**
+ * Used to indicate where the payload is inserted into the value of an item
+ * of data within a JSON structure.
+ */
+ static final byte INS_PARAM_JSON = 0x06;
+ /**
+ * Used to indicate where the payload is inserted into the value of an AMF
+ * parameter.
+ */
+ static final byte INS_PARAM_AMF = 0x07;
+ /**
+ * Used to indicate where the payload is inserted into the value of an HTTP
+ * request header.
+ */
+ static final byte INS_HEADER = 0x20;
+ /**
+ * Used to indicate where the payload is inserted into a URL path folder.
+ */
+ static final byte INS_URL_PATH_FOLDER = 0x21;
+ /**
+ * Used to indicate where the payload is inserted into a URL path folder.
+ * This is now deprecated; use INS_URL_PATH_FOLDER
instead.
+ */
+ @Deprecated
+ static final byte INS_URL_PATH_REST = INS_URL_PATH_FOLDER;
+ /**
+ * Used to indicate where the payload is inserted into the name of an added
+ * URL parameter.
+ */
+ static final byte INS_PARAM_NAME_URL = 0x22;
+ /**
+ * Used to indicate where the payload is inserted into the name of an added
+ * body parameter.
+ */
+ static final byte INS_PARAM_NAME_BODY = 0x23;
+ /**
+ * Used to indicate where the payload is inserted into the body of the HTTP
+ * request.
+ */
+ static final byte INS_ENTIRE_BODY = 0x24;
+ /**
+ * Used to indicate where the payload is inserted into the URL path
+ * filename.
+ */
+ static final byte INS_URL_PATH_FILENAME = 0x25;
+ /**
+ * Used to indicate where the payload is inserted at a location manually
+ * configured by the user.
+ */
+ static final byte INS_USER_PROVIDED = 0x40;
+ /**
+ * Used to indicate where the insertion point is provided by an
+ * extension-registered
+ * IScannerInsertionPointProvider
.
+ */
+ static final byte INS_EXTENSION_PROVIDED = 0x41;
+ /**
+ * Used to indicate where the payload is inserted at an unknown location
+ * within the request.
+ */
+ static final byte INS_UNKNOWN = 0x7f;
+
+ /**
+ * This method returns the name of the insertion point.
+ *
+ * @return The name of the insertion point (for example, a description of a
+ * particular request parameter).
+ */
+ String getInsertionPointName();
+
+ /**
+ * This method returns the base value for this insertion point.
+ *
+ * @return the base value that appears in this insertion point in the base
+ * request being scanned, or null
if there is no value in the
+ * base request that corresponds to this insertion point.
+ */
+ String getBaseValue();
+
+ /**
+ * This method is used to build a request with the specified payload placed
+ * into the insertion point. There is no requirement for extension-provided
+ * insertion points to adjust the Content-Length header in requests if the
+ * body length has changed, although Burp-provided insertion points will
+ * always do this and will return a request with a valid Content-Length
+ * header.
+ * Note:
+ * Scan checks should submit raw non-encoded payloads to insertion points,
+ * and the insertion point has responsibility for performing any data
+ * encoding that is necessary given the nature and location of the insertion
+ * point.
+ *
+ * @param payload The payload that should be placed into the insertion
+ * point.
+ * @return The resulting request.
+ */
+ byte[] buildRequest(byte[] payload);
+
+ /**
+ * This method is used to determine the offsets of the payload value within
+ * the request, when it is placed into the insertion point. Scan checks may
+ * invoke this method when reporting issues, so as to highlight the relevant
+ * part of the request within the UI.
+ *
+ * @param payload The payload that should be placed into the insertion
+ * point.
+ * @return An int[2] array containing the start and end offsets of the
+ * payload within the request, or null if this is not applicable (for
+ * example, where the insertion point places a payload into a serialized
+ * data structure, the raw payload may not literally appear anywhere within
+ * the resulting request).
+ */
+ int[] getPayloadOffsets(byte[] payload);
+
+ /**
+ * This method returns the type of the insertion point.
+ *
+ * @return The type of the insertion point. Available types are defined in
+ * this interface.
+ */
+ byte getInsertionPointType();
+}
diff --git a/src/burp/IScannerInsertionPointProvider.java b/src/burp/IScannerInsertionPointProvider.java
new file mode 100644
index 0000000..41472a1
--- /dev/null
+++ b/src/burp/IScannerInsertionPointProvider.java
@@ -0,0 +1,38 @@
+package burp;
+
+/*
+ * @(#)IScannerInsertionPointProvider.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.util.List;
+
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerScannerInsertionPointProvider()
+ * to register a factory for custom Scanner insertion points.
+ */
+public interface IScannerInsertionPointProvider
+{
+ /**
+ * When a request is actively scanned, the Scanner will invoke this method,
+ * and the provider should provide a list of custom insertion points that
+ * will be used in the scan. Note: these insertion points are used in
+ * addition to those that are derived from Burp Scanner's configuration, and
+ * those provided by any other Burp extensions.
+ *
+ * @param baseRequestResponse The base request that will be actively
+ * scanned.
+ * @return A list of
+ * IScannerInsertionPoint
objects that should be used in the
+ * scanning, or
+ * null
if no custom insertion points are applicable for this
+ * request.
+ */
+ List getInsertionPoints(
+ IHttpRequestResponse baseRequestResponse);
+}
diff --git a/src/burp/IScannerListener.java b/src/burp/IScannerListener.java
new file mode 100644
index 0000000..0bd51d9
--- /dev/null
+++ b/src/burp/IScannerListener.java
@@ -0,0 +1,30 @@
+package burp;
+
+/*
+ * @(#)IScannerListener.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerScannerListener()
to register a
+ * Scanner listener. The listener will be notified of new issues that are
+ * reported by the Scanner tool. Extensions can perform custom analysis or
+ * logging of Scanner issues by registering a Scanner listener.
+ */
+public interface IScannerListener
+{
+ /**
+ * This method is invoked when a new issue is added to Burp Scanner's
+ * results.
+ *
+ * @param issue An
+ * IScanIssue
object that the extension can query to obtain
+ * details about the new issue.
+ */
+ void newScanIssue(IScanIssue issue);
+}
diff --git a/src/burp/IScopeChangeListener.java b/src/burp/IScopeChangeListener.java
new file mode 100644
index 0000000..a289388
--- /dev/null
+++ b/src/burp/IScopeChangeListener.java
@@ -0,0 +1,25 @@
+package burp;
+
+/*
+ * @(#)IScopeChangeListener.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerScopeChangeListener()
to register
+ * a scope change listener. The listener will be notified whenever a change
+ * occurs to Burp's suite-wide target scope.
+ */
+public interface IScopeChangeListener
+{
+ /**
+ * This method is invoked whenever a change occurs to Burp's suite-wide
+ * target scope.
+ */
+ void scopeChanged();
+}
diff --git a/src/burp/ISessionHandlingAction.java b/src/burp/ISessionHandlingAction.java
new file mode 100644
index 0000000..c953e22
--- /dev/null
+++ b/src/burp/ISessionHandlingAction.java
@@ -0,0 +1,51 @@
+package burp;
+
+/*
+ * @(#)ISessionHandlingAction.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * Extensions can implement this interface and then call
+ * IBurpExtenderCallbacks.registerSessionHandlingAction()
to
+ * register a custom session handling action. Each registered action will be
+ * available within the session handling rule UI for the user to select as a
+ * rule action. Users can choose to invoke an action directly in its own right,
+ * or following execution of a macro.
+ */
+public interface ISessionHandlingAction
+{
+ /**
+ * This method is used by Burp to obtain the name of the session handling
+ * action. This will be displayed as an option within the session handling
+ * rule editor when the user selects to execute an extension-provided
+ * action.
+ *
+ * @return The name of the action.
+ */
+ String getActionName();
+
+ /**
+ * This method is invoked when the session handling action should be
+ * executed. This may happen as an action in its own right, or as a
+ * sub-action following execution of a macro.
+ *
+ * @param currentRequest The base request that is currently being processed.
+ * The action can query this object to obtain details about the base
+ * request. It can issue additional requests of its own if necessary, and
+ * can use the setter methods on this object to update the base request.
+ * @param macroItems If the action is invoked following execution of a
+ * macro, this parameter contains the result of executing the macro.
+ * Otherwise, it is
+ * null
. Actions can use the details of the macro items to
+ * perform custom analysis of the macro to derive values of non-standard
+ * session handling tokens, etc.
+ */
+ void performAction(
+ IHttpRequestResponse currentRequest,
+ IHttpRequestResponse[] macroItems);
+}
diff --git a/src/burp/ITab.java b/src/burp/ITab.java
new file mode 100644
index 0000000..12be08f
--- /dev/null
+++ b/src/burp/ITab.java
@@ -0,0 +1,38 @@
+package burp;
+
+/*
+ * @(#)ITab.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.Component;
+
+/**
+ * This interface is used to provide Burp with details of a custom tab that will
+ * be added to Burp's UI, using a method such as
+ * IBurpExtenderCallbacks.addSuiteTab()
.
+ */
+public interface ITab
+{
+ /**
+ * Burp uses this method to obtain the caption that should appear on the
+ * custom tab when it is displayed.
+ *
+ * @return The caption that should appear on the custom tab when it is
+ * displayed.
+ */
+ String getTabCaption();
+
+ /**
+ * Burp uses this method to obtain the component that should be used as the
+ * contents of the custom tab when it is displayed.
+ *
+ * @return The component that should be used as the contents of the custom
+ * tab when it is displayed.
+ */
+ Component getUiComponent();
+}
diff --git a/src/burp/ITempFile.java b/src/burp/ITempFile.java
new file mode 100644
index 0000000..d20785c
--- /dev/null
+++ b/src/burp/ITempFile.java
@@ -0,0 +1,33 @@
+package burp;
+
+/*
+ * @(#)ITempFile.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+/**
+ * This interface is used to hold details of a temporary file that has been
+ * created via a call to
+ * IBurpExtenderCallbacks.saveToTempFile()
.
+ *
+ */
+public interface ITempFile
+{
+ /**
+ * This method is used to retrieve the contents of the buffer that was saved
+ * in the temporary file.
+ *
+ * @return The contents of the buffer that was saved in the temporary file.
+ */
+ byte[] getBuffer();
+
+ /**
+ * This method is deprecated and no longer performs any action.
+ */
+ @Deprecated
+ void delete();
+}
diff --git a/src/burp/ITextEditor.java b/src/burp/ITextEditor.java
new file mode 100644
index 0000000..25a979a
--- /dev/null
+++ b/src/burp/ITextEditor.java
@@ -0,0 +1,90 @@
+package burp;
+
+/*
+ * @(#)ITextEditor.java
+ *
+ * Copyright PortSwigger Ltd. All rights reserved.
+ *
+ * This code may be used to extend the functionality of Burp Suite Community Edition
+ * and Burp Suite Professional, provided that this usage does not violate the
+ * license terms for those products.
+ */
+import java.awt.Component;
+
+/**
+ * This interface is used to provide extensions with an instance of Burp's raw
+ * text editor, for the extension to use in its own UI. Extensions should call
+ * IBurpExtenderCallbacks.createTextEditor()
to obtain an instance
+ * of this interface.
+ */
+public interface ITextEditor
+{
+ /**
+ * This method returns the UI component of the editor, for extensions to add
+ * to their own UI.
+ *
+ * @return The UI component of the editor.
+ */
+ Component getComponent();
+
+ /**
+ * This method is used to control whether the editor is currently editable.
+ * This status can be toggled on and off as required.
+ *
+ * @param editable Indicates whether the editor should be currently
+ * editable.
+ */
+ void setEditable(boolean editable);
+
+ /**
+ * This method is used to update the currently displayed text in the editor.
+ *
+ * @param text The text to be displayed.
+ */
+ void setText(byte[] text);
+
+ /**
+ * This method is used to retrieve the currently displayed text.
+ *
+ * @return The currently displayed text.
+ */
+ byte[] getText();
+
+ /**
+ * This method is used to determine whether the user has modified the
+ * contents of the editor.
+ *
+ * @return An indication of whether the user has modified the contents of
+ * the editor since the last call to
+ * setText()
.
+ */
+ boolean isTextModified();
+
+ /**
+ * This method is used to obtain the currently selected text.
+ *
+ * @return The currently selected text, or
+ * null
if the user has not made any selection.
+ */
+ byte[] getSelectedText();
+
+ /**
+ * This method can be used to retrieve the bounds of the user's selection
+ * into the displayed text, if applicable.
+ *
+ * @return An int[2] array containing the start and end offsets of the
+ * user's selection within the displayed text. If the user has not made any
+ * selection in the current message, both offsets indicate the position of
+ * the caret within the editor.
+ */
+ int[] getSelectionBounds();
+
+ /**
+ * This method is used to update the search expression that is shown in the
+ * search bar below the editor. The editor will automatically highlight any
+ * regions of the displayed text that match the search expression.
+ *
+ * @param expression The search expression.
+ */
+ void setSearchExpression(String expression);
+}
diff --git a/src/helper/BurpFunctions.java b/src/helper/BurpFunctions.java
new file mode 100644
index 0000000..f1e0ed6
--- /dev/null
+++ b/src/helper/BurpFunctions.java
@@ -0,0 +1,50 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package helper;
+
+import java.io.PrintWriter;
+
+import burp.IBurpExtenderCallbacks;
+
+public class BurpFunctions {
+ public static Object loadExtensionSettingHelper(String name, String type, Object defaultValue,IBurpExtenderCallbacks callbacks, PrintWriter stderr) {
+ Object value = null;
+ try {
+ String temp_value = callbacks.loadExtensionSetting(name);
+ if(temp_value!=null && !temp_value.equals("")) {
+ switch(type.toLowerCase()){
+ case "int":
+ case "integer":
+ value = Integer.valueOf(temp_value);
+ break;
+ case "bool":
+ case "boolean":
+ value = Boolean.valueOf(temp_value);
+ break;
+ default:
+ value = temp_value;
+ break;
+ }
+ }
+ }catch(Exception e) {
+ stderr.println(e.getMessage());
+ }
+
+ if(value==null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+}
diff --git a/src/helper/HTTPMessage.java b/src/helper/HTTPMessage.java
new file mode 100644
index 0000000..3f45d87
--- /dev/null
+++ b/src/helper/HTTPMessage.java
@@ -0,0 +1,350 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package helper;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.swing.JCheckBox;
+import javax.swing.JOptionPane;
+
+public class HTTPMessage {
+
+ //private static String LWSP_Regex= "(([\\r\\n]|\\r\\n)[ \\t]+|[ \\t])*"; // https://tools.ietf.org/html/rfc5234 - ToDo -> add support of LWSP when finding header values
+
+ // Reads the Content-Type value from the header - no LWSP support yet! - reads the value before ";", "," or space
+ public static String findHeaderContentType(String strHeader){
+ String contentType="";
+ if(!strHeader.equals("")){
+ Pattern my_pattern = Pattern.compile("(?im)^content-type:[ \\t]*([^;,\\s]+)");
+ Matcher m = my_pattern.matcher(strHeader);
+ if (m.find()) {
+ contentType = m.group(1);
+ }
+ }
+ return contentType;
+ }
+
+ // Reads the Content-Type charset value from the header - no LWSP support yet! no support for double quotes around charset value either!
+ public static String findCharsetFromHeader(String strHeader, boolean trimSpaces){
+ String charset="";
+ if(!strHeader.equals("")){
+ Pattern my_pattern = Pattern.compile("(?im)^content-type:.*?[ \\t;,]+charset=[ \\t]*([\"]([^\"]+)[\"]|([^;\\s,]+))");
+ Matcher m = my_pattern.matcher(strHeader);
+ if (m.find()) {
+ charset = m.group(1);
+ charset = charset.replaceAll("\"", "");
+ if (trimSpaces)
+ charset = charset.trim();
+ }
+ }
+ return charset;
+ }
+
+ // Reads the Content-Type boundary value from the header - no LWSP support yet!
+ public static String findBoundaryFromHeader(String strHeader, boolean trimSpaces){
+ String boundary="";
+ if(!strHeader.equals("")){
+ Pattern my_pattern = Pattern.compile("(?im)^content-type:.*?[ \\t;,]+boundary=[ \\t]*([\"]([^\"]+)[\"]|([^\\s,]+))");
+ Matcher m = my_pattern.matcher(strHeader);
+ if (m.find()) {
+ boundary = m.group(1);
+ boundary = boundary.replaceAll("\"", "");
+ if (trimSpaces)
+ boundary = boundary.trim();
+ }
+ }
+ return boundary;
+ }
+
+ // Makes a content-type header using provided parameters
+ // Obviously the ; delimiter can be changed by comma in certain cases but that's not for discussion here!
+ public static String createContentTypeHeader(String cType, String charset, String boundary, boolean trimSpaces){
+ String contentType="";
+ if(trimSpaces) {
+ charset = charset.trim();
+ boundary = boundary.trim();
+ }
+
+ if(charset.contains(" "))
+ charset = "\""+charset+"\"";
+ if(boundary.contains(" "))
+ boundary = "\""+boundary+"\"";
+
+ contentType = cType + "; charset=" + charset;
+
+ if(!boundary.isEmpty()) {
+ contentType = cType + "; boundary="+boundary + " ; charset=" + charset;
+ // contentType = cType + "; charset=" + charset + ", boundary="+boundary; // another format
+ }
+
+ return contentType;
+ }
+
+ // Reads the Content-Type value from the header - reads the value before ";", "," or space
+ public static String findHeaderContentType(List headers){
+ String contentType="";
+ for(String strHeader : headers){
+ if(!strHeader.equals("")){
+ Pattern my_pattern = Pattern.compile("(?im)^content-type:[ \\t]*([^;, \\s]+)");
+ Matcher m = my_pattern.matcher(strHeader);
+ if (m.find()) {
+ contentType = m.group(1);
+ break;
+ }
+ }
+ }
+ return contentType;
+ }
+
+
+ // Splits header and body of a request or response
+ public static String[] getHeaderAndBody(byte[] fullMessage,String encoding) throws UnsupportedEncodingException{
+ String[] result = {"",""};
+ String strFullMessage = "";
+ if(fullMessage != null){
+ // splitting the message to retrieve the header and the body
+ strFullMessage = new String(fullMessage,encoding);
+ if(strFullMessage.contains("\r\n\r\n"))
+ result = strFullMessage.split("\r\n\r\n",2);
+ }
+ return result;
+ }
+
+ // Splits header and body of a request or response
+ public static String[] getHeaderAndBody(String fullMessage) {
+ String[] result = {"",""};
+ if(fullMessage != null){
+ // splitting the message to retrieve the header and the body
+ if(fullMessage.contains("\r\n\r\n"))
+ result = fullMessage.split("\r\n\r\n",2);
+ }
+ return result;
+ }
+
+
+ public static List> getQueryString(String fullMessage){
+ return getQueryString(fullMessage, "" , "");
+ }
+ public static List> getQueryString(String fullMessage, String delimiter_QS_param){
+ return getQueryString(fullMessage, "" , delimiter_QS_param);
+ }
+ // gets querystring parameters because burp can't handle special cases such as when we have jsessionid after ;
+ public static List> getQueryString(String reqMessage, String delimiter_QS, String delimiter_QS_param){
+ if (delimiter_QS.isEmpty()) delimiter_QS = "?";
+ if (delimiter_QS_param.isEmpty()) delimiter_QS = "&";
+ // final object with qs name and its value
+ List> qs_list = new ArrayList>();
+
+ // we assume that we are dealing with one HTTP message (not multiple in a pipeline)
+ String firstline = reqMessage.split("\r\n|\r|\n", 2)[0];
+
+ // we assume that we are dealing with an standard HTTP message in which there is a space after the last parameter value
+ String QS = "";
+ Pattern pattern = Pattern.compile("\\"+delimiter_QS+"([^ \\s]+)");
+ Matcher matcher = pattern.matcher(firstline);
+ if (matcher.find())
+ {
+ QS = matcher.group(1);
+ }
+
+ if (!QS.isEmpty()) {
+ String[] keyValues = QS.split("\\"+delimiter_QS_param);
+ for(String keyValue:keyValues){
+ List keyValueList = new ArrayList();
+ String key = keyValue;
+ String value = "";
+ if(keyValue.contains("=")) {
+ key = keyValue.split("=",2)[0];
+ value = keyValue.split("=",2)[1];
+ }
+ keyValueList.add(key);
+ keyValueList.add(value);
+ qs_list.add(keyValueList);
+ }
+ }
+ return qs_list;
+ }
+
+
+ public static List> getURLEncodedBodyParams(String strMessage, boolean isBodyOnly){
+ return getURLEncodedBodyParams(strMessage, isBodyOnly, "");
+ }
+ // gets URLEncoded POST parameters - it can use different delimiters than &
+ public static List> getURLEncodedBodyParams(String strMessage, boolean isBodyOnly, String delimiter_urlencoded_body_param){
+ if (delimiter_urlencoded_body_param.isEmpty()) delimiter_urlencoded_body_param = "&";
+ if(!isBodyOnly) {
+ strMessage = getHeaderAndBody(strMessage)[1];
+ }
+ // final object with param name and its value
+ List> param_list = new ArrayList>();
+ String[] keyValues = strMessage.split("\\"+delimiter_urlencoded_body_param);
+ for(String keyValue:keyValues){
+ List keyValueList = new ArrayList();
+ String key = keyValue;
+ String value = "";
+ if(keyValue.contains("=")) {
+ key = keyValue.split("=",2)[0];
+ value = keyValue.split("=",2)[1];
+ }
+ keyValueList.add(key);
+ keyValueList.add(value);
+ param_list.add(keyValueList);
+ }
+ return param_list;
+ }
+
+
+ public static String replaceQueryString(String reqMessage, String newQS){
+ return replaceQueryString(reqMessage, newQS, "");
+ }
+ // replaces querystring or adds it if empty in a request
+ public static String replaceQueryString(String reqMessage, String newQS, String delimiter_QS){
+ String finalMessage = reqMessage;
+ if (delimiter_QS.isEmpty()) delimiter_QS = "?";
+ // we assume that we are dealing with one HTTP message (not multiple in a pipeline)
+ String[] splittedRequest = reqMessage.split("\r\n|\r|\n", 2);
+ String firstline = splittedRequest[0];
+ firstline = firstline.trim(); // we don't have spaces before or after the first line if it is standard!
+
+ String QS_pattern = "\\"+delimiter_QS+"[^ \\s]+";
+ Pattern pattern = Pattern.compile(QS_pattern);
+ Matcher matcher = pattern.matcher(firstline);
+ if(matcher.find()) {
+ // replacing existing QS
+ firstline = matcher.replaceAll(delimiter_QS + newQS);
+ }else {
+ // adding QS to the request
+ String HTTP_version_pattern = "([ ]+HTTP/[^ \\s]+)";
+ pattern = Pattern.compile(HTTP_version_pattern);
+ matcher = pattern.matcher(firstline);
+ if(matcher.find()) {
+ firstline = matcher.replaceAll(delimiter_QS + newQS + "$1");
+ }else {
+ // HTTP v0.9?!
+ firstline += delimiter_QS + newQS;
+ }
+
+ }
+ finalMessage = firstline + "\r\n" + splittedRequest[1];
+ return finalMessage;
+ }
+
+ // get values of a header even when it is duplicated
+ public static ArrayList getHeaderValuesByName(List headers, String headername){
+ ArrayList result = new ArrayList();
+ headername = headername.toLowerCase();
+ for(String item:headers){
+ if(item.indexOf(":")>=0){
+ String[] headerItem = item.split(":",2);
+ String headerNameLC = headerItem[0].toLowerCase();
+ if(headerNameLC.equals(headername)){
+ // We have a match
+ result.add(headerItem[1].trim());
+ }
+ }
+ }
+ return result;
+ }
+
+ // get the first value of a header
+ public static String getHeaderValueByName(List headers, String headerName){
+ String result = "";
+ headerName = headerName.toLowerCase();
+ for(String item:headers){
+ if(item.indexOf(":")>=0){
+ String[] headerItem = item.split(":",2);
+ String headerNameLC = headerItem[0].toLowerCase();
+ if(headerNameLC.equals(headerName)){
+ // We have a match
+ result = headerItem[1].trim();
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ // replace a header value with the new value
+ public static List replaceHeaderValue(List headers, String headerName, String newHeaderValue, boolean isCaseSensitive) {
+ List result = new ArrayList();
+ if(!isCaseSensitive)
+ headerName = headerName.toLowerCase();
+ int counter = 0;
+ for(String item:headers){
+ if(item.indexOf(":")>=0 && counter != 0){
+ String[] headerItem = item.split(":",2);
+ String headerNameForComp = headerItem[0];
+ if(!isCaseSensitive)
+ headerNameForComp = headerNameForComp.toLowerCase();
+ if(headerNameForComp.equals(headerName)){
+ // We have a match
+ headerItem[1] = newHeaderValue;
+ }
+ result.add(headerItem[0]+": "+headerItem[1].trim());
+ }else{
+ result.add(item);
+ }
+ counter++;
+ }
+ return result;
+ }
+
+ // replace a header value with the new value
+ public static String replaceHeaderValue(String strHeader, String headerName, String newHeaderValue, boolean isCaseSensitive) {
+ String result = "";
+ String header_pattern_string = "(?im)^("+Pattern.quote(headerName)+":).*$";
+ if(isCaseSensitive) {
+ header_pattern_string = "(?m)^("+Pattern.quote(headerName)+":).*$";
+ }
+
+ Pattern header_pattern = Pattern.compile(header_pattern_string);
+ Matcher m = header_pattern.matcher(strHeader);
+ if(m.find()) {
+ // replacing
+ result = m.replaceAll("$1 " + newHeaderValue);
+ }else {
+ // adding
+ result = addHeader(strHeader, headerName, newHeaderValue);
+ }
+ return result;
+ }
+
+ // add a new header and its value - this is vulnerable to CRLF but that's intentional
+ public static String addHeader(String strHeader, String newHeaderName, String newHeaderValue) {
+ return addHeader(strHeader, newHeaderName + ": " +newHeaderValue);
+ }
+
+ // add a new header - this is vulnerable to CRLF but that's intentional
+ public static String addHeader(String strHeader, String newHeader) {
+ String result = "";
+ // adding the new header to the second line after the HTTP version!
+ result = strHeader.replaceFirst("([\r\n]+)", "$1"+newHeader+"$1");
+ return result;
+ }
+
+ // replace a header verb with a new verb
+ public static String replaceHeaderVerb(String strHeader, String newVerb) {
+ String result = "";
+ result = strHeader.replaceFirst("^[^ \t]+", newVerb);
+ return result;
+ }
+}
diff --git a/src/helper/UIStuff.java b/src/helper/UIStuff.java
new file mode 100644
index 0000000..6926b31
--- /dev/null
+++ b/src/helper/UIStuff.java
@@ -0,0 +1,87 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package helper;
+
+import java.awt.Component;
+import java.awt.Container;
+import javax.swing.JCheckBox;
+import javax.swing.JOptionPane;
+
+public class UIStuff {
+
+ // Show a message to the user
+ public static void showMessage(final String strMsg){
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ JOptionPane.showMessageDialog(null, strMsg);
+ }
+ }).start();
+
+ }
+
+ // Show a message to the user
+ public static void showWarningMessage(final String strMsg){
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ JOptionPane.showMessageDialog(null, strMsg, "Warning", JOptionPane.WARNING_MESSAGE);
+ }
+ }).start();
+
+ }
+
+ // Show a message to the user
+ public static String showPlainInputMessage(final String strMessage, final String strTitle, final String defaultValue){
+ String output = (String)JOptionPane.showInputDialog(null,
+ strMessage,strTitle,JOptionPane.PLAIN_MESSAGE, null, null, defaultValue);
+ if(output==null){
+ output = defaultValue;
+ }
+ return output;
+ }
+
+ // Common method to ask a multiple question
+ public static Integer askConfirmMessage(final String strTitle, final String strQuestion, String[] msgOptions){
+ final Object[] options = msgOptions;
+ final int[] choice = new int[1];
+ choice[0] = 0;
+ choice[0] = JOptionPane.showOptionDialog(null,
+ strQuestion,
+ strTitle,
+ JOptionPane.YES_NO_CANCEL_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[0]);
+ return choice[0];
+ }
+
+ // to update the JCheckbox background colour after using the customizeUiComponent() method
+ public static void updateJCheckBoxBackground(Container c) {
+ Component[] components = c.getComponents();
+ for(Component com : components) {
+ if(com instanceof JCheckBox) {
+ com.setBackground(c.getBackground());
+ } else if(com instanceof Container) {
+ updateJCheckBoxBackground((Container) com);
+ }
+ }
+ }
+}
diff --git a/src/helper/Utilities.java b/src/helper/Utilities.java
new file mode 100644
index 0000000..2c7d682
--- /dev/null
+++ b/src/helper/Utilities.java
@@ -0,0 +1,101 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package helper;
+
+public class Utilities {
+ private static final char[] hexChar = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+ };
+
+ public static String URLEncodeAll(String input) {
+ return URLEncode(input, "");
+ }
+
+ public static String URLEncodeSpecial(String input, String specialChars) {
+ if (specialChars.isEmpty()) specialChars = "!#$&'()*+,/:;=?@[] \"%-.<>\\^_`{|}~";
+ return URLEncode(input, specialChars);
+ }
+
+ public static String URLEncodeSpecial(String input) {
+ return URLEncodeSpecial(input, "");
+ }
+
+ public static String URLEncode(String input, String specialChars) {
+ // idea from https://codereview.stackexchange.com/questions/102591/efficient-url-escape-percent-encoding
+ if (input == null || input.isEmpty()) {
+ return input;
+ }
+ StringBuilder result = new StringBuilder(input);
+ for (int i = input.length() - 1; i >= 0; i--) {
+ if(specialChars.isEmpty()) {
+ result.replace(i, i + 1, "%" + String.format("%2s",Integer.toHexString(input.charAt(i))).replace(' ', '0').toUpperCase());
+ }else if(specialChars.indexOf(input.charAt(i)) != -1) {
+ result.replace(i, i + 1, "%" + String.format("%2s",Integer.toHexString(input.charAt(i)).replace(' ', '0').toUpperCase()));
+ }
+ }
+ return result.toString();
+ }
+
+ public static String URLEncodeAllBytes(byte[] input) {
+ // idea from https://codereview.stackexchange.com/questions/102591/efficient-url-escape-percent-encoding
+ if (input == null) {
+ return "";
+ }
+ StringBuilder result = new StringBuilder();
+ for (byte b: input) {
+ result.append("%" + String.format("%02x", b).toUpperCase());
+ }
+ return result.toString();
+ }
+
+ // https://docs.oracle.com/javase/tutorial/i18n/text/examples/UnicodeFormatter.java
+ static public String byteToHex(byte b) {
+ // Returns hex String representation of byte b
+ char[] array = { hexChar[(b >> 4) & 0x0f], hexChar[b & 0x0f] };
+ return new String(array);
+ }
+
+ // https://docs.oracle.com/javase/tutorial/i18n/text/examples/UnicodeFormatter.java
+ static public String charToHex(char c) {
+ // Returns hex String representation of char c
+ byte hi = (byte) (c >>> 8);
+ byte lo = (byte) (c & 0xff);
+ return byteToHex(hi) + byteToHex(lo);
+ }
+
+
+ // http://www.xinotes.net/notes/note/812/
+ static public String unicodeEscape(String s, boolean encodeAll, boolean isURL) {
+ StringBuilder sb = new StringBuilder();
+ String escapePrefix = "\\u";
+ if(isURL) escapePrefix = "%u";
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if ((c >> 7) > 0 || encodeAll) {
+ sb.append(escapePrefix);
+ sb.append(hexChar[(c >> 12) & 0xF]); // append the hex character for the left-most 4-bits
+ sb.append(hexChar[(c >> 8) & 0xF]); // hex for the second group of 4-bits from the left
+ sb.append(hexChar[(c >> 4) & 0xF]); // hex for the third group
+ sb.append(hexChar[c & 0xF]); // hex for the last group, e.g., the right most 4-bits
+ }
+ else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+
+}
diff --git a/src/mutation/HTTPEncodingObject.java b/src/mutation/HTTPEncodingObject.java
new file mode 100644
index 0000000..7d6bd17
--- /dev/null
+++ b/src/mutation/HTTPEncodingObject.java
@@ -0,0 +1,391 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package mutation;
+
+public class HTTPEncodingObject {
+ boolean preventReEncoding = true;
+ boolean encodeMicrosoftURLEncode = true; // to encode utf-8 characters to their %uXXXX format
+ boolean encodeDespiteErrors = false; // this will be ignored if encodeMicrosoftURLEncode=true
+ boolean addACharToEmptyBody = true;
+ boolean replaceGETwithPOST = false;
+ boolean isEncodable_QS = true;
+ boolean isEncodable_body = true;
+ boolean isEncodable_QS_delimiter = false;
+ boolean isEncodable_urlencoded_body_delimiter = false;
+ boolean isEncodable_QS_equal_sign = false;
+ boolean isEncodable_urlencoded_body_equal_sign = false;
+ String delimiter_QS = "?";
+ String delimiter_QS_param = "&";
+ String QS_equalSign = "=";
+ String delimiter_urlencoded_body_param = "&";
+ String body_param_equalSign = "=";
+ boolean isURLEncoded_incoming_QS = true;
+ boolean isURLEncoded_incoming_body = true; // this is not active when it is a multipart message
+ boolean isURLEncoded_outgoing_QS = true;
+ boolean isURLEncoded_outgoing_body = true; // this is not active when it is a multipart message
+ boolean isAllChar_URLEncoded_outgoing_QS = true; // only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters
+ boolean isAllChar_URLEncoded_outgoing_body = true; // only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters
+ boolean trimSpacesInContentTypeHeaderValues = true; // IIS needs this, Apache does not!
+ boolean encodeNameValueOnlyMultipart = false; // python django needs this, IIS does not!
+ String outgoing_request_encoding = "ibm500";
+ boolean use_incoming_charset_for_request_encoding = true;
+ String incoming_request_encoding = "utf-8";
+ public String[] normalEncodings = {"UTF-8", "UTF-16", "UTF-32", "ISO-8859-1"};
+
+ public HTTPEncodingObject(boolean preventReEncoding, boolean encodeMicrosoftURLEncode, boolean encodeDespiteErrors,
+ boolean addACharToEmptyBody, boolean replaceGETwithPOST, boolean isEncodable_QS, boolean isEncodable_body,
+ boolean isEncodable_QS_delimiter, boolean isEncodable_urlencoded_body_delimiter,
+ boolean isEncodable_QS_equal_sign, boolean isEncodable_urlencoded_body_equal_sign, String delimiter_QS,
+ String delimiter_QS_param, String qS_equalSign, String delimiter_urlencoded_body_param,
+ String body_param_equalSign, boolean isURLEncoded_incoming_QS, boolean isURLEncoded_incoming_body,
+ boolean isURLEncoded_outgoing_QS, boolean isURLEncoded_outgoing_body,
+ boolean isAllChar_URLEncoded_outgoing_QS, boolean isAllChar_URLEncoded_outgoing_body,
+ boolean trimSpacesInContentTypeHeaderValues, boolean encodeNameValueOnlyMultipart,
+ String outgoing_request_encoding, boolean use_incoming_charset_for_request_encoding,
+ String incoming_request_encoding, String[] normalEncodings) {
+ super();
+ this.preventReEncoding = preventReEncoding;
+ this.encodeMicrosoftURLEncode = encodeMicrosoftURLEncode;
+ this.encodeDespiteErrors = encodeDespiteErrors;
+ this.addACharToEmptyBody = addACharToEmptyBody;
+ this.replaceGETwithPOST = replaceGETwithPOST;
+ this.isEncodable_QS = isEncodable_QS;
+ this.isEncodable_body = isEncodable_body;
+ this.isEncodable_QS_delimiter = isEncodable_QS_delimiter;
+ this.isEncodable_urlencoded_body_delimiter = isEncodable_urlencoded_body_delimiter;
+ this.isEncodable_QS_equal_sign = isEncodable_QS_equal_sign;
+ this.isEncodable_urlencoded_body_equal_sign = isEncodable_urlencoded_body_equal_sign;
+ this.delimiter_QS = delimiter_QS;
+ this.delimiter_QS_param = delimiter_QS_param;
+ QS_equalSign = qS_equalSign;
+ this.delimiter_urlencoded_body_param = delimiter_urlencoded_body_param;
+ this.body_param_equalSign = body_param_equalSign;
+ this.isURLEncoded_incoming_QS = isURLEncoded_incoming_QS;
+ this.isURLEncoded_incoming_body = isURLEncoded_incoming_body;
+ this.isURLEncoded_outgoing_QS = isURLEncoded_outgoing_QS;
+ this.isURLEncoded_outgoing_body = isURLEncoded_outgoing_body;
+ this.isAllChar_URLEncoded_outgoing_QS = isAllChar_URLEncoded_outgoing_QS;
+ this.isAllChar_URLEncoded_outgoing_body = isAllChar_URLEncoded_outgoing_body;
+ this.trimSpacesInContentTypeHeaderValues = trimSpacesInContentTypeHeaderValues;
+ this.encodeNameValueOnlyMultipart = encodeNameValueOnlyMultipart;
+ this.outgoing_request_encoding = outgoing_request_encoding;
+ this.use_incoming_charset_for_request_encoding = use_incoming_charset_for_request_encoding;
+ this.incoming_request_encoding = incoming_request_encoding;
+ this.normalEncodings = normalEncodings;
+ }
+
+ public HTTPEncodingObject() {
+
+ }
+
+ public HTTPEncodingObject(String sampleType) {
+ switch(sampleType.toLowerCase()) {
+ case "jsp":
+ case "jsp/tomcat":
+ this.preventReEncoding = true;
+ this.encodeMicrosoftURLEncode = false; // to encode utf-8 characters to their %uXXXX format
+ this.encodeDespiteErrors = false; // this will be ignored if encodeMicrosoftURLEncode=true
+ this.addACharToEmptyBody = false;
+ this.replaceGETwithPOST = false;
+ this.isEncodable_QS = false; // this is for JSP on Tomcat
+ this.isEncodable_body = true;
+ this.isEncodable_QS_delimiter = false;
+ this.isEncodable_urlencoded_body_delimiter = false;
+ this.isEncodable_QS_equal_sign = false;
+ this.isEncodable_urlencoded_body_equal_sign = false;
+ this.delimiter_QS = "?";
+ this.delimiter_QS_param = "&";
+ this.QS_equalSign = "=";
+ this.delimiter_urlencoded_body_param = "&";
+ this.body_param_equalSign = "=";
+ this.isURLEncoded_incoming_QS = true;
+ this.isURLEncoded_incoming_body = true; // this is not active when it is a multipart message
+ this.isURLEncoded_outgoing_QS = true;
+ this.isURLEncoded_outgoing_body = true; // this is not active when it is a multipart message
+ this.isAllChar_URLEncoded_outgoing_QS = true; // only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters
+ this.isAllChar_URLEncoded_outgoing_body = true; // only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters
+ this.trimSpacesInContentTypeHeaderValues = true; // similar to IIS and ASPX
+ this.encodeNameValueOnlyMultipart = true; // probably won't work here... needs more testing
+ this.outgoing_request_encoding = "ibm500";
+ this.use_incoming_charset_for_request_encoding = true;
+ this.incoming_request_encoding = "utf-8";
+ break;
+
+ case "py2":
+ case "py2/django":
+ this.preventReEncoding = true;
+ this.encodeMicrosoftURLEncode = false; // to encode utf-8 characters to their %uXXXX format
+ this.encodeDespiteErrors = false; // this will be ignored if encodeMicrosoftURLEncode=true
+ this.addACharToEmptyBody = false;
+ this.replaceGETwithPOST = false;
+ this.isEncodable_QS = true;
+ this.isEncodable_body = true;
+ this.isEncodable_QS_delimiter = false;
+ this.isEncodable_urlencoded_body_delimiter = false;
+ this.isEncodable_QS_equal_sign = false;
+ this.isEncodable_urlencoded_body_equal_sign = false;
+ this.delimiter_QS = "?";
+ this.delimiter_QS_param = "&";
+ this.QS_equalSign = "=";
+ this.delimiter_urlencoded_body_param = "&";
+ this.body_param_equalSign = "=";
+ this.isURLEncoded_incoming_QS = true;
+ this.isURLEncoded_incoming_body = true; // this is not active when it is a multipart message
+ this.isURLEncoded_outgoing_QS = true;
+ this.isURLEncoded_outgoing_body = true; // this is not active when it is a multipart message
+ this.isAllChar_URLEncoded_outgoing_QS = true; // only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters
+ this.isAllChar_URLEncoded_outgoing_body = true; // only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters
+ this.trimSpacesInContentTypeHeaderValues = true; // similar to IIS and ASPX
+ this.encodeNameValueOnlyMultipart = true; // for python
+ this.outgoing_request_encoding = "ibm500";
+ this.use_incoming_charset_for_request_encoding = true;
+ this.incoming_request_encoding = "utf-8";
+ break;
+
+ case "py3":
+ case "py3/django":
+ this.preventReEncoding = true;
+ this.encodeMicrosoftURLEncode = false; // to encode utf-8 characters to their %uXXXX format
+ this.encodeDespiteErrors = false; // this will be ignored if encodeMicrosoftURLEncode=true
+ this.addACharToEmptyBody = false;
+ this.replaceGETwithPOST = false;
+ this.isEncodable_QS = true;
+ this.isEncodable_body = true;
+ this.isEncodable_QS_delimiter = true;
+ this.isEncodable_urlencoded_body_delimiter = true;
+ this.isEncodable_QS_equal_sign = true;
+ this.isEncodable_urlencoded_body_equal_sign = true;
+ this.delimiter_QS = "?";
+ this.delimiter_QS_param = "&";
+ this.QS_equalSign = "=";
+ this.delimiter_urlencoded_body_param = "&";
+ this.body_param_equalSign = "=";
+ this.isURLEncoded_incoming_QS = true;
+ this.isURLEncoded_incoming_body = true; // this is not active when it is a multipart message
+ this.isURLEncoded_outgoing_QS = false;
+ this.isURLEncoded_outgoing_body = false; // this is not active when it is a multipart message
+ this.isAllChar_URLEncoded_outgoing_QS = false; // only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters
+ this.isAllChar_URLEncoded_outgoing_body = false; // only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters
+ this.trimSpacesInContentTypeHeaderValues = false; // similar to IIS and ASPX
+ this.encodeNameValueOnlyMultipart = true; // for python
+ this.outgoing_request_encoding = "ibm500";
+ this.use_incoming_charset_for_request_encoding = true;
+ this.incoming_request_encoding = "utf-8";
+ break;
+
+ case "aspx":
+ case "aspx/iis":
+ this.preventReEncoding = true;
+ this.encodeMicrosoftURLEncode = true; // to encode utf-8 characters to their %uXXXX format
+ this.encodeDespiteErrors = false; // this will be ignored if encodeMicrosoftURLEncode=true
+ this.addACharToEmptyBody = true;
+ this.replaceGETwithPOST = false;
+ this.isEncodable_QS = true;
+ this.isEncodable_body = true;
+ this.isEncodable_QS_delimiter = false;
+ this.isEncodable_urlencoded_body_delimiter = false;
+ this.isEncodable_QS_equal_sign = false;
+ this.isEncodable_urlencoded_body_equal_sign = false;
+ this.delimiter_QS = "?";
+ this.delimiter_QS_param = "&";
+ this.QS_equalSign = "=";
+ this.delimiter_urlencoded_body_param = "&";
+ this.body_param_equalSign = "=";
+ this.isURLEncoded_incoming_QS = true;
+ this.isURLEncoded_incoming_body = true; // this is not active when it is a multipart message
+ this.isURLEncoded_outgoing_QS = true;
+ this.isURLEncoded_outgoing_body = true; // this is not active when it is a multipart message
+ this.isAllChar_URLEncoded_outgoing_QS = true; // only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters
+ this.isAllChar_URLEncoded_outgoing_body = true; // only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters
+ this.trimSpacesInContentTypeHeaderValues = true; // IIS needs this, Apache does not!
+ this.encodeNameValueOnlyMultipart = false; // python django needs this, IIS does not!
+ this.outgoing_request_encoding = "ibm500";
+ this.use_incoming_charset_for_request_encoding = true;
+ this.incoming_request_encoding = "utf-8";
+ break;
+ }
+ }
+
+ public synchronized boolean isPreventReEncoding() {
+ return preventReEncoding;
+ }
+ public synchronized void setPreventReEncoding(boolean preventReEncoding) {
+ this.preventReEncoding = preventReEncoding;
+ }
+ public synchronized boolean isEncodeMicrosoftURLEncode() {
+ return encodeMicrosoftURLEncode;
+ }
+ public synchronized void setEncodeMicrosoftURLEncode(boolean encodeMicrosoftURLEncode) {
+ this.encodeMicrosoftURLEncode = encodeMicrosoftURLEncode;
+ }
+ public synchronized boolean isEncodeDespiteErrors() {
+ return encodeDespiteErrors;
+ }
+ public synchronized void setEncodeDespiteErrors(boolean encodeDespiteErrors) {
+ this.encodeDespiteErrors = encodeDespiteErrors;
+ }
+ public synchronized boolean isAddACharToEmptyBody() {
+ return addACharToEmptyBody;
+ }
+ public synchronized void setAddACharToEmptyBody(boolean addACharToEmptyBody) {
+ this.addACharToEmptyBody = addACharToEmptyBody;
+ }
+ public synchronized boolean isReplaceGETwithPOST() {
+ return replaceGETwithPOST;
+ }
+ public synchronized void setReplaceGETwithPOST(boolean replaceGETwithPOST) {
+ this.replaceGETwithPOST = replaceGETwithPOST;
+ }
+ public synchronized boolean isEncodable_QS() {
+ return isEncodable_QS;
+ }
+ public synchronized void setEncodable_QS(boolean isEncodable_QS) {
+ this.isEncodable_QS = isEncodable_QS;
+ }
+ public synchronized boolean isEncodable_body() {
+ return isEncodable_body;
+ }
+ public synchronized void setEncodable_body(boolean isEncodable_body) {
+ this.isEncodable_body = isEncodable_body;
+ }
+ public synchronized boolean isEncodable_QS_delimiter() {
+ return isEncodable_QS_delimiter;
+ }
+ public synchronized void setEncodable_QS_delimiter(boolean isEncodable_QS_delimiter) {
+ this.isEncodable_QS_delimiter = isEncodable_QS_delimiter;
+ }
+ public synchronized boolean isEncodable_urlencoded_body_delimiter() {
+ return isEncodable_urlencoded_body_delimiter;
+ }
+ public synchronized void setEncodable_urlencoded_body_delimiter(boolean isEncodable_urlencoded_body_delimiter) {
+ this.isEncodable_urlencoded_body_delimiter = isEncodable_urlencoded_body_delimiter;
+ }
+ public synchronized boolean isEncodable_QS_equal_sign() {
+ return isEncodable_QS_equal_sign;
+ }
+ public synchronized void setEncodable_QS_equal_sign(boolean isEncodable_QS_equal_sign) {
+ this.isEncodable_QS_equal_sign = isEncodable_QS_equal_sign;
+ }
+ public synchronized boolean isEncodable_urlencoded_body_equal_sign() {
+ return isEncodable_urlencoded_body_equal_sign;
+ }
+ public synchronized void setEncodable_urlencoded_body_equal_sign(boolean isEncodable_urlencoded_body_equal_sign) {
+ this.isEncodable_urlencoded_body_equal_sign = isEncodable_urlencoded_body_equal_sign;
+ }
+ public synchronized String getDelimiter_QS() {
+ return delimiter_QS;
+ }
+ public synchronized void setDelimiter_QS(String delimiter_QS) {
+ this.delimiter_QS = delimiter_QS;
+ }
+ public synchronized String getDelimiter_QS_param() {
+ return delimiter_QS_param;
+ }
+ public synchronized void setDelimiter_QS_param(String delimiter_QS_param) {
+ this.delimiter_QS_param = delimiter_QS_param;
+ }
+ public synchronized String getQS_equalSign() {
+ return QS_equalSign;
+ }
+ public synchronized void setQS_equalSign(String qS_equalSign) {
+ QS_equalSign = qS_equalSign;
+ }
+ public synchronized String getDelimiter_urlencoded_body_param() {
+ return delimiter_urlencoded_body_param;
+ }
+ public synchronized void setDelimiter_urlencoded_body_param(String delimiter_urlencoded_body_param) {
+ this.delimiter_urlencoded_body_param = delimiter_urlencoded_body_param;
+ }
+ public synchronized String getBody_param_equalSign() {
+ return body_param_equalSign;
+ }
+ public synchronized void setBody_param_equalSign(String body_param_equalSign) {
+ this.body_param_equalSign = body_param_equalSign;
+ }
+ public synchronized boolean isURLEncoded_incoming_QS() {
+ return isURLEncoded_incoming_QS;
+ }
+ public synchronized void setURLEncoded_incoming_QS(boolean isURLEncoded_incoming_QS) {
+ this.isURLEncoded_incoming_QS = isURLEncoded_incoming_QS;
+ }
+ public synchronized boolean isURLEncoded_incoming_body() {
+ return isURLEncoded_incoming_body;
+ }
+ public synchronized void setURLEncoded_incoming_body(boolean isURLEncoded_incoming_body) {
+ this.isURLEncoded_incoming_body = isURLEncoded_incoming_body;
+ }
+ public synchronized boolean isURLEncoded_outgoing_QS() {
+ return isURLEncoded_outgoing_QS;
+ }
+ public synchronized void setURLEncoded_outgoing_QS(boolean isURLEncoded_outgoing_QS) {
+ this.isURLEncoded_outgoing_QS = isURLEncoded_outgoing_QS;
+ }
+ public synchronized boolean isAllChar_URLEncoded_outgoing_QS() {
+ return isAllChar_URLEncoded_outgoing_QS;
+ }
+ public synchronized void setAllChar_URLEncoded_outgoing_QS(boolean isAllChar_URLEncoded_outgoing_QS) {
+ this.isAllChar_URLEncoded_outgoing_QS = isAllChar_URLEncoded_outgoing_QS;
+ }
+ public synchronized boolean isURLEncoded_outgoing_body() {
+ return isURLEncoded_outgoing_body;
+ }
+ public synchronized void setURLEncoded_outgoing_body(boolean isURLEncoded_outgoing_body) {
+ this.isURLEncoded_outgoing_body = isURLEncoded_outgoing_body;
+ }
+ public synchronized boolean isAllChar_URLEncoded_outgoing_body() {
+ return isAllChar_URLEncoded_outgoing_body;
+ }
+ public synchronized void setAllChar_URLEncoded_outgoing_body(boolean isAllChar_URLEncoded_outgoing_body) {
+ this.isAllChar_URLEncoded_outgoing_body = isAllChar_URLEncoded_outgoing_body;
+ }
+ public synchronized boolean isTrimSpacesInContentTypeHeaderValues() {
+ return trimSpacesInContentTypeHeaderValues;
+ }
+ public synchronized void setTrimSpacesInContentTypeHeaderValues(boolean trimSpacesInContentTypeHeaderValues) {
+ this.trimSpacesInContentTypeHeaderValues = trimSpacesInContentTypeHeaderValues;
+ }
+ public synchronized boolean isEncodeNameValueOnlyMultipart() {
+ return encodeNameValueOnlyMultipart;
+ }
+ public synchronized void setEncodeNameValueOnlyMultipart(boolean encodeNameValueOnlyMultipart) {
+ this.encodeNameValueOnlyMultipart = encodeNameValueOnlyMultipart;
+ }
+ public synchronized String getOutgoing_request_encoding() {
+ return outgoing_request_encoding;
+ }
+ public synchronized void setOutgoing_request_encoding(String outgoing_request_encoding) {
+ this.outgoing_request_encoding = outgoing_request_encoding;
+ }
+ public synchronized boolean isUse_incoming_charset_for_request_encoding() {
+ return use_incoming_charset_for_request_encoding;
+ }
+ public synchronized void setUse_incoming_charset_for_request_encoding(
+ boolean use_incoming_charset_for_request_encoding) {
+ this.use_incoming_charset_for_request_encoding = use_incoming_charset_for_request_encoding;
+ }
+ public synchronized String getIncoming_request_encoding() {
+ return incoming_request_encoding;
+ }
+ public synchronized void setIncoming_request_encoding(String incoming_request_encoding) {
+ this.incoming_request_encoding = incoming_request_encoding;
+ }
+ public synchronized String[] getNormalEncodings() {
+ return normalEncodings;
+ }
+ public synchronized void setNormalEncodings(String[] normalEncodings) {
+ this.normalEncodings = normalEncodings;
+ }
+
+}
diff --git a/src/mutation/HttpEncoding.java b/src/mutation/HttpEncoding.java
new file mode 100644
index 0000000..e38c96b
--- /dev/null
+++ b/src/mutation/HttpEncoding.java
@@ -0,0 +1,382 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package mutation;
+
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+//import java.nio.ByteBuffer;
+//import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+//import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
+//import burp.IRequestInfo;
+
+public class HttpEncoding {
+ private boolean isDebug = false;
+ private IBurpExtenderCallbacks _callbacks;
+ private IExtensionHelpers _helpers;
+ private PrintWriter _stdout;
+ private PrintWriter _stderr;
+ private HTTPEncodingObject currentHTTPEncodingObject = new HTTPEncodingObject();
+
+ public HttpEncoding(IBurpExtenderCallbacks callbacks, PrintWriter stdout, PrintWriter stderr, boolean isDebug) {
+ _callbacks = callbacks;
+ _helpers = _callbacks.getHelpers();
+ _stdout = stdout;
+ _stderr = stderr;
+ this.isDebug = isDebug;
+ }
+
+ private void showDebugMessage(Object object) {
+ if(isDebug)
+ _stdout.println(object.toString());
+ }
+
+ private String encode(String inputStr, boolean URLEncodeResult, boolean URLEncodeAll) throws Exception {
+ String result = "";
+ if(currentHTTPEncodingObject.encodeMicrosoftURLEncode) {
+ // We want to encode characters that are ASCII readable and the rest should be encoded using %uXXXX format
+ StringBuilder sb = new StringBuilder();
+ String MSEncodedInputStr = helper.Utilities.unicodeEscape(inputStr, false, true);
+ String[] MSEncodedInputStrSplitted = MSEncodedInputStr.split("%u");
+ int counter = 0;
+ for(String str:MSEncodedInputStrSplitted) {
+ if(str.length()>0) {
+ String tempStr = "";
+ if(counter==0) {
+ tempStr = encode(str, currentHTTPEncodingObject.outgoing_request_encoding);
+ }else {
+ sb.append("%u"+str.substring(0, 4));
+ if(str.length()>4)
+ tempStr = encode(str.substring(4), currentHTTPEncodingObject.outgoing_request_encoding);
+ }
+ if(tempStr.length()>0) {
+ if(URLEncodeResult){
+ if(URLEncodeAll) {
+ tempStr = helper.Utilities.URLEncodeAll(tempStr);
+ }else {
+ tempStr = _helpers.urlEncode(tempStr);
+ }
+ }
+ sb.append(tempStr);
+ }
+ }
+ counter++;
+ }
+ result = sb.toString();
+ }else {
+ if(!currentHTTPEncodingObject.encodeDespiteErrors) {
+ // Detecting if there is a character that can be encoded to something like \\u[NotZero][NotZero]XX
+ boolean hasHigherUTF8 = false;
+ char[] hexChar = {
+ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+ };
+ for (int i = 0; i < inputStr.length(); i++) {
+ char c = inputStr.charAt(i);
+ if ((c >> 7) > 0) {
+ if(hexChar[(c >> 12) & 0xF]!=0 || hexChar[(c >> 8) & 0xF]!=0) {
+ hasHigherUTF8 = true;
+ }
+ }
+ }
+ if(hasHigherUTF8) {
+ showDebugMessage("Error in encoding , a character will be converted to a \"?\".");
+ throw new Exception("\"Message could not be encoded properly - try it with encodeDespiteErrors=True or encodeMicrosoftURLEncode=True if the request does not change anything on the server\"");
+ }
+ }
+ result = encode(inputStr, currentHTTPEncodingObject.outgoing_request_encoding);
+ if(URLEncodeResult){
+ if(URLEncodeAll) {
+ result = helper.Utilities.URLEncodeAll(result);
+ }else {
+ result = _helpers.urlEncode(result);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public String encode(String strInput,String outgoingEncoding) {
+ String result = strInput;
+ if(outgoingEncoding.isEmpty()) outgoingEncoding = currentHTTPEncodingObject.outgoing_request_encoding;
+ try{
+ showDebugMessage("Encode method using outgoingEncoding: " + outgoingEncoding);
+ showDebugMessage("strInput: " + strInput);
+ result = new String(strInput.getBytes(outgoingEncoding), "ISO-8859-1");
+ if(outgoingEncoding.startsWith("ibm") || outgoingEncoding.startsWith("cp")) {
+ // to support ibm.swapLF=true - see https://stackoverflow.com/questions/24633276/encoding-strangeness-with-cp500-lf-nel
+ result=result.replaceAll("(?im)\\x15", "%");
+ }
+ //long questionMarkCounterAfter = result.chars().filter(ch -> ch == '?').count();
+ showDebugMessage("result: " + result);
+ }catch(UnsupportedEncodingException e){
+ _stderr.println(e.getMessage());
+ }
+ return result;
+ }
+
+ public String encodeHTTPMessage(burp.IHttpRequestResponse iHttpRequestResponse, String incomingEncoding, String outgoingEncoding) throws UnsupportedEncodingException {
+ return encodeHTTPMessage(iHttpRequestResponse.getRequest(), incomingEncoding, outgoingEncoding);
+ }
+
+
+ public String encodeHTTPMessage(byte[] fullMessageByte,String incomingEncoding, String outgoingEncoding) throws UnsupportedEncodingException {
+ boolean hasSomethingChanged = false;
+ if (incomingEncoding.isEmpty()) incomingEncoding = currentHTTPEncodingObject.incoming_request_encoding;
+ String fullMessage = new String(fullMessageByte,incomingEncoding);
+ //IRequestInfo requestInfo = _helpers.analyzeRequest(fullMessageByte);
+ String encodedRequest = "";
+ String validContentType = "";
+ String[] acceptable_content_types = {"application/x-www-form-urlencoded","multipart/form-data","xml","json"};
+ if(outgoingEncoding.isEmpty()) outgoingEncoding = currentHTTPEncodingObject.outgoing_request_encoding;
+ String[] headerBody = helper.HTTPMessage.getHeaderAndBody(fullMessage);
+ String header = headerBody[0];
+ String body = headerBody[1];
+ String content_type = helper.HTTPMessage.findHeaderContentType(header);
+ String charset = helper.HTTPMessage.findCharsetFromHeader(header, currentHTTPEncodingObject.trimSpacesInContentTypeHeaderValues).toUpperCase();
+
+ if(currentHTTPEncodingObject.use_incoming_charset_for_request_encoding && Charset.availableCharsets().keySet().contains(charset)) {
+ currentHTTPEncodingObject.incoming_request_encoding = charset;
+ }
+
+ if(currentHTTPEncodingObject.preventReEncoding && !charset.isEmpty() && !(Arrays.asList(currentHTTPEncodingObject.normalEncodings).contains(currentHTTPEncodingObject.incoming_request_encoding))) {
+ showDebugMessage("The request seems to be encoded already using " + charset + " that is not one of " + Arrays.asList(currentHTTPEncodingObject.normalEncodings).toString());
+ return "";
+ }
+
+ //List> QS_params = new ArrayList>();
+
+ showDebugMessage("content-type was: " + content_type);
+
+ for (String acceptable_content_type : acceptable_content_types) {
+ if(content_type.toLowerCase().contains(acceptable_content_type)) {
+ validContentType = acceptable_content_type;
+ break;
+ }
+ }
+
+ try {
+ if(currentHTTPEncodingObject.isEncodable_QS) {
+ List> original_qs_params = helper.HTTPMessage.getQueryString(header, currentHTTPEncodingObject.delimiter_QS, currentHTTPEncodingObject.delimiter_QS_param);
+ showDebugMessage("QueryString:");
+ showDebugMessage(original_qs_params);
+ String newQueryString = "";
+
+ if(currentHTTPEncodingObject.isEncodable_QS_delimiter) {
+ currentHTTPEncodingObject.delimiter_QS = encode(currentHTTPEncodingObject.delimiter_QS, false, false);
+ }
+ if (currentHTTPEncodingObject.isEncodable_QS_equal_sign) {
+ currentHTTPEncodingObject.QS_equalSign = encode(currentHTTPEncodingObject.QS_equalSign, false, false);
+ }
+ // the parameters might be url encoded - we need to decode them before mutation!
+ // in the future, burp converter should be replaced really so this class can be used independently
+ for(List item:original_qs_params) {
+ String param_name = item.get(0);
+ String param_value = item.get(1);
+ if(currentHTTPEncodingObject.isURLEncoded_incoming_QS){
+ // Burp Sutie can't handle utf-8 in URL decoding! e.g.: _helpers.urlDecode("تست")
+ param_name = new String(_helpers.urlDecode(param_name.getBytes("ISO-8859-1")),currentHTTPEncodingObject.incoming_request_encoding);
+ //param_name = new String(param_name.getBytes());
+ param_value = new String(_helpers.urlDecode(param_value.getBytes("ISO-8859-1")),currentHTTPEncodingObject.incoming_request_encoding);
+ }
+ String param_name_encoded = encode(param_name, currentHTTPEncodingObject.isURLEncoded_outgoing_QS, currentHTTPEncodingObject.isAllChar_URLEncoded_outgoing_QS);
+ String param_value_encoded = encode(param_value, currentHTTPEncodingObject.isURLEncoded_outgoing_QS, currentHTTPEncodingObject.isAllChar_URLEncoded_outgoing_QS);
+
+ if(!newQueryString.isEmpty()) {
+ newQueryString += currentHTTPEncodingObject.delimiter_QS_param;
+ }
+ newQueryString += param_name_encoded + currentHTTPEncodingObject.QS_equalSign + param_value_encoded;
+ }
+ if(!newQueryString.isEmpty()) {
+ hasSomethingChanged = true;
+ header = helper.HTTPMessage.replaceQueryString(header,newQueryString);
+ showDebugMessage(header);
+ }
+ }
+
+ if(!validContentType.isEmpty()) {
+
+ if(currentHTTPEncodingObject.isEncodable_body && body.length()>0) {
+ // encoding body
+ switch(validContentType) {
+ case "application/x-www-form-urlencoded":
+ List> original_body_params = helper.HTTPMessage.getURLEncodedBodyParams(body, true, currentHTTPEncodingObject.delimiter_urlencoded_body_param);
+ showDebugMessage("Body Params:");
+ showDebugMessage(original_body_params);
+ String newBodyParams = "";
+ if(currentHTTPEncodingObject.isEncodable_urlencoded_body_delimiter) {
+ currentHTTPEncodingObject.delimiter_urlencoded_body_param = encode(currentHTTPEncodingObject.delimiter_urlencoded_body_param, false, false);
+ }
+ if (currentHTTPEncodingObject.isEncodable_urlencoded_body_equal_sign) {
+ currentHTTPEncodingObject.body_param_equalSign = encode(currentHTTPEncodingObject.body_param_equalSign, false, false);
+ }
+ // the parameters might be url encoded - we need to decode them before mutation!
+ // in the future, burp converter should be replaced really so this class can be used independently
+ for(List item:original_body_params) {
+ String param_name = item.get(0);
+ String param_value = item.get(1);
+ if(currentHTTPEncodingObject.isURLEncoded_incoming_body){
+ // Burp Sutie can't handle utf-8 in URL decoding! e.g.: _helpers.urlDecode("تست")
+ param_name = new String(_helpers.urlDecode(param_name.getBytes("ISO-8859-1")),currentHTTPEncodingObject.incoming_request_encoding);
+ //param_name = new String(param_name.getBytes());
+ param_value = new String(_helpers.urlDecode(param_value.getBytes("ISO-8859-1")),currentHTTPEncodingObject.incoming_request_encoding);
+ }
+ String param_name_encoded = encode(param_name, currentHTTPEncodingObject.isURLEncoded_outgoing_body, currentHTTPEncodingObject.isAllChar_URLEncoded_outgoing_body);
+ String param_value_encoded = encode(param_value, currentHTTPEncodingObject.isURLEncoded_outgoing_body, currentHTTPEncodingObject.isAllChar_URLEncoded_outgoing_body);
+
+ if(!newBodyParams.isEmpty()) {
+ newBodyParams += currentHTTPEncodingObject.delimiter_urlencoded_body_param;
+ }
+ newBodyParams += param_name_encoded + currentHTTPEncodingObject.body_param_equalSign + param_value_encoded;
+ }
+
+ if(!newBodyParams.isEmpty()) {
+ body = newBodyParams;
+ hasSomethingChanged = true;
+ }
+
+ break;
+ case "multipart/form-data":
+ // find the boundary value from the content-type header
+ String boundaryValue = helper.HTTPMessage.findBoundaryFromHeader(header, currentHTTPEncodingObject.trimSpacesInContentTypeHeaderValues);
+ if(!charset.equals("UTF-8") && !charset.isEmpty()) {
+ _stdout.println("Charset is "+charset + " in a MultiPart message, message has probably been corrupted already :(");
+ }
+ if(!boundaryValue.isEmpty()) {
+ // we need to parse it... yes and here is the source of another canonical issue :p
+ StringBuilder finalBody = new StringBuilder("");
+ String [] bodyparts;
+ bodyparts = body.split("[\r]?[\n]?\\-\\-"+Pattern.quote(boundaryValue)+"(\\-\\-)?[\r]?[\n]?");
+ if(bodyparts.length > 1) {
+ for(int i=0; i < bodyparts.length; i++) {
+ String bodypart = bodyparts[i];
+ String [] bodypart_header_body;
+ if(bodypart.isEmpty() && i < bodyparts.length-1) {
+ if(finalBody.length()>0)
+ finalBody.append("\r\n");
+ finalBody.append("--");
+ finalBody.append(boundaryValue);
+ }else {
+ bodypart_header_body = bodypart.split("\r\n\r\n",2);
+ if(bodypart_header_body.length==2) {
+ String part_header_encoded = "";
+ String part_body_encoded = "";
+ if(currentHTTPEncodingObject.encodeNameValueOnlyMultipart) {
+ // Example: python Django needs to encode the name value rather than the whole header
+ String nameRegEx = "(Content\\-Disposition: .*name=[\"])([^\"]+)(.*)";
+ Pattern pattern_param_name = Pattern.compile(nameRegEx);
+ Matcher matcher_param_name = pattern_param_name.matcher(bodypart_header_body[0]);
+ if (matcher_param_name.find())
+ {
+ String param_name = matcher_param_name.group(2);
+ String param_name_encoded = encode(param_name, false, false);
+ part_header_encoded = bodypart_header_body[0].replaceAll(nameRegEx, "$1"+param_name_encoded+"$3");
+ }else {
+ part_header_encoded = bodypart_header_body[0];
+ }
+ part_body_encoded = encode(bodypart_header_body[1], false, false);
+ }else {
+ // Example: IIS needs the full header being encoded but line by line!
+ // Assuming CR LF is used - otherwise we need to split it differently :(
+ String[] partHeaderArray = bodypart_header_body[0].split("[\r\n]");
+ for(String partHeaderLine:partHeaderArray) {
+ if(!partHeaderLine.isEmpty()) {
+ if(part_header_encoded.isEmpty())
+ part_header_encoded = encode(partHeaderLine, false, false);
+ else
+ part_header_encoded += "\r\n" + encode(partHeaderLine, false, false);
+ }
+ }
+ //part_header_encoded = encode(bodypart_header_body[0], false, false);
+ part_body_encoded = encode(bodypart_header_body[1], false, false);
+ }
+ if(finalBody.length()>0)
+ finalBody.append("\r\n");
+ finalBody.append(part_header_encoded);
+ finalBody.append("\r\n\r\n");
+ finalBody.append(part_body_encoded);
+ finalBody.append("\r\n--");
+ finalBody.append(boundaryValue);
+ }else {
+ String bodypart_encoded = encode(bodypart, false, false);
+ finalBody.append("--");
+ finalBody.append(boundaryValue);
+ finalBody.append("\r\n");
+ finalBody.append(bodypart_encoded);
+ finalBody.append("\r\n");
+ }
+ }
+
+ }
+ finalBody.append("--\r\n");
+ body = finalBody.toString();
+
+ content_type = helper.HTTPMessage.createContentTypeHeader(content_type, currentHTTPEncodingObject.outgoing_request_encoding, boundaryValue, currentHTTPEncodingObject.trimSpacesInContentTypeHeaderValues);
+ hasSomethingChanged = true;
+ }
+ }
+ break;
+ case "json":
+ case "xml":
+ body = encode(body, false, false);
+ hasSomethingChanged = true;
+ break;
+ }
+ }
+ }else {
+ content_type = "application/x-www-form-urlencoded";
+ }
+
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ return "";
+ }
+
+ if(hasSomethingChanged) {
+ if(currentHTTPEncodingObject.addACharToEmptyBody && body.length()==0) {
+ body = " ";
+ }
+
+ if(currentHTTPEncodingObject.replaceGETwithPOST) {
+ header = helper.HTTPMessage.replaceHeaderVerb(header, "POST");
+ }
+
+ if(!content_type.contains("charset")) {
+ content_type = helper.HTTPMessage.createContentTypeHeader(content_type, currentHTTPEncodingObject.outgoing_request_encoding, "", currentHTTPEncodingObject.trimSpacesInContentTypeHeaderValues);
+ }
+
+ header = helper.HTTPMessage.replaceHeaderValue(header, "content-length", String.valueOf(body.length()), false);
+ header = helper.HTTPMessage.replaceHeaderValue(header, "content-type", content_type, false);
+ encodedRequest = header+"\r\n\r\n"+body;
+ return encodedRequest;
+ }else {
+ return "";
+ }
+
+ }
+
+ public String encodeHTTPMessage(byte[] request, HTTPEncodingObject selectedHTTPEncodingObject) throws UnsupportedEncodingException {
+ currentHTTPEncodingObject = selectedHTTPEncodingObject;
+ return encodeHTTPMessage(request, currentHTTPEncodingObject.incoming_request_encoding, currentHTTPEncodingObject.outgoing_request_encoding);
+ }
+
+
+}
diff --git a/src/myui/AboutTab.java b/src/myui/AboutTab.java
new file mode 100644
index 0000000..787b86c
--- /dev/null
+++ b/src/myui/AboutTab.java
@@ -0,0 +1,200 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package myui;
+
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+import burp.IBurpExtenderCallbacks;
+
+import java.awt.GridBagLayout;
+import javax.swing.JLabel;
+import java.awt.Desktop;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.swing.JButton;
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+public class AboutTab extends JPanel {
+
+ private final burp.IBurpExtenderCallbacks callbacks;
+ private final PrintWriter stdout;
+ private final PrintWriter stderr;
+
+ /**
+ * Create the panel.
+ */
+ public AboutTab(IBurpExtenderCallbacks callbacks, PrintWriter stdout, PrintWriter stderr) {
+ this.callbacks = callbacks;
+ this.stdout = stdout;
+ this.stderr = stderr;
+
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ gridBagLayout.columnWidths = new int[]{0, 86, 80, 248, 0};
+ gridBagLayout.rowHeights = new int[]{0, 38, 0, 0, 0, 43, 0, 0, 0, 0};
+ gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+ gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+ setLayout(gridBagLayout);
+
+ ClassLoader cldr = this.getClass().getClassLoader();
+ java.net.URL imageURLMain = cldr.getResource("resources/AboutMain.png");
+ ImageIcon imageIconMain = new ImageIcon(imageURLMain);
+ JLabel lblMain = new JLabel("Main"); // to see the label in eclipse design tab!
+ if("running".equals("running")) // to see the image while running it.
+ lblMain = new JLabel(imageIconMain);
+ GridBagConstraints gbc_lblMain = new GridBagConstraints();
+ gbc_lblMain.gridheight = 8;
+ gbc_lblMain.insets = new Insets(0, 0, 0, 5);
+ gbc_lblMain.gridx = 1;
+ gbc_lblMain.gridy = 1;
+ add(lblMain, gbc_lblMain);
+
+ JLabel lblName = new JLabel("Name");
+ GridBagConstraints gbc_lblName = new GridBagConstraints();
+ gbc_lblName.anchor = GridBagConstraints.SOUTHWEST;
+ gbc_lblName.insets = new Insets(0, 0, 5, 5);
+ gbc_lblName.gridx = 2;
+ gbc_lblName.gridy = 1;
+ add(lblName, gbc_lblName);
+
+ JLabel lblDynamicname = new JLabel("dynamic_name");
+ GridBagConstraints gbc_lblDynamicname = new GridBagConstraints();
+ gbc_lblDynamicname.anchor = GridBagConstraints.SOUTHWEST;
+ gbc_lblDynamicname.insets = new Insets(0, 0, 5, 0);
+ gbc_lblDynamicname.gridx = 3;
+ gbc_lblDynamicname.gridy = 1;
+ add(lblDynamicname, gbc_lblDynamicname);
+
+ JLabel lblVersion = new JLabel("Version");
+ GridBagConstraints gbc_lblVersion = new GridBagConstraints();
+ gbc_lblVersion.insets = new Insets(0, 0, 5, 5);
+ gbc_lblVersion.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblVersion.gridx = 2;
+ gbc_lblVersion.gridy = 2;
+ add(lblVersion, gbc_lblVersion);
+
+ JLabel lblDynamicversion = new JLabel("dynamic_version");
+ GridBagConstraints gbc_lblDynamicversion = new GridBagConstraints();
+ gbc_lblDynamicversion.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblDynamicversion.insets = new Insets(0, 0, 5, 0);
+ gbc_lblDynamicversion.gridx = 3;
+ gbc_lblDynamicversion.gridy = 2;
+ add(lblDynamicversion, gbc_lblDynamicversion);
+
+ JLabel lblSource = new JLabel("Source");
+ GridBagConstraints gbc_lblSource = new GridBagConstraints();
+ gbc_lblSource.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblSource.insets = new Insets(0, 0, 5, 5);
+ gbc_lblSource.gridx = 2;
+ gbc_lblSource.gridy = 3;
+ add(lblSource, gbc_lblSource);
+
+ JLabel lblDynamicsource = new JLabel("dynamic_source");
+ GridBagConstraints gbc_lblDynamicsource = new GridBagConstraints();
+ gbc_lblDynamicsource.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblDynamicsource.insets = new Insets(0, 0, 5, 0);
+ gbc_lblDynamicsource.gridx = 3;
+ gbc_lblDynamicsource.gridy = 3;
+ add(lblDynamicsource, gbc_lblDynamicsource);
+
+ JLabel lblAuthor = new JLabel("Author");
+ GridBagConstraints gbc_lblAuthor = new GridBagConstraints();
+ gbc_lblAuthor.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblAuthor.insets = new Insets(0, 0, 5, 5);
+ gbc_lblAuthor.gridx = 2;
+ gbc_lblAuthor.gridy = 4;
+ add(lblAuthor, gbc_lblAuthor);
+
+ JLabel lblDynamicauthor = new JLabel("dynamic_author");
+ GridBagConstraints gbc_lblDynamicauthor = new GridBagConstraints();
+ gbc_lblDynamicauthor.insets = new Insets(0, 0, 5, 0);
+ gbc_lblDynamicauthor.anchor = GridBagConstraints.NORTHWEST;
+ gbc_lblDynamicauthor.gridx = 3;
+ gbc_lblDynamicauthor.gridy = 4;
+ add(lblDynamicauthor, gbc_lblDynamicauthor);
+
+ JLabel label = new JLabel(" ");
+ GridBagConstraints gbc_label = new GridBagConstraints();
+ gbc_label.insets = new Insets(0, 0, 5, 5);
+ gbc_label.gridx = 2;
+ gbc_label.gridy = 5;
+ add(label, gbc_label);
+
+ JButton btnOpenExtensionHome = new JButton("Open extension homepage");
+ btnOpenExtensionHome.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ openWebpage("https://github.com/nccgroup/BurpSuiteHTTPSmuggler");
+ }
+ });
+ GridBagConstraints gbc_btnOpenExtensionHome = new GridBagConstraints();
+ gbc_btnOpenExtensionHome.insets = new Insets(0, 0, 5, 0);
+ gbc_btnOpenExtensionHome.gridwidth = 2;
+ gbc_btnOpenExtensionHome.anchor = GridBagConstraints.NORTHWEST;
+ gbc_btnOpenExtensionHome.gridx = 2;
+ gbc_btnOpenExtensionHome.gridy = 6;
+ add(btnOpenExtensionHome, gbc_btnOpenExtensionHome);
+
+ JButton btnReportAnIssue = new JButton("Report a bug/feature!");
+ btnReportAnIssue.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ openWebpage("https://github.com/nccgroup/BurpSuiteHTTPSmuggler/issues");
+ }
+ });
+ GridBagConstraints gbc_btnReportAnIssue = new GridBagConstraints();
+ gbc_btnReportAnIssue.insets = new Insets(0, 0, 5, 0);
+ gbc_btnReportAnIssue.anchor = GridBagConstraints.WEST;
+ gbc_btnReportAnIssue.gridwidth = 2;
+ gbc_btnReportAnIssue.gridx = 2;
+ gbc_btnReportAnIssue.gridy = 7;
+ add(btnReportAnIssue, gbc_btnReportAnIssue);
+
+ lblDynamicname.setText("Burp Suite HTTP Smuggler");
+ lblDynamicversion.setText(String.valueOf(0.1));
+ lblDynamicsource.setText("https://github.com/nccgroup/BurpSuiteHTTPSmuggler/");
+ lblDynamicauthor.setText("Soroush Dalili from NCC Group");
+
+ }
+
+ private static void openWebpage(URI uri) {
+ Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null;
+ if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) {
+ try {
+ desktop.browse(uri);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private static void openWebpage(String url) {
+ try {
+ openWebpage((new URL(url)).toURI());
+ } catch (URISyntaxException e) {
+ e.printStackTrace();
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+}
diff --git a/src/myui/EditedRequestTab.java b/src/myui/EditedRequestTab.java
new file mode 100644
index 0000000..1e78a78
--- /dev/null
+++ b/src/myui/EditedRequestTab.java
@@ -0,0 +1,106 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package myui;
+
+import java.awt.Component;
+import burp.IBurpExtenderCallbacks;
+import burp.IMessageEditorController;
+import burp.IMessageEditorTab;
+import burp.IMessageEditorTabFactory;
+import burp.ITextEditor;
+
+// based on https://github.com/PortSwigger/example-custom-editor-tab/blob/master/java/BurpExtender.java
+public class EditedRequestTab implements IMessageEditorTabFactory, IMessageEditorTab{
+ private boolean editable;
+ private ITextEditor txtInput;
+ //private byte[] changedMessage;
+ private byte[] originalMessage;
+ private IBurpExtenderCallbacks _callbacks;
+
+ public EditedRequestTab(IBurpExtenderCallbacks callbacks, boolean editable, byte[] changedMessage, byte[] originalMessage)
+ {
+ this._callbacks = callbacks;
+ this.editable = editable;
+ //this.changedMessage = changedMessage;
+ this.originalMessage = originalMessage;
+
+ txtInput = _callbacks.createTextEditor();
+ txtInput.setEditable(editable);
+ txtInput.setText(changedMessage);
+
+ }
+
+ @Override
+ public String getTabCaption() {
+ return "HTTP Smuggler Output";
+ }
+
+ @Override
+ public Component getUiComponent() {
+ return txtInput.getComponent();
+ }
+
+ @Override
+ public boolean isEnabled(byte[] content, boolean isRequest) {
+ if(isRequest)
+ return true;
+ else
+ return false;
+ }
+
+ @Override
+ public void setMessage(byte[] content, boolean isRequest) {
+ if (content == null)
+ {
+ // clear our display
+ txtInput.setText(null);
+ txtInput.setEditable(false);
+ }
+ else
+ {
+ txtInput.setText(content);
+ txtInput.setEditable(editable);
+ }
+
+ // remember the displayed content
+ // currentMessage = content;
+
+ }
+
+ @Override
+ public byte[] getMessage() {
+ return originalMessage;
+ }
+
+ @Override
+ public boolean isModified() {
+ // not needed
+ return txtInput.isTextModified();
+ }
+
+ @Override
+ public byte[] getSelectedData() {
+ // not needed
+ return txtInput.getSelectedText();
+ }
+
+ @Override
+ public IMessageEditorTab createNewInstance(IMessageEditorController controller, boolean editable) {
+ this.editable = editable;
+ return this;
+ }
+
+
+}
diff --git a/src/myui/EncodingTab.java b/src/myui/EncodingTab.java
new file mode 100644
index 0000000..8cb0257
--- /dev/null
+++ b/src/myui/EncodingTab.java
@@ -0,0 +1,682 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package myui;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.io.PrintWriter;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
+import mutation.HTTPEncodingObject;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.border.TitledBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.JTextField;
+
+public class EncodingTab extends JScrollPane {
+ private IBurpExtenderCallbacks _callbacks;;
+ private IExtensionHelpers _helpers;
+ private PrintWriter _stdout;
+ private PrintWriter _stderr;
+
+ private enum policyOptions{
+ aspx("ASPX/IIS"),
+ jsp("JSP/TOMCAT"),
+ py2("Py2/Django"),
+ py3("Py3/Django"),
+ custom("custom");
+ private String value;
+ private policyOptions(String value)
+ {
+ this.value = value;
+ }
+
+ public String toString()
+ {
+ return this.value; //This will return , # or +
+ }
+ }
+ private JComboBox comboBoxPolicy = new JComboBox(new DefaultComboBoxModel(policyOptions.values()));
+ private JTextField delimiter_QS;
+ private JTextField delimiter_QS_param;
+ private JTextField QS_equalSign;
+ private JTextField delimiter_urlencoded_body_param;
+ private JTextField body_param_equalSign;
+ private JTextField outgoing_request_encoding;
+ private JTextField incoming_request_encoding;
+ JCheckBox preventReEncoding = new JCheckBox("Prevent re-encoding");
+
+ JCheckBox encodeMicrosoftURLEncode = new JCheckBox("Encode using MS URLEncode");
+ JCheckBox encodeDespiteErrors = new JCheckBox("Encode despite errors");
+ JCheckBox addACharToEmptyBody = new JCheckBox("Add a character to an empty body");
+ JCheckBox replaceGETwithPOST = new JCheckBox("Replace GET with POST");
+ JCheckBox isEncodable_QS = new JCheckBox("Encode querystring?");
+ JCheckBox isEncodable_body = new JCheckBox("Encode body?");
+ JCheckBox isEncodable_QS_delimiter = new JCheckBox("Encode querystring delimiter?");
+ JCheckBox isEncodable_urlencoded_body_delimiter = new JCheckBox("Encode URL-encoded body delimiter?");
+ JCheckBox isEncodable_QS_equal_sign = new JCheckBox("Encode equal sign in querystring?");
+ JCheckBox isEncodable_urlencoded_body_equal_sign = new JCheckBox("Encode equal sign in URL-encoded body?");
+ JCheckBox isURLEncoded_incoming_QS = new JCheckBox("Is incoming querystring URL-encoded?");
+ JCheckBox isURLEncoded_incoming_body = new JCheckBox("Is incoming body URL-encoded?");
+ JCheckBox isURLEncoded_outgoing_QS = new JCheckBox("Is outgoing querystring URL-encoded?");
+ JCheckBox isURLEncoded_outgoing_body = new JCheckBox("Is outgoing body URL-encoded?");
+ JCheckBox isAllChar_URLEncoded_outgoing_QS = new JCheckBox("URL-encoding all characters in querystring?");
+ JCheckBox isAllChar_URLEncoded_outgoing_body = new JCheckBox("URL-encoding all characters in POST body");
+ JCheckBox trimSpacesInContentTypeHeaderValues = new JCheckBox("Trim spaces from content-type parts");
+ JCheckBox encodeNameValueOnlyMultipart = new JCheckBox("Encode name value only in multipart");
+ JCheckBox use_incoming_charset_for_request_encoding = new JCheckBox("Use incoming charset for encoding");
+
+ /**
+ * Create the panel.
+ */
+ public EncodingTab(IBurpExtenderCallbacks callbacks, PrintWriter stdout, PrintWriter stderr) {
+ _callbacks = callbacks;
+ _helpers = _callbacks.getHelpers();
+ _stdout = stdout;
+ _stderr = stderr;
+
+
+ JPanel panel = new JPanel();
+ setViewportView(panel);
+ GridBagLayout gbl_panel = new GridBagLayout();
+ gbl_panel.columnWidths = new int[]{0, 0, 0, 0, 0};
+ gbl_panel.rowHeights = new int[]{0, 0, 0, 0};
+ gbl_panel.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE};
+ gbl_panel.rowWeights = new double[]{0.0, 1.0, 0.0, Double.MIN_VALUE};
+ panel.setLayout(gbl_panel);
+
+ JLabel lblPolicy = new JLabel("Policy:");
+ GridBagConstraints gbc_lblPolicy = new GridBagConstraints();
+ gbc_lblPolicy.insets = new Insets(0, 0, 5, 5);
+ gbc_lblPolicy.anchor = GridBagConstraints.EAST;
+ gbc_lblPolicy.gridx = 1;
+ gbc_lblPolicy.gridy = 0;
+ panel.add(lblPolicy, gbc_lblPolicy);
+
+ GridBagConstraints gbc_comboBoxPolicy = new GridBagConstraints();
+ gbc_comboBoxPolicy.insets = new Insets(0, 0, 5, 5);
+ gbc_comboBoxPolicy.anchor = GridBagConstraints.WEST;
+ gbc_comboBoxPolicy.gridx = 2;
+ gbc_comboBoxPolicy.gridy = 0;
+ panel.add(comboBoxPolicy, gbc_comboBoxPolicy);
+
+ JPanel panel_1 = new JPanel();
+ panel_1.setBorder(new TitledBorder(null, "Options", TitledBorder.LEFT, TitledBorder.TOP, null, null));
+ GridBagConstraints gbc_panel_1 = new GridBagConstraints();
+ gbc_panel_1.insets = new Insets(0, 0, 5, 5);
+ gbc_panel_1.fill = GridBagConstraints.BOTH;
+ gbc_panel_1.gridx = 2;
+ gbc_panel_1.gridy = 1;
+ panel.add(panel_1, gbc_panel_1);
+ GridBagLayout gbl_panel_1 = new GridBagLayout();
+ gbl_panel_1.columnWidths = new int[]{0, 0, 0, 0};
+ gbl_panel_1.rowHeights = new int[]{35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35};
+ gbl_panel_1.columnWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
+ gbl_panel_1.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+ panel_1.setLayout(gbl_panel_1);
+
+
+ preventReEncoding.setToolTipText("Only encodes when there is no charset or it is one of these: \"UTF-8\", \"UTF-16\", \"UTF-32\", \"ISO-8859-1\"");
+ GridBagConstraints gbc_preventReEncoding = new GridBagConstraints();
+ gbc_preventReEncoding.anchor = GridBagConstraints.WEST;
+ gbc_preventReEncoding.insets = new Insets(0, 0, 5, 5);
+ gbc_preventReEncoding.gridx = 0;
+ gbc_preventReEncoding.gridy = 0;
+ panel_1.add(preventReEncoding, gbc_preventReEncoding);
+
+ JLabel lblQuerystringDelimiter = new JLabel("Querystring url delimiter:");
+ GridBagConstraints gbc_lblQuerystringDelimiter = new GridBagConstraints();
+ gbc_lblQuerystringDelimiter.anchor = GridBagConstraints.EAST;
+ gbc_lblQuerystringDelimiter.insets = new Insets(0, 0, 5, 5);
+ gbc_lblQuerystringDelimiter.gridx = 1;
+ gbc_lblQuerystringDelimiter.gridy = 0;
+ panel_1.add(lblQuerystringDelimiter, gbc_lblQuerystringDelimiter);
+
+ delimiter_QS = new JTextField();
+ delimiter_QS.setText("?");
+ GridBagConstraints gbc_delimiter_QS = new GridBagConstraints();
+ gbc_delimiter_QS.anchor = GridBagConstraints.WEST;
+ gbc_delimiter_QS.insets = new Insets(0, 0, 5, 0);
+ gbc_delimiter_QS.gridx = 2;
+ gbc_delimiter_QS.gridy = 0;
+ panel_1.add(delimiter_QS, gbc_delimiter_QS);
+ delimiter_QS.setColumns(10);
+
+ encodeMicrosoftURLEncode.setToolTipText("to encode utf-8 characters to their %uXXXX format");
+ GridBagConstraints gbc_encodeMicrosoftURLEncode = new GridBagConstraints();
+ gbc_encodeMicrosoftURLEncode.insets = new Insets(0, 0, 5, 5);
+ gbc_encodeMicrosoftURLEncode.anchor = GridBagConstraints.WEST;
+ gbc_encodeMicrosoftURLEncode.gridx = 0;
+ gbc_encodeMicrosoftURLEncode.gridy = 1;
+ panel_1.add(encodeMicrosoftURLEncode, gbc_encodeMicrosoftURLEncode);
+
+ JLabel lblQuerystringParameterDelimiter = new JLabel("Querystring parameter delimiter:");
+ GridBagConstraints gbc_lblQuerystringParameterDelimiter = new GridBagConstraints();
+ gbc_lblQuerystringParameterDelimiter.anchor = GridBagConstraints.EAST;
+ gbc_lblQuerystringParameterDelimiter.insets = new Insets(0, 0, 5, 5);
+ gbc_lblQuerystringParameterDelimiter.gridx = 1;
+ gbc_lblQuerystringParameterDelimiter.gridy = 1;
+ panel_1.add(lblQuerystringParameterDelimiter, gbc_lblQuerystringParameterDelimiter);
+
+ delimiter_QS_param = new JTextField();
+ delimiter_QS_param.setText("&");
+ GridBagConstraints gbc_delimiter_QS_param = new GridBagConstraints();
+ gbc_delimiter_QS_param.anchor = GridBagConstraints.WEST;
+ gbc_delimiter_QS_param.insets = new Insets(0, 0, 5, 0);
+ gbc_delimiter_QS_param.gridx = 2;
+ gbc_delimiter_QS_param.gridy = 1;
+ panel_1.add(delimiter_QS_param, gbc_delimiter_QS_param);
+ delimiter_QS_param.setColumns(10);
+
+ encodeDespiteErrors.setToolTipText("Can be dangerous as it can change all the parameters wrongly. This will be ignored if encodeMicrosoftURLEncode=true");
+ GridBagConstraints gbc_encodeDespiteErrors = new GridBagConstraints();
+ gbc_encodeDespiteErrors.insets = new Insets(0, 0, 5, 5);
+ gbc_encodeDespiteErrors.anchor = GridBagConstraints.WEST;
+ gbc_encodeDespiteErrors.gridx = 0;
+ gbc_encodeDespiteErrors.gridy = 2;
+ panel_1.add(encodeDespiteErrors, gbc_encodeDespiteErrors);
+
+ JLabel lblQuerystringEqualSign = new JLabel("Querystring equal sign:");
+ GridBagConstraints gbc_lblQuerystringEqualSign = new GridBagConstraints();
+ gbc_lblQuerystringEqualSign.anchor = GridBagConstraints.EAST;
+ gbc_lblQuerystringEqualSign.insets = new Insets(0, 0, 5, 5);
+ gbc_lblQuerystringEqualSign.gridx = 1;
+ gbc_lblQuerystringEqualSign.gridy = 2;
+ panel_1.add(lblQuerystringEqualSign, gbc_lblQuerystringEqualSign);
+
+ QS_equalSign = new JTextField();
+ QS_equalSign.setText("=");
+ GridBagConstraints gbc_QS_equalSign = new GridBagConstraints();
+ gbc_QS_equalSign.insets = new Insets(0, 0, 5, 0);
+ gbc_QS_equalSign.fill = GridBagConstraints.HORIZONTAL;
+ gbc_QS_equalSign.gridx = 2;
+ gbc_QS_equalSign.gridy = 2;
+ panel_1.add(QS_equalSign, gbc_QS_equalSign);
+ QS_equalSign.setColumns(10);
+
+ GridBagConstraints gbc_addACharToEmptyBody = new GridBagConstraints();
+ gbc_addACharToEmptyBody.anchor = GridBagConstraints.WEST;
+ gbc_addACharToEmptyBody.insets = new Insets(0, 0, 5, 5);
+ gbc_addACharToEmptyBody.gridx = 0;
+ gbc_addACharToEmptyBody.gridy = 3;
+ panel_1.add(addACharToEmptyBody, gbc_addACharToEmptyBody);
+
+ JLabel lblUrlencodedBodyParameter = new JLabel("URL-encoded body parameter delimiter:");
+ GridBagConstraints gbc_lblUrlencodedBodyParameter = new GridBagConstraints();
+ gbc_lblUrlencodedBodyParameter.anchor = GridBagConstraints.EAST;
+ gbc_lblUrlencodedBodyParameter.insets = new Insets(0, 0, 5, 5);
+ gbc_lblUrlencodedBodyParameter.gridx = 1;
+ gbc_lblUrlencodedBodyParameter.gridy = 3;
+ panel_1.add(lblUrlencodedBodyParameter, gbc_lblUrlencodedBodyParameter);
+
+ delimiter_urlencoded_body_param = new JTextField();
+ delimiter_urlencoded_body_param.setText("&");
+ GridBagConstraints gbc_delimiter_urlencoded_body_param = new GridBagConstraints();
+ gbc_delimiter_urlencoded_body_param.insets = new Insets(0, 0, 5, 0);
+ gbc_delimiter_urlencoded_body_param.fill = GridBagConstraints.HORIZONTAL;
+ gbc_delimiter_urlencoded_body_param.gridx = 2;
+ gbc_delimiter_urlencoded_body_param.gridy = 3;
+ panel_1.add(delimiter_urlencoded_body_param, gbc_delimiter_urlencoded_body_param);
+ delimiter_urlencoded_body_param.setColumns(10);
+
+ GridBagConstraints gbc_replaceGETwithPOST = new GridBagConstraints();
+ gbc_replaceGETwithPOST.insets = new Insets(0, 0, 5, 5);
+ gbc_replaceGETwithPOST.anchor = GridBagConstraints.WEST;
+ gbc_replaceGETwithPOST.gridx = 0;
+ gbc_replaceGETwithPOST.gridy = 4;
+ panel_1.add(replaceGETwithPOST, gbc_replaceGETwithPOST);
+
+ JLabel lblBodyParameterEqual = new JLabel("Body parameter equal sign:");
+ GridBagConstraints gbc_lblBodyParameterEqual = new GridBagConstraints();
+ gbc_lblBodyParameterEqual.anchor = GridBagConstraints.EAST;
+ gbc_lblBodyParameterEqual.insets = new Insets(0, 0, 5, 5);
+ gbc_lblBodyParameterEqual.gridx = 1;
+ gbc_lblBodyParameterEqual.gridy = 4;
+ panel_1.add(lblBodyParameterEqual, gbc_lblBodyParameterEqual);
+
+ body_param_equalSign = new JTextField();
+ body_param_equalSign.setText("=");
+ GridBagConstraints gbc_body_param_equalSign = new GridBagConstraints();
+ gbc_body_param_equalSign.insets = new Insets(0, 0, 5, 0);
+ gbc_body_param_equalSign.fill = GridBagConstraints.HORIZONTAL;
+ gbc_body_param_equalSign.gridx = 2;
+ gbc_body_param_equalSign.gridy = 4;
+ panel_1.add(body_param_equalSign, gbc_body_param_equalSign);
+ body_param_equalSign.setColumns(10);
+
+ GridBagConstraints gbc_isEncodable_QS = new GridBagConstraints();
+ gbc_isEncodable_QS.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_QS.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_QS.gridx = 0;
+ gbc_isEncodable_QS.gridy = 5;
+ panel_1.add(isEncodable_QS, gbc_isEncodable_QS);
+
+ JLabel lblOutgoingRequestEncoding = new JLabel("Outgoing request encoding:");
+ GridBagConstraints gbc_lblOutgoingRequestEncoding = new GridBagConstraints();
+ gbc_lblOutgoingRequestEncoding.anchor = GridBagConstraints.EAST;
+ gbc_lblOutgoingRequestEncoding.insets = new Insets(0, 0, 5, 5);
+ gbc_lblOutgoingRequestEncoding.gridx = 1;
+ gbc_lblOutgoingRequestEncoding.gridy = 5;
+ panel_1.add(lblOutgoingRequestEncoding, gbc_lblOutgoingRequestEncoding);
+
+ outgoing_request_encoding = new JTextField();
+ outgoing_request_encoding.setText("ibm500");
+ GridBagConstraints gbc_outgoing_request_encoding = new GridBagConstraints();
+ gbc_outgoing_request_encoding.insets = new Insets(0, 0, 5, 0);
+ gbc_outgoing_request_encoding.fill = GridBagConstraints.HORIZONTAL;
+ gbc_outgoing_request_encoding.gridx = 2;
+ gbc_outgoing_request_encoding.gridy = 5;
+ panel_1.add(outgoing_request_encoding, gbc_outgoing_request_encoding);
+ outgoing_request_encoding.setColumns(10);
+
+ GridBagConstraints gbc_isEncodable_body = new GridBagConstraints();
+ gbc_isEncodable_body.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_body.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_body.gridx = 0;
+ gbc_isEncodable_body.gridy = 6;
+ panel_1.add(isEncodable_body, gbc_isEncodable_body);
+
+ JLabel lblDefaultIncomingRequest = new JLabel("Default incoming request encoding:");
+ GridBagConstraints gbc_lblDefaultIncomingRequest = new GridBagConstraints();
+ gbc_lblDefaultIncomingRequest.anchor = GridBagConstraints.EAST;
+ gbc_lblDefaultIncomingRequest.insets = new Insets(0, 0, 5, 5);
+ gbc_lblDefaultIncomingRequest.gridx = 1;
+ gbc_lblDefaultIncomingRequest.gridy = 6;
+ panel_1.add(lblDefaultIncomingRequest, gbc_lblDefaultIncomingRequest);
+
+ incoming_request_encoding = new JTextField();
+ incoming_request_encoding.setText("utf-8");
+ GridBagConstraints gbc_incoming_request_encoding = new GridBagConstraints();
+ gbc_incoming_request_encoding.insets = new Insets(0, 0, 5, 0);
+ gbc_incoming_request_encoding.fill = GridBagConstraints.HORIZONTAL;
+ gbc_incoming_request_encoding.gridx = 2;
+ gbc_incoming_request_encoding.gridy = 6;
+ panel_1.add(incoming_request_encoding, gbc_incoming_request_encoding);
+ incoming_request_encoding.setColumns(10);
+
+ GridBagConstraints gbc_isEncodable_QS_delimiter = new GridBagConstraints();
+ gbc_isEncodable_QS_delimiter.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_QS_delimiter.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_QS_delimiter.gridx = 0;
+ gbc_isEncodable_QS_delimiter.gridy = 7;
+ panel_1.add(isEncodable_QS_delimiter, gbc_isEncodable_QS_delimiter);
+
+ GridBagConstraints gbc_isEncodable_urlencoded_body_delimiter = new GridBagConstraints();
+ gbc_isEncodable_urlencoded_body_delimiter.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_urlencoded_body_delimiter.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_urlencoded_body_delimiter.gridx = 0;
+ gbc_isEncodable_urlencoded_body_delimiter.gridy = 8;
+ panel_1.add(isEncodable_urlencoded_body_delimiter, gbc_isEncodable_urlencoded_body_delimiter);
+
+ GridBagConstraints gbc_isEncodable_QS_equal_sign = new GridBagConstraints();
+ gbc_isEncodable_QS_equal_sign.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_QS_equal_sign.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_QS_equal_sign.gridx = 0;
+ gbc_isEncodable_QS_equal_sign.gridy = 9;
+ panel_1.add(isEncodable_QS_equal_sign, gbc_isEncodable_QS_equal_sign);
+
+ GridBagConstraints gbc_isEncodable_urlencoded_body_equal_sign = new GridBagConstraints();
+ gbc_isEncodable_urlencoded_body_equal_sign.anchor = GridBagConstraints.WEST;
+ gbc_isEncodable_urlencoded_body_equal_sign.insets = new Insets(0, 0, 5, 5);
+ gbc_isEncodable_urlencoded_body_equal_sign.gridx = 0;
+ gbc_isEncodable_urlencoded_body_equal_sign.gridy = 10;
+ panel_1.add(isEncodable_urlencoded_body_equal_sign, gbc_isEncodable_urlencoded_body_equal_sign);
+
+ GridBagConstraints gbc_isURLEncoded_incoming_QS = new GridBagConstraints();
+ gbc_isURLEncoded_incoming_QS.anchor = GridBagConstraints.WEST;
+ gbc_isURLEncoded_incoming_QS.insets = new Insets(0, 0, 5, 5);
+ gbc_isURLEncoded_incoming_QS.gridx = 0;
+ gbc_isURLEncoded_incoming_QS.gridy = 11;
+ panel_1.add(isURLEncoded_incoming_QS, gbc_isURLEncoded_incoming_QS);
+
+ isURLEncoded_incoming_body.setToolTipText("this is not active when it is a multipart message");
+ GridBagConstraints gbc_isURLEncoded_incoming_body = new GridBagConstraints();
+ gbc_isURLEncoded_incoming_body.anchor = GridBagConstraints.WEST;
+ gbc_isURLEncoded_incoming_body.insets = new Insets(0, 0, 5, 5);
+ gbc_isURLEncoded_incoming_body.gridx = 0;
+ gbc_isURLEncoded_incoming_body.gridy = 12;
+ panel_1.add(isURLEncoded_incoming_body, gbc_isURLEncoded_incoming_body);
+
+ GridBagConstraints gbc_isURLEncoded_outgoing_QS = new GridBagConstraints();
+ gbc_isURLEncoded_outgoing_QS.anchor = GridBagConstraints.WEST;
+ gbc_isURLEncoded_outgoing_QS.insets = new Insets(0, 0, 5, 5);
+ gbc_isURLEncoded_outgoing_QS.gridx = 0;
+ gbc_isURLEncoded_outgoing_QS.gridy = 13;
+ panel_1.add(isURLEncoded_outgoing_QS, gbc_isURLEncoded_outgoing_QS);
+
+ isURLEncoded_outgoing_body.setToolTipText("this is not active when it is a multipart message");
+ GridBagConstraints gbc_isURLEncoded_outgoing_body = new GridBagConstraints();
+ gbc_isURLEncoded_outgoing_body.anchor = GridBagConstraints.WEST;
+ gbc_isURLEncoded_outgoing_body.insets = new Insets(0, 0, 5, 5);
+ gbc_isURLEncoded_outgoing_body.gridx = 0;
+ gbc_isURLEncoded_outgoing_body.gridy = 14;
+ panel_1.add(isURLEncoded_outgoing_body, gbc_isURLEncoded_outgoing_body);
+
+ isAllChar_URLEncoded_outgoing_QS.setToolTipText("only active when isURLEncoded_outgoing_QS=true to encode all characters rather than just key characters");
+ GridBagConstraints gbc_isAllChar_URLEncoded_outgoing_QS = new GridBagConstraints();
+ gbc_isAllChar_URLEncoded_outgoing_QS.anchor = GridBagConstraints.WEST;
+ gbc_isAllChar_URLEncoded_outgoing_QS.insets = new Insets(0, 0, 5, 5);
+ gbc_isAllChar_URLEncoded_outgoing_QS.gridx = 0;
+ gbc_isAllChar_URLEncoded_outgoing_QS.gridy = 15;
+ panel_1.add(isAllChar_URLEncoded_outgoing_QS, gbc_isAllChar_URLEncoded_outgoing_QS);
+
+ isAllChar_URLEncoded_outgoing_body.setToolTipText("only active when isURLEncoded_outgoing_body=true to encode all characters rather than just key characters");
+ GridBagConstraints gbc_isAllChar_URLEncoded_outgoing_body = new GridBagConstraints();
+ gbc_isAllChar_URLEncoded_outgoing_body.anchor = GridBagConstraints.WEST;
+ gbc_isAllChar_URLEncoded_outgoing_body.insets = new Insets(0, 0, 5, 5);
+ gbc_isAllChar_URLEncoded_outgoing_body.gridx = 0;
+ gbc_isAllChar_URLEncoded_outgoing_body.gridy = 16;
+ panel_1.add(isAllChar_URLEncoded_outgoing_body, gbc_isAllChar_URLEncoded_outgoing_body);
+
+ GridBagConstraints gbc_trimSpacesInContentTypeHeaderValues = new GridBagConstraints();
+ gbc_trimSpacesInContentTypeHeaderValues.anchor = GridBagConstraints.WEST;
+ gbc_trimSpacesInContentTypeHeaderValues.insets = new Insets(0, 0, 5, 5);
+ gbc_trimSpacesInContentTypeHeaderValues.gridx = 0;
+ gbc_trimSpacesInContentTypeHeaderValues.gridy = 17;
+ panel_1.add(trimSpacesInContentTypeHeaderValues, gbc_trimSpacesInContentTypeHeaderValues);
+
+ encodeNameValueOnlyMultipart.setToolTipText("python django needs this, IIS does not!");
+ GridBagConstraints gbc_encodeNameValueOnlyMultipart = new GridBagConstraints();
+ gbc_encodeNameValueOnlyMultipart.anchor = GridBagConstraints.WEST;
+ gbc_encodeNameValueOnlyMultipart.insets = new Insets(0, 0, 5, 5);
+ gbc_encodeNameValueOnlyMultipart.gridx = 0;
+ gbc_encodeNameValueOnlyMultipart.gridy = 18;
+ panel_1.add(encodeNameValueOnlyMultipart, gbc_encodeNameValueOnlyMultipart);
+
+ GridBagConstraints gbc_use_incoming_charset_for_request_encoding = new GridBagConstraints();
+ gbc_use_incoming_charset_for_request_encoding.anchor = GridBagConstraints.WEST;
+ gbc_use_incoming_charset_for_request_encoding.insets = new Insets(0, 0, 0, 5);
+ gbc_use_incoming_charset_for_request_encoding.gridx = 0;
+ gbc_use_incoming_charset_for_request_encoding.gridy = 19;
+ panel_1.add(use_incoming_charset_for_request_encoding, gbc_use_incoming_charset_for_request_encoding);
+
+ init();
+ }
+ private void init(){
+ //resetSettings();
+ loadSettings();
+ updateUIState();
+ setActions();
+ saveSettings();
+ }
+
+ private void updateUIState() {
+
+ Object policy = comboBoxPolicy.getSelectedItem();
+
+ if(!policy.equals(policyOptions.custom)) {
+ HTTPEncodingObject newHTTPEncodingObject = new HTTPEncodingObject(policy.toString());
+ preventReEncoding.setSelected(newHTTPEncodingObject.isPreventReEncoding());
+ encodeMicrosoftURLEncode.setSelected(newHTTPEncodingObject.isEncodeMicrosoftURLEncode());
+ encodeDespiteErrors.setSelected(newHTTPEncodingObject.isEncodeDespiteErrors());
+ addACharToEmptyBody.setSelected(newHTTPEncodingObject.isAddACharToEmptyBody());
+ replaceGETwithPOST.setSelected(newHTTPEncodingObject.isReplaceGETwithPOST());
+ isEncodable_QS.setSelected(newHTTPEncodingObject.isEncodable_QS());
+ isEncodable_body.setSelected(newHTTPEncodingObject.isEncodable_body());
+ isEncodable_QS_delimiter.setSelected(newHTTPEncodingObject.isEncodable_QS_delimiter());
+ isEncodable_urlencoded_body_delimiter.setSelected(newHTTPEncodingObject.isEncodable_urlencoded_body_delimiter());
+ isEncodable_QS_equal_sign.setSelected(newHTTPEncodingObject.isEncodable_QS_equal_sign());
+ isEncodable_urlencoded_body_equal_sign.setSelected(newHTTPEncodingObject.isEncodable_urlencoded_body_equal_sign());
+ isURLEncoded_incoming_QS.setSelected(newHTTPEncodingObject.isURLEncoded_incoming_QS());
+ isURLEncoded_incoming_body.setSelected(newHTTPEncodingObject.isURLEncoded_incoming_body());
+ isURLEncoded_outgoing_QS.setSelected(newHTTPEncodingObject.isURLEncoded_outgoing_QS());
+ isURLEncoded_outgoing_body.setSelected(newHTTPEncodingObject.isURLEncoded_outgoing_body());
+ isAllChar_URLEncoded_outgoing_QS.setSelected(newHTTPEncodingObject.isAllChar_URLEncoded_outgoing_QS());
+ isAllChar_URLEncoded_outgoing_body.setSelected(newHTTPEncodingObject.isAllChar_URLEncoded_outgoing_body());
+ trimSpacesInContentTypeHeaderValues.setSelected(newHTTPEncodingObject.isTrimSpacesInContentTypeHeaderValues());
+ encodeNameValueOnlyMultipart.setSelected(newHTTPEncodingObject.isEncodeNameValueOnlyMultipart());
+ use_incoming_charset_for_request_encoding.setSelected(newHTTPEncodingObject.isUse_incoming_charset_for_request_encoding());
+
+ delimiter_QS.setText(newHTTPEncodingObject.getDelimiter_QS());
+ delimiter_QS_param.setText(newHTTPEncodingObject.getDelimiter_QS_param());
+ QS_equalSign.setText(newHTTPEncodingObject.getQS_equalSign());
+ delimiter_urlencoded_body_param.setText(newHTTPEncodingObject.getDelimiter_urlencoded_body_param());
+ body_param_equalSign.setText(newHTTPEncodingObject.getBody_param_equalSign());
+ outgoing_request_encoding.setText(newHTTPEncodingObject.getOutgoing_request_encoding());
+ incoming_request_encoding.setText(newHTTPEncodingObject.getIncoming_request_encoding());
+
+ comboBoxPolicy.setSelectedItem(policy);
+ }
+
+
+ }
+
+
+ private void setActions() {
+ setActionsJComboBoxHelper(comboBoxPolicy);
+
+ setActionsJCheckBoxHelper(preventReEncoding);
+ setActionsJCheckBoxHelper(encodeMicrosoftURLEncode);
+ setActionsJCheckBoxHelper(encodeDespiteErrors);
+ setActionsJCheckBoxHelper(addACharToEmptyBody);
+ setActionsJCheckBoxHelper(replaceGETwithPOST);
+ setActionsJCheckBoxHelper(isEncodable_QS);
+ setActionsJCheckBoxHelper(isEncodable_body);
+ setActionsJCheckBoxHelper(isEncodable_QS_delimiter);
+ setActionsJCheckBoxHelper(isEncodable_urlencoded_body_delimiter);
+ setActionsJCheckBoxHelper(isEncodable_QS_equal_sign);
+ setActionsJCheckBoxHelper(isEncodable_urlencoded_body_equal_sign);
+ setActionsJCheckBoxHelper(isURLEncoded_incoming_QS);
+ setActionsJCheckBoxHelper(isURLEncoded_incoming_body);
+ setActionsJCheckBoxHelper(isURLEncoded_outgoing_QS);
+ setActionsJCheckBoxHelper(isURLEncoded_outgoing_body);
+ setActionsJCheckBoxHelper(isAllChar_URLEncoded_outgoing_QS);
+ setActionsJCheckBoxHelper(isAllChar_URLEncoded_outgoing_body);
+ setActionsJCheckBoxHelper(trimSpacesInContentTypeHeaderValues);
+ setActionsJCheckBoxHelper(encodeNameValueOnlyMultipart);
+ setActionsJCheckBoxHelper(use_incoming_charset_for_request_encoding);
+
+ setActionsJTextFieldHelper(delimiter_QS);
+ setActionsJTextFieldHelper(delimiter_QS_param);
+ setActionsJTextFieldHelper(QS_equalSign);
+ setActionsJTextFieldHelper(delimiter_urlencoded_body_param);
+ setActionsJTextFieldHelper(body_param_equalSign);
+ setActionsJTextFieldHelper(outgoing_request_encoding);
+ setActionsJTextFieldHelper(incoming_request_encoding);
+
+ }
+
+ private void setActionsJCheckBoxHelper(JCheckBox checkbox) {
+ checkbox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ comboBoxPolicy.setSelectedItem(policyOptions.custom);
+ saveSettings();
+ }
+ });
+ }
+
+ private void setActionsJComboBoxHelper(JComboBox combobox) {
+ combobox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ updateUIState();
+ saveSettings();
+ }
+ });
+ }
+
+ private void setActionsJTextFieldHelper(JTextField textfield) {
+ textfield.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent arg0) {
+ comboBoxPolicy.setSelectedItem(policyOptions.custom);
+ saveSettings();
+ }
+ @Override
+ public void insertUpdate(DocumentEvent arg0) {
+ comboBoxPolicy.setSelectedItem(policyOptions.custom);
+ saveSettings();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent arg0) {
+ comboBoxPolicy.setSelectedItem(policyOptions.custom);
+ saveSettings();
+ }
+ });
+ }
+
+ private void loadSettings() {
+ setValueFromExtensionSettings(comboBoxPolicy,"comboBoxPolicy",0);
+ setValueFromExtensionSettings(preventReEncoding,"preventReEncoding",true);
+ setValueFromExtensionSettings(encodeMicrosoftURLEncode,"encodeMicrosoftURLEncode",false);
+ setValueFromExtensionSettings(encodeDespiteErrors,"encodeDespiteErrors",false);
+ setValueFromExtensionSettings(addACharToEmptyBody,"addACharToEmptyBody",true);
+ setValueFromExtensionSettings(replaceGETwithPOST,"replaceGETwithPOST",false);
+ setValueFromExtensionSettings(isEncodable_QS,"isEncodable_QS",true);
+ setValueFromExtensionSettings(isEncodable_body,"isEncodable_body",true);
+ setValueFromExtensionSettings(isEncodable_QS_delimiter,"isEncodable_QS_delimiter",false);
+ setValueFromExtensionSettings(isEncodable_urlencoded_body_delimiter,"isEncodable_urlencoded_body_delimiter",false);
+ setValueFromExtensionSettings(isEncodable_QS_equal_sign,"isEncodable_QS_equal_sign",false);
+ setValueFromExtensionSettings(isEncodable_urlencoded_body_equal_sign,"isEncodable_urlencoded_body_equal_sign",false);
+ setValueFromExtensionSettings(isURLEncoded_incoming_QS,"isURLEncoded_incoming_QS",true);
+ setValueFromExtensionSettings(isURLEncoded_incoming_body,"isURLEncoded_incoming_body",true);
+ setValueFromExtensionSettings(isURLEncoded_outgoing_QS,"isURLEncoded_outgoing_QS",true);
+ setValueFromExtensionSettings(isURLEncoded_outgoing_body,"isURLEncoded_outgoing_body",true);
+ setValueFromExtensionSettings(isAllChar_URLEncoded_outgoing_QS,"isAllChar_URLEncoded_outgoing_QS",true);
+ setValueFromExtensionSettings(isAllChar_URLEncoded_outgoing_body,"isAllChar_URLEncoded_outgoing_body",true);
+ setValueFromExtensionSettings(trimSpacesInContentTypeHeaderValues,"trimSpacesInContentTypeHeaderValues",true);
+ setValueFromExtensionSettings(encodeNameValueOnlyMultipart,"encodeNameValueOnlyMultipart",false);
+ setValueFromExtensionSettings(use_incoming_charset_for_request_encoding,"use_incoming_charset_for_request_encoding",true);
+ setValueFromExtensionSettings(delimiter_QS,"delimiter_QS","?");
+ setValueFromExtensionSettings(delimiter_QS_param,"delimiter_QS_param","&");
+ setValueFromExtensionSettings(QS_equalSign,"QS_equalSign","=");
+ setValueFromExtensionSettings(delimiter_urlencoded_body_param,"delimiter_urlencoded_body_param","&");
+ setValueFromExtensionSettings(body_param_equalSign,"body_param_equalSign","=");
+ setValueFromExtensionSettings(outgoing_request_encoding,"outgoing_request_encoding","ibm500");
+ setValueFromExtensionSettings(incoming_request_encoding,"incoming_request_encoding","utf-8");
+ }
+
+ private void saveSettings() {
+ saveExtensionSettingHelper("comboBoxPolicy", comboBoxPolicy.getSelectedIndex());
+ saveExtensionSettingHelper("preventReEncoding", preventReEncoding.isSelected());
+ saveExtensionSettingHelper("encodeMicrosoftURLEncode", encodeMicrosoftURLEncode.isSelected());
+ saveExtensionSettingHelper("encodeDespiteErrors", encodeDespiteErrors.isSelected());
+ saveExtensionSettingHelper("addACharToEmptyBody", addACharToEmptyBody.isSelected());
+ saveExtensionSettingHelper("replaceGETwithPOST", replaceGETwithPOST.isSelected());
+ saveExtensionSettingHelper("isEncodable_QS", isEncodable_QS.isSelected());
+ saveExtensionSettingHelper("isEncodable_body", isEncodable_body.isSelected());
+ saveExtensionSettingHelper("isEncodable_QS_delimiter", isEncodable_QS_delimiter.isSelected());
+ saveExtensionSettingHelper("isEncodable_urlencoded_body_delimiter", isEncodable_urlencoded_body_delimiter.isSelected());
+ saveExtensionSettingHelper("isEncodable_QS_equal_sign", isEncodable_QS_equal_sign.isSelected());
+ saveExtensionSettingHelper("isEncodable_urlencoded_body_equal_sign", isEncodable_urlencoded_body_equal_sign.isSelected());
+ saveExtensionSettingHelper("delimiter_QS", delimiter_QS.getText());
+ saveExtensionSettingHelper("delimiter_QS_param", delimiter_QS_param.getText());
+ saveExtensionSettingHelper("QS_equalSign", QS_equalSign.getText());
+ saveExtensionSettingHelper("delimiter_urlencoded_body_param", delimiter_urlencoded_body_param.getText());
+ saveExtensionSettingHelper("body_param_equalSign", body_param_equalSign.getText());
+ saveExtensionSettingHelper("isURLEncoded_incoming_QS", isURLEncoded_incoming_QS.isSelected());
+ saveExtensionSettingHelper("isURLEncoded_incoming_body", isURLEncoded_incoming_body.isSelected());
+ saveExtensionSettingHelper("isURLEncoded_outgoing_QS", isURLEncoded_outgoing_QS.isSelected());
+ saveExtensionSettingHelper("isURLEncoded_outgoing_body", isURLEncoded_outgoing_body.isSelected());
+ saveExtensionSettingHelper("isAllChar_URLEncoded_outgoing_QS", isAllChar_URLEncoded_outgoing_QS.isSelected());
+ saveExtensionSettingHelper("isAllChar_URLEncoded_outgoing_body", isAllChar_URLEncoded_outgoing_body.isSelected());
+ saveExtensionSettingHelper("trimSpacesInContentTypeHeaderValues", trimSpacesInContentTypeHeaderValues.isSelected());
+ saveExtensionSettingHelper("encodeNameValueOnlyMultipart", encodeNameValueOnlyMultipart.isSelected());
+ saveExtensionSettingHelper("outgoing_request_encoding", outgoing_request_encoding.getText());
+ saveExtensionSettingHelper("use_incoming_charset_for_request_encoding", use_incoming_charset_for_request_encoding.isSelected());
+ saveExtensionSettingHelper("incoming_request_encoding", incoming_request_encoding.getText());
+ }
+
+ private void resetSettings() {
+ comboBoxPolicy.setSelectedIndex(0);
+ updateUIState();
+ saveSettings();
+ }
+
+ private void saveExtensionSettingHelper(String name, Object value) {
+ try {
+ _callbacks.saveExtensionSetting(name, String.valueOf(value));
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ }
+ }
+
+ private Object loadExtensionSettingHelper(String name, String type, Object defaultValue) {
+ Object value = null;
+ try {
+ String temp_value = _callbacks.loadExtensionSetting(name);
+ if(temp_value!=null && !temp_value.equals("")) {
+ switch(type.toLowerCase()){
+ case "int":
+ case "integer":
+ value = Integer.valueOf(temp_value);
+ break;
+ case "bool":
+ case "boolean":
+ value = Boolean.valueOf(temp_value);
+ break;
+ default:
+ value = temp_value;
+ break;
+ }
+ }
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ }
+
+ if(value==null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+
+
+ private void setValueFromExtensionSettings(JTextField jTextField, String name, Object defaultValue) {
+ String value = _callbacks.loadExtensionSetting(name);
+ if(value!=null && !value.equals("") && !value.equals(jTextField.getText())) {
+ jTextField.setText(value);
+ }else{
+ jTextField.setText((String) defaultValue);
+ }
+ }
+
+ private void setValueFromExtensionSettings(JComboBox jComboBox, String name, Object defaultValue) {
+ String value = _callbacks.loadExtensionSetting(name);
+ if(value!=null && !value.equals("")) {
+ int temp_value = Integer.valueOf(value);
+ if(temp_value!=jComboBox.getSelectedIndex())
+ jComboBox.setSelectedIndex(temp_value);
+ }else {
+ jComboBox.setSelectedIndex((int) defaultValue);
+ }
+ }
+
+ private void setValueFromExtensionSettings(JCheckBox jCheckBox, String name, Object defaultValue) {
+ String value = _callbacks.loadExtensionSetting(name);
+ if(value!=null && !value.equals("")) {
+ boolean temp_value = Boolean.valueOf(value);
+ if(temp_value!=jCheckBox.isSelected())
+ jCheckBox.setSelected(temp_value);
+ }else {
+ jCheckBox.setSelected((boolean) defaultValue);
+ }
+ }
+
+}
diff --git a/src/myui/ScopeTab.java b/src/myui/ScopeTab.java
new file mode 100644
index 0000000..867b15d
--- /dev/null
+++ b/src/myui/ScopeTab.java
@@ -0,0 +1,442 @@
+/*
+ * Burp Suite HTTP Smuggler
+ *
+ * Released as open source by NCC Group - https://www.nccgroup.trust/
+ *
+ * Developed by:
+ * Soroush Dalili (@irsdl)
+ *
+ * Project link: https://github.com/nccgroup/BurpSuiteHTTPSmuggler/
+ *
+ * Released under AGPL v3.0 see LICENSE for more information
+ *
+ * */
+
+package myui;
+
+/*
+ * TODO: implement OR + AND-NOT + OR-NOT
+ * */
+import javax.swing.JPanel;
+import java.awt.GridBagLayout;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.PrintWriter;
+import javax.swing.JLabel;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import burp.IBurpExtenderCallbacks;
+import burp.IExtensionHelpers;
+
+public class ScopeTab extends JPanel {
+ private IBurpExtenderCallbacks _callbacks;;
+ private IExtensionHelpers _helpers;
+ private PrintWriter _stdout;
+ private PrintWriter _stderr;
+
+ /**
+ * Create the panel.
+ */
+
+ public enum scopeOptions1{
+ AND,
+ OR,
+ DISABLED
+ }
+
+ public enum scopeOptions2{
+ ENABLED,
+ DISABLED
+ }
+
+ private JComboBox targetScopeOption;
+ private JComboBox pathRegExOption;
+ private JTextField pathRegEx;
+ private JComboBox headerRegExOption;
+ private JTextField headerRegEx;
+ private JCheckBox chckbxAllTools;
+ private JCheckBox chckbxProxy;
+ private JCheckBox chckbxScanner;
+ private JCheckBox chckbxIntruder;
+ private JCheckBox chckbxRepeator;
+ private JCheckBox chckbxExtender;
+ private JCheckBox chckbxTarget;
+ private JCheckBox chckbxSequencer;
+ private JCheckBox chckbxSpider;
+
+ public ScopeTab(IBurpExtenderCallbacks callbacks, PrintWriter stdout, PrintWriter stderr) {
+ _callbacks = callbacks;
+ _helpers = _callbacks.getHelpers();
+ _stdout = stdout;
+ _stderr = stderr;
+
+ GridBagLayout gridBagLayout = new GridBagLayout();
+ gridBagLayout.columnWidths = new int[]{30, 0, 30, 101, 221, 0, 0, 0};
+ gridBagLayout.rowHeights = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+ gridBagLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
+ setLayout(gridBagLayout);
+
+
+ JLabel lblIn = new JLabel("In Burp Target scope?");
+ GridBagConstraints gbc_lblIn = new GridBagConstraints();
+ gbc_lblIn.anchor = GridBagConstraints.EAST;
+ gbc_lblIn.insets = new Insets(0, 0, 5, 5);
+ gbc_lblIn.gridx = 2;
+ gbc_lblIn.gridy = 2;
+ add(lblIn, gbc_lblIn);
+
+ targetScopeOption = new JComboBox();
+ targetScopeOption.setModel(new DefaultComboBoxModel(scopeOptions2.values()));
+ GridBagConstraints gbc_targetScopeOption = new GridBagConstraints();
+ gbc_targetScopeOption.anchor = GridBagConstraints.WEST;
+ gbc_targetScopeOption.insets = new Insets(0, 0, 5, 5);
+ gbc_targetScopeOption.gridx = 3;
+ gbc_targetScopeOption.gridy = 2;
+ add(targetScopeOption, gbc_targetScopeOption);
+
+ JLabel lblPathRegex = new JLabel("Path/URL RegEx:");
+ GridBagConstraints gbc_lblPathRegex = new GridBagConstraints();
+ gbc_lblPathRegex.anchor = GridBagConstraints.EAST;
+ gbc_lblPathRegex.insets = new Insets(0, 0, 5, 5);
+ gbc_lblPathRegex.gridx = 2;
+ gbc_lblPathRegex.gridy = 3;
+ add(lblPathRegex, gbc_lblPathRegex);
+
+ pathRegExOption = new JComboBox();
+ pathRegExOption.setModel(new DefaultComboBoxModel(scopeOptions2.values()));
+ GridBagConstraints gbc_pathRegexOption = new GridBagConstraints();
+ gbc_pathRegexOption.anchor = GridBagConstraints.WEST;
+ gbc_pathRegexOption.insets = new Insets(0, 0, 5, 5);
+ gbc_pathRegexOption.gridx = 3;
+ gbc_pathRegexOption.gridy = 3;
+ add(pathRegExOption, gbc_pathRegexOption);
+
+
+ pathRegEx = new JTextField();
+ GridBagConstraints gbc_pathRegEx = new GridBagConstraints();
+ gbc_pathRegEx.insets = new Insets(0, 0, 5, 5);
+ gbc_pathRegEx.fill = GridBagConstraints.HORIZONTAL;
+ gbc_pathRegEx.gridx = 4;
+ gbc_pathRegEx.gridy = 3;
+ add(pathRegEx, gbc_pathRegEx);
+ pathRegEx.setColumns(10);
+
+ JLabel lblHeaderRegex = new JLabel("Headers RegEx:");
+ GridBagConstraints gbc_lblHeaderRegex = new GridBagConstraints();
+ gbc_lblHeaderRegex.anchor = GridBagConstraints.EAST;
+ gbc_lblHeaderRegex.insets = new Insets(0, 0, 5, 5);
+ gbc_lblHeaderRegex.gridx = 2;
+ gbc_lblHeaderRegex.gridy = 4;
+ add(lblHeaderRegex, gbc_lblHeaderRegex);
+
+ headerRegExOption = new JComboBox();
+ headerRegExOption.setModel(new DefaultComboBoxModel(scopeOptions2.values()));
+ GridBagConstraints gbc_headerRegExOption = new GridBagConstraints();
+ gbc_headerRegExOption.anchor = GridBagConstraints.WEST;
+ gbc_headerRegExOption.insets = new Insets(0, 0, 5, 5);
+ gbc_headerRegExOption.gridx = 3;
+ gbc_headerRegExOption.gridy = 4;
+ add(headerRegExOption, gbc_headerRegExOption);
+
+ headerRegEx = new JTextField();
+ GridBagConstraints gbc_headerRegEx = new GridBagConstraints();
+ gbc_headerRegEx.insets = new Insets(0, 0, 5, 5);
+ gbc_headerRegEx.fill = GridBagConstraints.HORIZONTAL;
+ gbc_headerRegEx.gridx = 4;
+ gbc_headerRegEx.gridy = 4;
+ add(headerRegEx, gbc_headerRegEx);
+ headerRegEx.setColumns(10);
+
+ JLabel lblActiveIn = new JLabel("Rules active in:");
+ GridBagConstraints gbc_lblActiveIn = new GridBagConstraints();
+ gbc_lblActiveIn.anchor = GridBagConstraints.EAST;
+ gbc_lblActiveIn.insets = new Insets(0, 0, 5, 5);
+ gbc_lblActiveIn.gridx = 2;
+ gbc_lblActiveIn.gridy = 6;
+ add(lblActiveIn, gbc_lblActiveIn);
+
+ chckbxAllTools = new JCheckBox("All Tools");
+ GridBagConstraints gbc_chckbxAllTools = new GridBagConstraints();
+ gbc_chckbxAllTools.anchor = GridBagConstraints.WEST;
+ gbc_chckbxAllTools.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxAllTools.gridx = 3;
+ gbc_chckbxAllTools.gridy = 6;
+ add(chckbxAllTools, gbc_chckbxAllTools);
+
+ chckbxProxy = new JCheckBox("Proxy");
+ GridBagConstraints gbc_chckbxProxy = new GridBagConstraints();
+ gbc_chckbxProxy.anchor = GridBagConstraints.WEST;
+ gbc_chckbxProxy.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxProxy.gridx = 3;
+ gbc_chckbxProxy.gridy = 7;
+ add(chckbxProxy, gbc_chckbxProxy);
+
+ chckbxScanner = new JCheckBox("Scanner");
+ GridBagConstraints gbc_chckbxScanner = new GridBagConstraints();
+ gbc_chckbxScanner.anchor = GridBagConstraints.WEST;
+ gbc_chckbxScanner.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxScanner.gridx = 3;
+ gbc_chckbxScanner.gridy = 8;
+ add(chckbxScanner, gbc_chckbxScanner);
+
+ chckbxIntruder = new JCheckBox("Intruder");
+ GridBagConstraints gbc_chckbxIntruder = new GridBagConstraints();
+ gbc_chckbxIntruder.anchor = GridBagConstraints.WEST;
+ gbc_chckbxIntruder.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxIntruder.gridx = 3;
+ gbc_chckbxIntruder.gridy = 9;
+ add(chckbxIntruder, gbc_chckbxIntruder);
+
+ chckbxRepeator = new JCheckBox("Repeator");
+ GridBagConstraints gbc_chckbxRepeator = new GridBagConstraints();
+ gbc_chckbxRepeator.anchor = GridBagConstraints.WEST;
+ gbc_chckbxRepeator.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxRepeator.gridx = 3;
+ gbc_chckbxRepeator.gridy = 10;
+ add(chckbxRepeator, gbc_chckbxRepeator);
+
+ chckbxExtender = new JCheckBox("Extender");
+ GridBagConstraints gbc_chckbxExtender = new GridBagConstraints();
+ gbc_chckbxExtender.anchor = GridBagConstraints.WEST;
+ gbc_chckbxExtender.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxExtender.gridx = 3;
+ gbc_chckbxExtender.gridy = 11;
+ add(chckbxExtender, gbc_chckbxExtender);
+
+ chckbxTarget = new JCheckBox("Target");
+ GridBagConstraints gbc_chckbxTarget = new GridBagConstraints();
+ gbc_chckbxTarget.anchor = GridBagConstraints.WEST;
+ gbc_chckbxTarget.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxTarget.gridx = 3;
+ gbc_chckbxTarget.gridy = 12;
+ add(chckbxTarget, gbc_chckbxTarget);
+
+ chckbxSequencer = new JCheckBox("Sequencer");
+ GridBagConstraints gbc_chckbxSequencer = new GridBagConstraints();
+ gbc_chckbxSequencer.anchor = GridBagConstraints.WEST;
+ gbc_chckbxSequencer.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxSequencer.gridx = 3;
+ gbc_chckbxSequencer.gridy = 13;
+ add(chckbxSequencer, gbc_chckbxSequencer);
+
+ chckbxSpider = new JCheckBox("Spider");
+ GridBagConstraints gbc_chckbxSpider = new GridBagConstraints();
+ gbc_chckbxSpider.anchor = GridBagConstraints.WEST;
+ gbc_chckbxSpider.insets = new Insets(0, 0, 5, 5);
+ gbc_chckbxSpider.gridx = 3;
+ gbc_chckbxSpider.gridy = 14;
+ add(chckbxSpider, gbc_chckbxSpider);
+
+ init();
+ }
+
+ private void init(){
+ //resetSettings();
+ loadSettings();
+ updateUIState();
+ setActions();
+ saveSettings();
+ }
+
+ private void updateUIState() {
+ if(pathRegExOption.getSelectedIndex()==1) {
+ pathRegEx.setEnabled(false);
+ }else {
+ pathRegEx.setEnabled(true);
+ }
+
+ if(headerRegExOption.getSelectedIndex()==1) {
+ headerRegEx.setEnabled(false);
+ }else {
+ headerRegEx.setEnabled(true);
+ }
+
+ if(chckbxAllTools.isSelected()) {
+ chckbxAllTools.setEnabled(true);
+ chckbxProxy.setEnabled(false);
+ chckbxScanner.setEnabled(false);
+ chckbxIntruder.setEnabled(false);
+ chckbxRepeator.setEnabled(false);
+ chckbxExtender.setEnabled(false);
+ chckbxTarget.setEnabled(false);
+ chckbxSequencer.setEnabled(false);
+ chckbxSpider.setEnabled(false);
+ }else {
+ chckbxAllTools.setEnabled(true);
+ chckbxProxy.setEnabled(true);
+ chckbxScanner.setEnabled(true);
+ chckbxIntruder.setEnabled(true);
+ chckbxRepeator.setEnabled(true);
+ chckbxExtender.setEnabled(true);
+ chckbxTarget.setEnabled(true);
+ chckbxSequencer.setEnabled(true);
+ chckbxSpider.setEnabled(true);
+ }
+
+ if(targetScopeOption.getSelectedItem().equals(scopeOptions2.DISABLED) &&
+ pathRegExOption.getSelectedItem().equals(scopeOptions2.DISABLED) &&
+ headerRegExOption.getSelectedItem().equals(scopeOptions2.DISABLED)) {
+ // totally disabled!
+ chckbxAllTools.setEnabled(false);
+ chckbxProxy.setEnabled(false);
+ chckbxScanner.setEnabled(false);
+ chckbxIntruder.setEnabled(false);
+ chckbxRepeator.setEnabled(false);
+ chckbxExtender.setEnabled(false);
+ chckbxTarget.setEnabled(false);
+ chckbxSequencer.setEnabled(false);
+ chckbxSpider.setEnabled(false);
+ }
+
+ }
+
+ private void setActions() {
+ setActionsJComboBoxHelper(targetScopeOption);
+ setActionsJComboBoxHelper(pathRegExOption);
+ setActionsJTextFieldHelper(pathRegEx);
+ setActionsJComboBoxHelper(headerRegExOption);
+ setActionsJTextFieldHelper(headerRegEx);
+ setActionsJCheckBoxHelper(chckbxAllTools);
+ setActionsJCheckBoxHelper(chckbxProxy);
+ setActionsJCheckBoxHelper(chckbxScanner);
+ setActionsJCheckBoxHelper(chckbxIntruder);
+ setActionsJCheckBoxHelper(chckbxRepeator);
+ setActionsJCheckBoxHelper(chckbxExtender);
+ setActionsJCheckBoxHelper(chckbxTarget);
+ setActionsJCheckBoxHelper(chckbxSequencer);
+ setActionsJCheckBoxHelper(chckbxSpider);
+ }
+
+ private void setActionsJCheckBoxHelper(JCheckBox checkbox) {
+ checkbox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ updateUIState();
+ saveSettings();
+ }
+ });
+ }
+
+ private void setActionsJComboBoxHelper(JComboBox combobox) {
+ combobox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ updateUIState();
+ saveSettings();
+ }
+ });
+ }
+
+ private void setActionsJTextFieldHelper(JTextField textfield) {
+ textfield.getDocument().addDocumentListener(new DocumentListener() {
+ @Override
+ public void changedUpdate(DocumentEvent arg0) {
+ updateUIState();
+ saveSettings();
+ }
+ @Override
+ public void insertUpdate(DocumentEvent arg0) {
+ updateUIState();
+ saveSettings();
+ }
+ @Override
+ public void removeUpdate(DocumentEvent arg0) {
+ updateUIState();
+ saveSettings();
+ }
+ });
+ }
+
+ private void loadSettings() {
+ targetScopeOption.setSelectedIndex((int) loadExtensionSettingHelper("targetScopeOption","int",0));
+ pathRegExOption.setSelectedIndex((int) loadExtensionSettingHelper("pathRegExOption","int",0));
+ pathRegEx.setText((String) loadExtensionSettingHelper("pathRegEx","string",""));
+ headerRegExOption.setSelectedIndex((int) loadExtensionSettingHelper("headerRegExOption","int",0));
+ headerRegEx.setText((String) loadExtensionSettingHelper("headerRegEx","string","x\\-my\\-http\\-smuggler: active"));
+ chckbxAllTools.setSelected((boolean) loadExtensionSettingHelper("chckbxAllTools","bool",false));
+ chckbxProxy.setSelected((boolean) loadExtensionSettingHelper("chckbxProxy","bool",false));
+ chckbxScanner.setSelected((boolean) loadExtensionSettingHelper("chckbxScanner","bool",false));
+ chckbxIntruder.setSelected((boolean) loadExtensionSettingHelper("chckbxIntruder","bool",false));
+ chckbxRepeator.setSelected((boolean) loadExtensionSettingHelper("chckbxRepeator","bool",true));
+ chckbxExtender.setSelected((boolean) loadExtensionSettingHelper("chckbxExtender","bool",false));
+ chckbxTarget.setSelected((boolean) loadExtensionSettingHelper("chckbxTarget","bool",false));
+ chckbxSequencer.setSelected((boolean) loadExtensionSettingHelper("chckbxSequencer","bool",false));
+ chckbxSpider.setSelected((boolean) loadExtensionSettingHelper("chckbxSpider","bool",false));
+ }
+
+ private void saveSettings() {
+ saveExtensionSettingHelper("targetScopeOption", targetScopeOption.getSelectedIndex());
+ saveExtensionSettingHelper("pathRegExOption", pathRegExOption.getSelectedIndex());
+ saveExtensionSettingHelper("pathRegEx", pathRegEx.getText());
+ saveExtensionSettingHelper("headerRegExOption", headerRegExOption.getSelectedIndex());
+ saveExtensionSettingHelper("headerRegEx", headerRegEx.getText());
+ saveExtensionSettingHelper("chckbxAllTools", chckbxAllTools.isSelected());
+ saveExtensionSettingHelper("chckbxProxy", chckbxProxy.isSelected());
+ saveExtensionSettingHelper("chckbxScanner", chckbxScanner.isSelected());
+ saveExtensionSettingHelper("chckbxIntruder", chckbxIntruder.isSelected());
+ saveExtensionSettingHelper("chckbxRepeator", chckbxRepeator.isSelected());
+ saveExtensionSettingHelper("chckbxExtender", chckbxExtender.isSelected());
+ saveExtensionSettingHelper("chckbxTarget", chckbxTarget.isSelected());
+ saveExtensionSettingHelper("chckbxSequencer", chckbxSequencer.isSelected());
+ saveExtensionSettingHelper("chckbxSpider", chckbxSpider.isSelected());
+ }
+
+ private void resetSettings() {
+ saveExtensionSettingHelper("targetScopeOption", 0);
+ saveExtensionSettingHelper("pathRegExOption", 0);
+ saveExtensionSettingHelper("pathRegEx", "");
+ saveExtensionSettingHelper("headerRegExOption", 0);
+ saveExtensionSettingHelper("headerRegEx", "x\\-my\\-http\\-smuggler: active");
+ saveExtensionSettingHelper("chckbxAllTools", false);
+ saveExtensionSettingHelper("chckbxProxy", false);
+ saveExtensionSettingHelper("chckbxScanner", false);
+ saveExtensionSettingHelper("chckbxIntruder", false);
+ saveExtensionSettingHelper("chckbxRepeator", true);
+ saveExtensionSettingHelper("chckbxExtender", false);
+ saveExtensionSettingHelper("chckbxTarget", false);
+ saveExtensionSettingHelper("chckbxSequencer", false);
+ saveExtensionSettingHelper("chckbxSpider", false);
+ }
+
+ private void saveExtensionSettingHelper(String name, Object value) {
+ try {
+ _callbacks.saveExtensionSetting(name, String.valueOf(value));
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ }
+ }
+
+ private Object loadExtensionSettingHelper(String name, String type, Object defaultValue) {
+ Object value = null;
+ try {
+ String temp_value = _callbacks.loadExtensionSetting(name);
+ if(temp_value!=null && !temp_value.equals("")) {
+ switch(type.toLowerCase()){
+ case "int":
+ case "integer":
+ value = Integer.valueOf(temp_value);
+ break;
+ case "bool":
+ case "boolean":
+ value = Boolean.valueOf(temp_value);
+ break;
+ default:
+ value = temp_value;
+ break;
+ }
+ }
+ }catch(Exception e) {
+ _stderr.println(e.getMessage());
+ }
+
+ if(value==null) {
+ value = defaultValue;
+ }
+ return value;
+ }
+}
diff --git a/src/resources/AboutMain.png b/src/resources/AboutMain.png
new file mode 100644
index 0000000..4fe33cd
Binary files /dev/null and b/src/resources/AboutMain.png differ