本人从0开始,写一个bp的开发教程,思路为:跟着教程搭建出一个可以用在burpsuite的插件,然后在此基础上构建一个由GUI的插件,后面进一步去熟悉插件相关的API函数。本文教程基于gradle项目,因为方便引言一些插件库。
1 一个小的bp插件Demo
1.1新建一个gradle项目
(1)新建一个gradle项目,项目名为:burp-detect-nginx
(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'
(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");
1.3 编译为jar包
点击右侧的 gradle 菜单,展开菜单,双击 shadowjar ,gradle 会自动编译项目成 jar 包,jar 包位于 build 目录中的 libs 目录中。 选中生成的jar包,右击show in exploer就可以得到我们的jar包
1.4 burpsuite 加载该jia包
在 burp 的扩展选项卡Extender->Extensions–>Add,选择Java类型,加载jar包点next就可以看到加载成功。
可以看到加载插件后成功打印了 success 字符串。
2 添加标签页
2.1 创建一个标签页:
(1)先在IDEA中创建一个 Form:file–>new–GUI Form,用于设计UI :在burp文件夹内如下图方式创建一个 DataCollectGUI.form
(2)创建的界面如下,左边的窗口中创建了两个文件,一个是 DataCollectGUI.java 文件,该文件与 form 文件绑定,一个是 DataCollectGUI.form 文件,可以在此文件上拖动控件来设计 UI 界面,当界面更新时,会自动生成代码插入 DataCollectGUI.java 文件中。 直接通过拖拉控件到面板即可完成UI设计。
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
(2)然后在 Gradle 的编译选项中设置编译器是 IDEA 自带的编译器,这样才能自动更新 form 文件中的控件到代码中:file-settings->Build,Execution,Deployment->Build Tools->Gradle:做如图的配置。
(3)构建项目
设置好后,点击构建图标,就会自动生成和 form 文件相关的代码,可以看到在 $$$setupUI$$$() 方法中自动生成了我们拖到界面中的3个控件。
接着需要回到 BurpExtender 类中,要为插件添加一个标签页,需要实现 ITab 接口:实现 ITab 接口后,会有两个方法需要实现,其中 getTabCaption() 方法返回标签页的名称, getUiComponent() 方法返回我们创建的 UI 面板。callbacks.addSuiteTab(this) 来注册接口。
2.3 设置按钮监听事件
接下来我们需要获取标签页中的配置内容,可以通过添加事件监听器来实现。回到 IDEA 的 form 文件中,在按钮上右键,点击 Create Listener,选择 ActionListener.在这里简单地把输入框中的内容打印在插件日志中,要把内容打印到插件日志中,我们需要获取 IBurpExtenderCallbacks 对象,可以修改构造函数,在初始化时传入:
还需要修改 BurpExtender 中的代码,传入 callbacks 对象
接着在监听器中实现获取标题内容并打印到日志的代码,代码中29行通过 getText()方法获取输入框架的内容,然后在30行处通过 callbacks.printOutput()方法打印内容到日志中。
2.4 打包jar
双击 gradle 中的 shadowjar 按钮重新打包 jar 包,然后在 burp 重新加载插件,在插件输入框中输入 12346849, 点击按钮,就会在插件日志中打印输入框中的内容了。
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();
}
(2)response分析
首先直接调用messageInfo.getResponse()获取整个response完整报文,如果想要对response分结构的获取,例如获取response报文的header,body等,需要借助IRequestInfo类对报文进行分解
public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
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();
}
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 {//重组请求信息
//获得请求的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);
} catch (MalformedURLException e) {
e.printStackTrace();
}
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 {
/*****************构建新的URL**********************/
newUrl = new URL(newUrlString);
BurpExtender.stdout.println("analyzeRequest.newUrl--new :" + newUrlString);
} catch (MalformedURLException e) {
e.printStackTrace();
}
(3)重新发送改变后的URL的请求
注意重新构建新的Request,这里采用的是buildHttpRequest方法。
URL newUrl;
try {
/*****************构建新的URL**********************/
/*****************获取 http service**********************/
IHttpService service = messageInfo.getHttpService();
/*****************发送一个新的请求**********************/
byte[] newRequest = helpers.buildHttpRequest(newUrl);
callbacks.makeHttpRequest(service, newRequest);
} catch (MalformedURLException e) {
e.printStackTrace();
}
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);
参考连接:
5.请求包的所有操作 超级推荐