Burp
Burp
Burp
2
Burp Extender 3
Burp Extender Interfaces 4
Setup DEV environment using IntelliJ 5
Using CLI interface to build jars 11
Burp Extender
Burp Extender provides necessary functionality required for creation of Burp Suite extensions. The
Extender tab exposes all APIs required for development of custom extensions in the form of Java
Interfaces. These interfaces provide bindings for non Java environments as well, for Python through
Jython and for Ruby through JRuby. The library support for Jython and JRuby is not so rich and is not
usually recommended to pick these for plugin development.
You can see the list of all the Interfaces under Burp -> Extender -> APIs.
IBurpExtender interface class is the entry point of any Extender plugin you write. And the class
implementing this interface should implement void registerExtenderCallbacks(IBurpExtenderCallbacks
callbacks) abstract function. This is what the Java Doc of IBurpExtender also talks about itself.
The implementing class should belong to the burp package. This package will be automatically created
once you export API Interface classes through 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
* <code>IBurpExtenderCallbacks</code> interface, providing methods that may
* be invoked by the extension to perform various actions.
*
* @param callbacks An
* <code>IBurpExtenderCallbacks</code> object.
*/
void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks);
}
The full list of Interfaces can be checked here or in the Burp Interface list.
1. Create a new Java Project in IntelliJ. Following the steps in the Image one after the other.
Click Apply or Ok. With this, now everytime you run build, you will have your artifact which is Jar created in
the build folder. This Jar can be directly imported in the Burp Suite.
mkdir build
mkdir bin
# clean those directories if they are already existing
Once the files are compiled, you can load the created binary in the Burp Extender interface.
Code for all the chapters including this is present inside the code folder along with this book.
Click on Save Interface Files and save it in the directory where you have stored the BurpExtender.java
file. Make sure it belongs to the burp package, which is the same for BurpExtender.java.
Hello Burp
Every Burp Extender plugin needs to implement IBurpExtender interface, which is nothing but the entry
point of any plugin.
This interface receives a callback and this callback object is used to send and receive signal/events to
the Burp runtime.
See the example below, it is using the setExtensionName method to set the name of my created
extension and tell that to Burp runtime. And then it is using the setAlert method for sending messages to
Burp runtime to display in the dashboard.
package burp;
😄
You can see the result of the loaded extension in the dashboard.
WOW we just built and loaded an extension into Burp. Kudos to you, to achieve this landmark.
1. As discussed in Chapter 1, every burp extender plugin needs to implement IBurpExtender. This line
public class BurpExtender implements IBurpExtender does the same thing with
@Override annotation
2. IBurpExtender has a registerExtenderCallbacks which takes input from Burp UI and receives a
callback as and when this plugin is called. Callback exposes multiple methods which can be used
to interact Burp Suite Runtime such as :
So far we learned how to write a basic Hello World extension showcasing interaction with Burp Suite.
In this chapter, we’ll mostly cover the Extender API interfaces and their use cases. In the Chapter's end, we
will create an extension which will monitor HTTP requests from Burp Suite and display the domains
passing through the Proxy in the Alert tab. Nice isn't it ?
1. Helper Interface
2. Simple URL Encoder
3. Interface Registration
4. Listen for events from Proxy
Helper Interface
In the previous extender plugin that we created, we used callbacks object’s methods twice for setting the
name of the extension and displaying a message on Alert tab, right ? Callback interface is really great, it
offers plenty of other resources as instance objects as well.
One of the important methods exposed by callbacks is getHelpers(). This method returns an object of
IExtensionHelperstype, which as the name suggests will be going to help us in making boring and
repetitive tasks easier. The object contains multiple methods, few of important ones are listed here to
throw an insight:
● analyzeRequest(): This method can be used to analyze an HTTP request, and obtain various key
details about it. Like request headers, cookies, etc.
● analyzeResponse(): This method can be used to analyze an HTTP response, and obtain various
key details about it.
● base64Encode(): This method can be used to Base64-encode the specified data.
● base64Decode(): This method can be used to decode Base64-encoded data.
● urlDecode(): This method can be used to URL-decode the specified data.
● urlEncode(): This method can be used to URL-encode the specified data
and many more. The full list of Extension helpers can be found here.
package burp;
public class BurpExtender implements IBurpExtender {
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
callbacks.setExtensionName("URL Encoder");
String encodedString =
helpers.urlEncode("http://www.example.com/dir/path?q=10&a=100");
callbacks.issueAlert(encodedString);
}
}
Interface registration
Let’s come back to our original case of creating a plugin which will monitor all the HTTP requests.
Interface registration is important and is useful in telling Burp Runtime what our custom code is capable
of handling. For doing this, you need to tell the Burp Runtime with callbacks’s register* functionality. If
you plan to handle different events you will need to register their respective interface registration function.
As an example, if you are implementing an IHTTPListener interface through any of the classes, then you
must have the object of those classes passed to callbacks.registerHttpListener() method.
Note that callbacks itself is an object of type IBurpExtenderCallbacks. IntelliJ loaded with all interface files
will show you suggestions something like this.
Create a class which will implement the IHTTPListener interface. In this interface we would need to
implement processHttpMessage method.
/*
LogProxyRequests.java
*/
package burp;
/*
For parsing requests.
*/
iExtensionHelpers = callbacks.getHelpers();
}
/*
Only listen for events from Burp Suite proxy && Only listen for requests.
*/
if(toolFlag == IBurpExtenderCallbacks.TOOL_PROXY && messageIsRequest == true)
requestInfo = iExtensionHelpers.analyzeRequest(messageInfo);
String domainName = requestInfo.getUrl().getHost();
/*
Log the domain name to the Alerts tab.
*/
iBurpExtenderCallbacks.issueAlert("Proxy: " + domainName);
}
}
Register the implemented class in Our BurpExtender.java class file through callbacks.
/*
BurpExtender.java
*/
package burp;
Now we have two different files where the logic for our plugin resides. That’s awesome, also we can see
dots are now getting connected.
Build the jar and load the jar in Burp Suite. If everything goes well, you will get domain names getting
logged in alerts tab.
Hurrah !!! We finally created a plugin which can help you intercept burp suite traffic, modify on the fly and
send the domains to the alert tab.
Although in the current state there might not be great use of this plugin, here I dont want to teach to build
specific plugins but my idea is to make you learn about the methods which are possible which exist and
how those methods can be used to to create a specific functionality.
IIntruderPayloadProcessor interface contains two method of the following structure, these will be
overridden in the implementing class which are necessary to bring the functionality that we need.
● string getProcessorName(): This will provide the name of the payload processor in the Burp
Suite UI.
For the demonstration purpose we would like to create a basic base64 payload processor. The idea is that
it will take a current payload and then create a base64 encoded payload and use that payload as intruder
payload.
IExtensionHelpers helpers;
/*
BurpExtender.java
*/
package burp;
// Notice this.
callbacks.registerIntruderPayloadProcessor(new IntruderPayloadProcessor(callbacks));
}
}
Now this Payload processor will pop up in Intruder, payload processor like follows.
The name you have entered for Payload processor in the implementing class will come under drop
down. Since I entered the Base64 Processor, it is showing as it is.
Run it and check the payloads are getting converted to base64 by our processor and are executed
likewise.
This chapter is just the extension of those principles on similar ground. This chapter in detail talks about
Event listeners, and how they work in flow with Burp Callbacks. This chapter will also demonstrate how
different event listeners can be configured in one single BurpExtender class.
● IHttpListener:
○ The listener will be notified of requests and responses made by any Burp tool, any http
request and response.
○ Extensions are useful in case of custom analysis or modification of HTTP messages.
● IProxyListener:
○ The listener will be notified of requests and responses being processed by the Proxy tool.
○ Extensions are useful in case of custom analysis or modification of these messages coming
from the proxy tab. This will exclude the events from Scanner, Repeater etc.
● IScannerListener:
○ The listener will be notified of new issues that are reported by the Scanner tool.
○ Extensions are useful in case of custom analysis or logging of Scanner issues by
registering a Scanner listener.
● IExtensionStateListener:
○ The listener will be notified of changes to the extension's state.
○ Extensions are useful in case you want to check if any other extension is loaded or not.
This can be useful in checking if the extension will need to interact with other extensions.
Yes in burp that too is possible.
** 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.
IBurpExtenderCallbacks callbacks;
/* This we have already seen so far, this method we mostly use to register out Extender to Burp, by
setting name
getting a helper, setting plugin level alerts etc.
*/
@Override public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
callbacks.setExtensionName("Event Listener Plugin");
callbacks.issueAlert("Plugin loaded");
this.callbacks = callbacks;
/*
Since this class is implementing all the interfaces, this class must register itself as listener for all
the
implementations.
*/
callbacks.registerHttpListener(this);
callbacks.registerProxyListener(this);
callbacks.registerScannerListener(this);
callbacks.registerExtensionStateListener(this);
/*
Since we are implementing event listener for 4 different class, we are registering it for 4 times
for various
Listeners.
Plugin registration is required to let Burp know what all events this plugin is looking for.
*/
}
/*
This function belongs to IHTTPListener Interface.
@toolFlag : take the Burp Suite plugin number, number to tool name can be obtained from
callback.getToolName()
@messageIsRequest : True if request, false id response
@ messageInfo : Encapsulating details about an event.
*/
@Override public void processHttpMessage(int toolFlag, boolean messageIsRequest,
/*
This function implements IProxyListener
@messageIsRequest : True if request, false id response
@message : Encapsulating details about an event.
*/
@Override public void processProxyMessage(boolean messageIsRequest,
IInterceptedProxyMessage message) {
callbacks.issueAlert(
String.format("%s %s Called from %s",
messageIsRequest ? "HTTP Request : " : "HTTP Response : ",
message.getMessageInfo(),
"Proxy")
);
}
/*
Implements IScannerListener
@issue: encapsulates the details about the scan event.
*/
@Override public void newScanIssue(IScanIssue issue) {
callbacks.issueAlert("Scan triggered : " + issue.getIssueName());
}
/*
This function implements IExtensionStateListener.
*/
@Override public void extensionUnloaded() {
callbacks.issueAlert("Extension Unloaded");
}
}
😄
At times you might want to scan an application with a custom session token set right ? If yes this extender
plugin cum tutorial can save you here
This chapter talks about how Burp suite extender APIs can be used to create plugins which can modify the
session related information on the fly. This chapter is more of an exercise than a plugin use case.
This chapter comes with a demo server to test the developed plugin. The application server code is here
Server. Just run this server as node server.js, this will spin up the server at port 8000, where we will be
testing our plugin.
If you carefully observe the server.js file, you can notice that session information is stored in the
SESSION_ID_KEY variable which points to X-Custom-Session-Id.
Let’s Start.
What is Macro ?
A word about Burp Macro.
● A macro in Burp Suite is a series of HTTP requests to be sent to the server prior to requests which
have been proxied by Burp. Once the macro requests have been carried out, the set of parameters
can be taken from the response of the final macro request and can then be passed on to the
request that called the macro.
● So in short macros are a series of steps which will/can be called before making an actual request
by any burp suite entity.
Create a macro
It’s simple again. Navigate like this :
Burp -> Project options -> Sessions -> Macros -> Add
So to record macro for session token generation, make a request to /session endpoint Burp Proxy and
record macro as discussed below:
😄
history tab. I have named the macro : test-server: Session Token Creation , remember this, as we
will need it.
package burp;
import java.util.List;
/*
Register the SessionHandler
*/
callbacks.registerSessionHandlingAction(this);
}
/*
This function is executed after macro call and before a subsequent Scanner or Intruder call.
*/
@Override public void performAction(IHttpRequestResponse currentRequest,
IHttpRequestResponse[] macroItems) {
/*
Extract Macro response
*/
final byte[] macroResponse = macroItems[macroItems.length - 1].getResponse();
/*
Extract all headers from response
*/
final List<String> headers = helpers.analyzeResponse(macroResponse).getHeaders();
/*
Extract the Custom Session token header from all headers
*/
String sessionToken = null;
for(String header : headers){
if(!header.startsWith(SESSION_ID_KEY)) continue;
sessionToken = header.substring(SESSION_ID_KEY.length()).trim();
}
/*
If the session token is not identified, skip.
*/
if(sessionToken == null) return;
/*
Otherwise, append the session token to currentRequest
*/
final String req = helpers.bytesToString(currentRequest.getRequest());
final int sessionTokenKeyStart = helpers.indexOf(helpers.stringToBytes(req),
SESSION_ID_KEY_BYTES,
false,
0,
req.length());
final int sessionTokenKeyEnd = helpers.indexOf(helpers.stringToBytes(req),
NEWLINE_BYTES,
false,
sessionTokenKeyStart,
req.length());
/*
Update the current request headers
*/
currentRequest.setRequest(helpers.stringToBytes(newRequest));
}
}
Code above is self explanatory. Build it and load it in Burp.
Goto : Burp -> Project options -> Sessions -> Session Handling Rule -> Add Session handling rule
---
In this chapter we will be creating a proxy tab extender plugin which will decode the JWT token present in
This is how this Tab class would look in an abstract way. Stay with me, We will fill up the space, one by one
package burp;
import java.awt.*;
Fill up constructor
public JWTDecodeTab(IMessageEditorController controller, boolean editable,
IBurpExtenderCallbacks callbacks) {
this.editable = editable;
this.callbacks = callbacks;
/*
Create an instance of Burp's text editor, to display our JWT decode data.
*/
txtInput = this.callbacks.createTextEditor();
txtInput.setEditable(editable);
}
Other functions
Explanations are inline with functions.
/*
This will set the name for this tab under Proxy.
*/
@Override public String getTabCaption() {
return "JWT Decode";
}
/*
This function will code the logic which will enable or disable this Tab. So since this is JWT decode
tab plugin this should enable when there is a JWT token present in there.
To keep this simple I am assuming that, JWT token is present as part of the parameter name
`jwtToken`.
This logic can be complex and process for all the parameters and can check if there is any field
with data JWT deserializable or not.
Steps :
- split on '.', '.'(Period) is regex in Java which points to all chars so make sure you use
patterns.
https://stackoverflow.com/a/3481842
- decode the first two parts as third part is just signature.
*/
List<String> jwtTokenParts = Arrays.asList( jwtToken.split(Pattern.quote(".")));
String decodedJwtToken =
helpers.bytesToString(helpers.base64Decode( jwtTokenParts.get(0))) +"\r\n" +
helpers.bytesToString(helpers.base64Decode( jwtTokenParts.get(1)));
And last but not the least, the main BurpExtender class, to bring everything to life.
callbacks.registerMessageEditorTabFactory(this);
}
Test
Did you ever think that you would be able to bring any of such plugins to life on your own ? And just now
we did it. Stare it for a moment, yes you only did it.
😏😝
This chapter is going to be bit length and tricky so try to be with the flow, otherwise you have to read from
start
This chapter needs some knowledge of Java Swing Framework, but if you don't have any knowledge, it
won't be too difficult to deal with.
In this chapter we will be creating a separate tab plugin Yes, you will have a tab like shown below if you
successfully complete this..
● This tab will show up in the Burp's Top tab menu like this.
Trust me this UI design won't be difficult at all if you are using any IDE like I am using intelliJ.
● This tab plugin will be very simple version of what we have in jwt.io
/**
* 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();
}
The content returned by getUiComponent() is what is rendered under the plugins tab window.
To create the UI for the tab I will be using, IntelliJ’s in-built form designer, through this you can create UI
very quickly with drag and drops and code only the event listeners.
Once you select this, Two files will be created, one will be Form in UI and another will be its
implementation at java class level. I have named those files as JWTDecodeTabForm.java &
JWTDecodeTabForm.form. I have kept the class JWTDecodeTab separate which implements ITab
interface.
/*
BurpExtender.java
*/
package burp;
/*
JWTDecodeTab.java
*/
package burp;
import java.awt.*;
JWTDecodeTabForm is the class, which we designed Swing UI for through IntelliJ designer. On Bare
minimum this class looks like.
IBurpExtenderCallbacks callbacks;
basePanel is the container component which contains all the other components, so I have returned this
only which will display the UI for the tab.
Once you do all these steps and build artifact, upon loading that into Burp will result in something like this:
This UI though is not functional as no click events are registered at all for Decode & Encode buttons.
● Right click on the decode button and select Create listener -> Action Listener. Then put in this
code.
headerFieldTextArea.setText(helpers.bytesToString(helpers.base64Decode( jwtTokenParts.get(0))));
payloadFieldTextArea.setText(helpers.bytesToString(helpers.base64Decode( jwtTokenParts.get(1))));
● Do the same for Encode, but its implementation will be slightly different.
encodeButton.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent actionEvent) {
try{
Mac sha512Hmac;
String secret = jwtSecretTextArea.getText();
jwtTokenTextArea.setText(partialJwt + '.' +
helpers.base64Encode(helpers.bytesToString(macData)));
There might be some issues in JWT decode and encode functionality but again the motive of this series is
to teach you how to create extensions not how to create logic for extensions.
Rebuild the jar and load it again in Burp and see the magic that you have created. Believe in yourself, you
only did it :)