从0开发burpsuite插件(Java)

本人从0开始,写一个bp的开发教程,思路为:跟着教程搭建出一个可以用在burpsuite的插件,然后在此基础上构建一个由GUI的插件,后面进一步去熟悉插件相关的API函数。本文教程基于gradle项目,因为方便引言一些插件库。

1 一个小的bp插件Demo

1.1新建一个gradle项目

(1)新建一个gradle项目,项目名为:burp-detect-nginx

1621586533328

(2)新建完后,在 build.gradle 文件中添加以下依赖,也就是加载 burpsuite 插件API ,如果提示 auto import, 可以点击,从而自动从远程仓库加载 burpsuite API 。具体需要的版本可以去Maven中央存储库搜索,这里使用的是1.7.13

compile('net.portswigger.burp.extender:burp-extender-api:1.7.13')

同时在 plugins 里面添加 shadow 插件,该插件可以方便把项目打包成 jar 包。shadow版本需要根据自己的gadle版本去选择,shaow插件版本可以根据这里去选择。这里我的选择的是4.0.3,然后保存 build.gradle文件可以看到加载成功。

id 'com.github.johnrengelman.shadow' version '4.0.3'

1621592658534

(3)接着在 /src/main/java 目录处创建一个名为 burp 的包名,在 java 目录处右键 -> New -> Package,接着在该包上右键,新建一个名为 BurpExtender 的类。这里需要注意的是这个包名和类名是固定的,burpsuite 加载插件时就是通过 burp.BurpExtender 来查找的,如果不这样起名,会报 ClassNotFoundException 。

1.2 编写插件

在BurpExtender 中继承 IBurpExtender 接口,并实现registerExtenderCallbacks方法。(BurpExtender 类需要实现 IBurpExtender 接口,burp 在加载插件时,会调用该接口,并传递 IBurpExtenderCallbacks 接口仅我们使用。)registerExtenderCallbacks方法内添加下面的代码为插件设置名称,并打印一 success 字符串

callbacks.setExtensionName("data-collect2");
callbacks.printOutput("load success");

1621592834548

1.3 编译为jar包

点击右侧的 gradle 菜单,展开菜单,双击 shadowjar ,gradle 会自动编译项目成 jar 包,jar 包位于 build 目录中的 libs 目录中。 选中生成的jar包,右击show in exploer就可以得到我们的jar包

1621593085131

1.4 burpsuite 加载该jia包

在 burp 的扩展选项卡Extender->Extensions–>Add,选择Java类型,加载jar包点next就可以看到加载成功。

1621593214656

可以看到加载插件后成功打印了 success 字符串。

1621593371239

2 添加标签页

2.1 创建一个标签页:

(1)先在IDEA中创建一个 Form:file–>new–GUI Form,用于设计UI :在burp文件夹内如下图方式创建一个 DataCollectGUI.form

1621593462769

(2)创建的界面如下,左边的窗口中创建了两个文件,一个是 DataCollectGUI.java 文件,该文件与 form 文件绑定,一个是 DataCollectGUI.form 文件,可以在此文件上拖动控件来设计 UI 界面,当界面更新时,会自动生成代码插入 DataCollectGUI.java 文件中。 直接通过拖拉控件到面板即可完成UI设计。

1621593667153

2.2 打包GUI类

为了让 IDEA 打包 GUI 界面的类,需要在 build.gradle 添加以下依赖

compile('com.intellij:forms_rt:7.0.3')

(1)在设置中设置根据 Form 界面自动生成 Java 源码:file-settings->editor->GUI Designer–>java source code-apply-ok

1621594071138

(2)然后在 Gradle 的编译选项中设置编译器是 IDEA 自带的编译器,这样才能自动更新 form 文件中的控件到代码中:file-settings->Build,Execution,Deployment->Build Tools->Gradle:做如图的配置。

1621594242374

(3)构建项目

设置好后,点击构建图标,就会自动生成和 form 文件相关的代码,可以看到在 $$$setupUI$$$() 方法中自动生成了我们拖到界面中的3个控件。

1621836741981

接着需要回到 BurpExtender 类中,要为插件添加一个标签页,需要实现 ITab 接口:实现 ITab 接口后,会有两个方法需要实现,其中 getTabCaption() 方法返回标签页的名称, getUiComponent() 方法返回我们创建的 UI 面板。callbacks.addSuiteTab(this) 来注册接口。

1621837625674

2.3 设置按钮监听事件

接下来我们需要获取标签页中的配置内容,可以通过添加事件监听器来实现。回到 IDEA 的 form 文件中,在按钮上右键,点击 Create Listener,选择 ActionListener.在这里简单地把输入框中的内容打印在插件日志中,要把内容打印到插件日志中,我们需要获取 IBurpExtenderCallbacks 对象,可以修改构造函数,在初始化时传入:

1621837911606

还需要修改 BurpExtender 中的代码,传入 callbacks 对象

1621837935350

接着在监听器中实现获取标题内容并打印到日志的代码,代码中29行通过 getText()方法获取输入框架的内容,然后在30行处通过 callbacks.printOutput()方法打印内容到日志中。

2.4 打包jar

双击 gradle 中的 shadowjar 按钮重新打包 jar 包,然后在 burp 重新加载插件,在插件输入框中输入 12346849, 点击按钮,就会在插件日志中打印输入框中的内容了。

1621838299568

1621838343829

3 burpsuite的HTTP处理

开发burpsuite插件关键在于处理http请求和响应

3.1 查看包的报文信息

很多插件都是分析HTTP的请求包和响应包,去分析里面的内容实现某种功能。

HTTP相关处理主要是IHttpListener接口,他有个方法processHttpMessage用来处理HTTP消息,该方法有3个参数。其中toolflag表示burpsuite中流量的形式,比如通过代理,通过扫描等。具体对应值可以查看IBurpExtenderCallbacks接口,例如IBurpExtenderCallbacks.TOOL_PROXY表示代理流量;messageInfo表示HTTP交互报文,我们就通过初该值的处理得到HTTP的request和response报文,具体处理如下:

(1)Request分析

首先可以通过messageInfo.getRequest()获得整个请求报文,然后利用IRequestInfo类对报文进行分解,得到header, body,url等信息

public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
IRequestInfo analyzeRequest = helpers.analyzeRequest(messageInfo);//对Request消息进行解体
String request = new String(messageInfo.getRequest());
//获得请求的body
byte[] body = request.substring(analyzeRequest.getBodyOffset()).getBytes();
//获取请求头,返回header参数列表
List<String> headers = analyzeRequest.getHeaders();
//获取请求头的HTTP方法    
String method=analyzeRequest.getMethod();
//获取请求头的参数列表       
List<IParameter> Params=analyzeRequest.getParameters();
//获取请求头的URL 
URL url=analyzeRequest.getUrl();
&#125;

(2)response分析

首先直接调用messageInfo.getResponse()获取整个response完整报文,如果想要对response分结构的获取,例如获取response报文的header,body等,需要借助IRequestInfo类对报文进行分解

public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) &#123;
    byte[] response = messageInfo.getResponse();//获得response完整报文
    BurpExtender.stdout.println("Response:"+new String(response)); 
    //对Response消息进行解体
    IResponseInfo analyzeResponse = helpers.analyzeResponse(response);
    //获得执行的状态码
    int statusCode=analyzeResponse.getStatusCode();
    //获得header参数
    List<String> headers = analyzeResponse.getHeaders();
&#125;

3.2 修改包重发

有些插件的功能需要对交互包进行修改,重发,下面提供几个修改点的例子。

3.2.1 headers的CRUD,并发送新请求

(1)获得headers

IRequestInfo analyzeRequest = helpers.analyzeRequest(messageInfo);//对消息进行解体
//获取i请求头,返回header参数列表
List<String> headers = analyzeRequest.getHeaders();

(2)对header的CRUD

String xforward="X-Forwarded-For:127.0.0.1";
headers.add(xforward);

(3)重新发送改变后的header的请求

注意重新构建新的Request,这里采用的是buildHttpRequest方法。

try &#123;//重组请求信息
    //获得请求的body
    byte[] body = request.substring(analyzeRequest.getBodyOffset()).getBytes();
    byte[] newRequest=helpers.buildHttpMessage(headers,body);
    /*****************获取 http service**********************/
    IHttpService service = messageInfo.getHttpService();
    //重新发送request
    callbacks.makeHttpRequest(service, newRequest);
&#125; catch (MalformedURLException e) &#123;
    e.printStackTrace();
&#125;

2.2修改URL,然后发送新的请求

(1)获得原有URL

IRequestInfo analyzeRequest = helpers.analyzeRequest(messageInfo);//对消息进行解体
URL url = analyzeRequest.getUrl();

(2)构建新的URL: URL的CRUD

注意,URL的new最好再try catch中去做,不然会报错

String newUrlString = url.toString() + "djkslahf@w*5%oi";
URL newUrl;
try &#123;
     /*****************构建新的URL**********************/
    newUrl = new URL(newUrlString);
    BurpExtender.stdout.println("analyzeRequest.newUrl--new :" + newUrlString);
   &#125; catch (MalformedURLException e) &#123;
    e.printStackTrace();
&#125;

(3)重新发送改变后的URL的请求

注意重新构建新的Request,这里采用的是buildHttpRequest方法。

URL newUrl;
try &#123;
     /*****************构建新的URL**********************/

    /*****************获取 http service**********************/
    IHttpService service = messageInfo.getHttpService();
    /*****************发送一个新的请求**********************/
    byte[] newRequest = helpers.buildHttpRequest(newUrl);
    callbacks.makeHttpRequest(service, newRequest);
&#125; catch (MalformedURLException e) &#123;
    e.printStackTrace();
&#125;

2.3 修改body

3.3 重新构建包

需要借助IExtensionHelpers接口,创建该接口对象helpers。这里以如下包为例:

POST /api/v3/search/lucene/ HTTP/1.1
Host: vulners.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: https://vulners.com/
Content-Type: application/json
Origin: https://vulners.com
Content-Length: 246
Connection: close
Cookie: _ga=GA1.2.166747250.1624591605; _gid=GA1.2.443724840.1624591605; _gat=1

{
"query":"affectedSoftware.name:nginx AND affectedSoftware.version:\"1.17.7\"",
"fields":["cvss","description","id",]
}

(1)组建header

header包括Url cookie等信息

String VULNERS_API_HOST = "vulners.com";
String VULNERS_API_PATH = "/api/v3/search/lucene";//"/api/v3/burp/";
List<String> headers = new ArrayList<>();
headers.add("POST " + VULNERS_API_PATH  + "/ HTTP/1.1");
headers.add("Host: " + VULNERS_API_HOST);
headers.add("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0");
headers.add("Content-type: application/json");
headers.add("Cookie: xxxxxxx;");

(2)组建body

首先我们构造出Json结构的body,注意body里可以添加嵌套多层的json。

JSONObject jsonBody = new JSONObject();
// Map mapBody = new HashMap();
jsonBody.put("query", "affectedSoftware.name:"+SoftwareName+" AND affectedSoftware.version:\""+SoftwareVersion+"\"");
List<String> fields=new ArrayList<>();
fields.add("cvss");
fields.add("description");
fields.add("id");
jsonBody.put("fields",fields);

(3)发送新请求

首先使用buildHttpMessage重新构造新的request;再调用makeHttpRequest发送新的请求,获取响应值response。

byte[] request = helpers.buildHttpMessage(headers, helpers.stringToBytes(jsonBody.toString()));
byte[] response = callbacks.makeHttpRequest(VULNERS_API_HOST, 443, true, request);

(4)解析response

将resposne转化为json格式的报文object,就可以精确的取值啦

String responseString = helpers.bytesToString(response);
IResponseInfo iResponseInfo = helpers.analyzeResponse(response);
String jsonString = responseString.substring(iResponseInfo.getBodyOffset());
JSONObject object = JSONObject.parseObject(jsonString);

参考连接:

1.从头开发一个BurpSuite数据收集插件

2.burp插件开发基础一(JAVA篇)

3.官方插件编写示例

4官方编写插件博客

5.请求包的所有操作 超级推荐

6 如何编写自己的burpsuite

文章目录
  1. 1 一个小的bp插件Demo
    1. 1.1新建一个gradle项目
    2. 1.2 编写插件
    3. 1.3 编译为jar包
    4. 1.4 burpsuite 加载该jia包
  2. 2 添加标签页
    1. 2.1 创建一个标签页:
    2. 2.2 打包GUI类
    3. 2.3 设置按钮监听事件
    4. 2.4 打包jar
  3. 3 burpsuite的HTTP处理
    1. 3.1 查看包的报文信息
    2. 3.2 修改包重发
      1. 3.2.1 headers的CRUD,并发送新请求
      2. 2.2修改URL,然后发送新的请求
      3. 2.3 修改body
    3. 3.3 重新构建包