BurpSuite practical tutorial 03-BurpSuite plug-in development

burp plug-in development

The power of Burp Suite not only provides a wealth of functions that can be used by testers, but also provides support for third-party extension plug-ins, which greatly facilitates users to write their own custom plug-ins. , Burp Suite supports three plug-in types: Java, Python, and Ruby. No matter which language is implemented, developers only need to choose the language they are familiar with and implement the desired functions according to the interface specifications. Let’s take a look at how to develop a Burp Extender plug-in. The main contents covered in this chapter are:

  1. API description
  2. Preparation before writing Burp plug-in
  3. Writing Burp plug-in (Java language version)

api description

Open the Tab page of Burp Extender's APIs and see the interface as shown below:
Insert image description here

Note that different versions of the API may be different. I used the latest method of using maven dependencies according to the official website. Because the latest version of BurpExtension uses an initialization method initalize that is one letter different from my current version of initalise, it took me a long time. It is recommended to use the current file for development. The api interface is exported to the project source code directory, because the maven api does not know the version correspondence at all. My version: V2022.9.

Create a new maven empty project in idea, click apis - save interface files to the src/main/java directory. The directory structure is
Insert image description here
as follows. For
Insert image description here
the specific use of the api, please refer to the api description or save javadoc files on the apis panel to open html to view
Insert image description here
or go to the official website to view:
https://portswigger.github.io/burp-extensions-montoya-api/javadoc/burp/api/montoya/MontoyaApi.html

Preparation before writing plug-in

Source code reference

Burpsuite does not have detailed documentation describing how to write plug-ins. It provides many related cases, which you need to read by yourself
https://github.com/PortSwigger/burp-extensions-montoya-api-examples

java environment configuration

First, determine the jdk you need to use for your burpsuite version. For example, mine is jdk17, and jdk8 is used for daily development. Modify the
Insert image description here
environment of the idea.
Click project structure - SDKS to add jdk17.
Insert image description here
If the language level on Modules is not 17, just select the largest one. Here is mine. 13 is enough. This is just the version used by idea to compile the code.
Change the Project SDK on the Project to 17 and
Insert image description here
add it in pom.xml.

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

Use maven to execute mvn package to confirm whether you are using jdk17.
Insert image description here
Modify pom.xml and modify the packaging method to jar.

    <packaging>jar</packaging>

Enable debugging

Open the Edit Configurations of idea running, create a new Remote, copy the command line arguments for remote JVM
Host is set to: localhost, and the port is set to: 50055.
Insert image description here
Add the copied content to the bat file of burpsuite
Insert image description here
and add the jvm parameters to
Insert image description here
restart burpsuite
netstat - aon | findstr 50055 Check whether the port is open.

helloworld written

Create a test class: HelloWorld

package com.qj.bc;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.logging.Logging;

public class HelloWorld implements BurpExtension {
    @Override
    public void initialise(MontoyaApi api) {
        Logging logging = api.logging();

        // write a message to our output stream
        logging.logToOutput("Hello output.");

        // write a message to our error stream
        logging.logToError("Hello error.");

        // write a message to the Burp alerts tab
        logging.raiseInfoEvent("Hello info event.");
        logging.raiseDebugEvent("Hello debug event.");
        logging.raiseErrorEvent("Hello error event.");
        logging.raiseCriticalEvent("Hello critical event.");

        // throw an exception that will appear in our error stream
        throw new RuntimeException("Hello exception.");
    }
}

Use mvn package to package.
Start remote debugging
Insert image description here
. Open burpsuite - Extener - Extensions - Add and add one.
Insert image description here
After clicking next, the breakpoint is set
Insert image description here
. After skipping the breakpoint, view the output and error log
Insert image description here
Errors are displayed .
Insert image description here

Customized packet capture log display

Requirement: The packet capture log of intercepted bp is displayed in a custom table. Clicking the table can display the request and response information.
The renderings are as follows.
Insert image description here
Official website example reference:
https://github.com/PortSwigger/burp-extensions-montoya-api-examples/tree/main/customlogger

Add request filter

package com.qj.bc.customlogger;

import burp.api.montoya.core.MessageAnnotations;
import burp.api.montoya.core.ToolSource;
import burp.api.montoya.http.HttpHandler;
import burp.api.montoya.http.RequestHandlerResult;
import burp.api.montoya.http.ResponseHandlerResult;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.http.message.responses.HttpResponse;

public class MyHttpHandler implements HttpHandler
{
    private final MyTableModel tableModel;

    public MyHttpHandler(MyTableModel tableModel)
    {

        this.tableModel = tableModel;
    }


    @Override
    public RequestHandlerResult handleHttpRequest(HttpRequest request, MessageAnnotations annotations, ToolSource toolSource) {
        return RequestHandlerResult.from(request,annotations);
    }

    /**
     *
     * @param request 被抓包的请求信息
     * @param response 返回的响应信息
     * @param annotations 消息标记,比如高亮,添加注释等。
     * @param toolSource 这个请求来源于那个工具,比如是proxy还是爆破,还是其他的工具,比如proxy抓包的HTTP请求,爆破自定义的请求等等
     * @return
     */
    @Override
    public ResponseHandlerResult handleHttpResponse(HttpRequest request, HttpResponse response, MessageAnnotations annotations, ToolSource toolSource) {
        tableModel.add(new HttpResponseReceived(toolSource,request,response));
        return ResponseHandlerResult.from(response,annotations);
    }
}

Add http request object

Because http intercepts four parameters

  1. request captured request information
  2. response the response information returned
  3. annotations message markup, such as highlighting, adding comments, etc.
  4. toolSource This request comes from which tool, such as proxy, blasting, or other tools, such as proxy capturing HTTP requests, blasting custom attack requests (click start attack to catch), etc.

Encapsulate a class to wrap these parameters, because the request response, source and other information need to be displayed on the interface.

package com.qj.bc.customlogger;

import burp.api.montoya.core.ToolSource;
import burp.api.montoya.http.message.requests.HttpRequest;
import burp.api.montoya.http.message.responses.HttpResponse;

public class HttpResponseReceived {
    private ToolSource toolSource;
    private HttpRequest request;
    private HttpResponse response;

    public HttpResponseReceived(ToolSource toolSource, HttpRequest request, HttpResponse response) {
        this.toolSource = toolSource;
        this.request = request;
        this.response = response;
    }

    public ToolSource toolSource(){
        return toolSource;
    }
    public HttpRequest initiatingRequest(){
        return request;
    }
    public HttpResponse getResponse(){
        return response;
    }
}

Add table data source

, this data is finally displayed in the table, define a table modal

package com.qj.bc.customlogger;
import burp.api.montoya.http.message.responses.HttpResponse;

import javax.swing.table.AbstractTableModel;
import java.util.ArrayList;
import java.util.List;
public class MyTableModel extends AbstractTableModel
{
    private final List<HttpResponseReceived> log;

    public MyTableModel()
    {
        this.log = new ArrayList<>();
    }

    @Override
    public synchronized int getRowCount()
    {
        return log.size();
    }

    @Override
    public int getColumnCount()
    {
        return 2;
    }

    @Override
    public String getColumnName(int column)
    {
        return switch (column)
                {
                    case 0 -> "Tool";
                    case 1 -> "URL";
                    default -> "";
                };
    }

    @Override
    public synchronized Object getValueAt(int rowIndex, int columnIndex)
    {
        HttpResponseReceived responseReceived = log.get(rowIndex);

        return switch (columnIndex)
                {
                    case 0 -> responseReceived.toolSource().toolType();
                    case 1 -> responseReceived.initiatingRequest().url();
                    default -> "";
                };
    }

    public synchronized void add(HttpResponseReceived responseReceived)
    {
        int index = log.size();
        log.add(responseReceived);
        fireTableRowsInserted(index, index);
    }

    public synchronized HttpResponseReceived get(int rowIndex)
    {
        return log.get(rowIndex);
    }
}

Define burp extension

package com.qj.bc.customlogger;

import burp.api.montoya.BurpExtension;
import burp.api.montoya.MontoyaApi;
import burp.api.montoya.ui.UserInterface;
import burp.api.montoya.ui.editor.HttpRequestEditor;
import burp.api.montoya.ui.editor.HttpResponseEditor;

import javax.swing.*;
import java.awt.*;

import static burp.api.montoya.ui.editor.EditorOptions.READ_ONLY;

public class CustomLogger implements BurpExtension
{
    private MontoyaApi api;

    @Override
    public void initialise(MontoyaApi api)
    {
        this.api = api;
        MyTableModel tableModel = new MyTableModel();
        //在burpsuite中添加一个tab页签,名字是Custom logger
        api.userInterface().registerSuiteTab("Custom logger", constructLoggerTab(tableModel));
        //注册一个http抓包请求拦截器,用来获取所有抓包的数据添加到表格
        api.http().registerHttpHandler(new MyHttpHandler(tableModel));
    }

    /**
     * 使用JSplitPane,添加一个左面是http请求的表格,下面是个http的请求和响应编辑器
     * @param tableModel
     * @return
     */
    private Component constructLoggerTab(MyTableModel tableModel)
    {
        // main split pane
        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);

        // tabs with request/response viewers
        JTabbedPane tabs = new JTabbedPane();

        UserInterface userInterface = api.userInterface();

        HttpRequestEditor requestViewer = userInterface.createHttpRequestEditor(READ_ONLY);
        HttpResponseEditor responseViewer = userInterface.createHttpResponseEditor(READ_ONLY);

        tabs.addTab("Request", requestViewer.uiComponent());
        tabs.addTab("Response", responseViewer.uiComponent());

        splitPane.setRightComponent(tabs);

        // table of log entries
        JTable table = new JTable(tableModel)
        {
            /**
             * 当表格的某个请求被选择后,需要将请求和响应的结果,设置到请求响应编辑器中
             * @param rowIndex
             * @param columnIndex
             * @param toggle
             * @param extend
             */
            @Override
            public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
            {
                // show the log entry for the selected row
                HttpResponseReceived responseReceived = tableModel.get(rowIndex);
                requestViewer.setRequest(responseReceived.initiatingRequest());
                responseViewer.setResponse(responseReceived.getResponse());

                super.changeSelection(rowIndex, columnIndex, toggle, extend);
            }
        };

        JScrollPane scrollPane = new JScrollPane(table);

        splitPane.setLeftComponent(scrollPane);

        return splitPane;
    }
}

Guess you like

Origin blog.csdn.net/liaomin416100569/article/details/129188554