freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

Burp插件编写(详细教程)——基于2023新版接口
景_ 2025-03-05 18:29:30 118027
所属地 海外

一 概述

经常在渗透过程中,遇到一些要手动尝试的payload,比较麻烦,于是想学习一下burp插件的开发。2023年后Burp对插件的接口进行了更新,在网上看了很多开源插件都是基于旧版本api,并且网上没有特别详细的文章,对于初学者摸索很是头疼。

Burp Suite支持的插件类型有Java、Python、Ruby,我们选择最常见的Java来写(选择自己最熟悉的语言即可)

官方的api接口说明地址:

https://portswigger.github.io/burp-extensions-montoya-api/javadoc/index.html

二 官方实例

1 构建

官方提供了一个使用的案例:

https://github.com/PortSwigger/burp-extensions-montoya-api-examples/tree/main/customlogger

我们先使用这个案例看看

把这三个文件下载下来

1740654462_67c0477e3d01f16327408.png!small?1740654439398

然后IDEA新建一个项目,这边直接创建一个java普通项目即可,我的bp 2023.10用的是JDK 17

1740654777_67c048b9eaaa6a90fa8d2.png!small?1740654754966

打开我们的burp,找到插件 APIs的位置,保存接口文件,导出到我们刚刚创建项目的src目录下

1740738118_67c18e46eaf6c256034e4.png!small?1740738095583

并且把刚刚官方的样例也放过来,结构如下:

1740655098_67c049fa475fd7b422b4d.png!small?1740655075101

然后在项目结构这边添加一个jar的工件,并且build一下,打包的jar就在out目录下

1740655215_67c04a6fd62f84d463726.png!small?1740655192770

1740655314_67c04ad2f0892b8ff2b7d.png!small?1740655291927

然后去Burp添加一下插件你就可以看到这样一个页面

1740655585_67c04be18c5b40207ae87.png!small?1740655562358

并且我们随便抓两个包就可以看到

1740659982_67c05d0ec0acd9ceb222a.png!small?1740659959609

这个就是官方给出的一个简单的Demo,接下来我们分析一下这个demo做了什么

2 CustomLogger

首先看一眼官方文档,对于BurpExtension,所有的扩展都需要实现此接口,这个接口实际就是Burp插件启动的地方

1740655736_67c04c780c7a3b17a103f.png!small?1740655713038

1740657290_67c0528a98080ab8b29c0.png!small?1740657267593

并且这个接口需要重写一个initialize方法,这个方法会在加载扩展时调用。只有在此方法完成后,才会启用任何已注册的处理程序,这个initialize方法还接受一个MontoyaApi参数,Burp Suite使用此接口将一组方法传递给扩展,这些扩展可用于在Burp中执行各种操作,也就是说调用其他扩展是直接使用这个MontoyaApi。那么我们的主体部分就在initialize方法中实现,即官方代码这样:

1740655849_67c04ce96cf56301d87e0.png!small?1740655826305

下面是剩下几行的解释,其中tableModel 其实就是我们在插件中看到的上半部分,registerSuiteTab方法进行注册一个标签页,也就是建立UI视图,这个方法的第二个参数将在自定义选项卡中呈现的组件,示例代码中使用constructLoggerTab去创建一个组件

//设置插件的名称
api.extension().setName("Custom logger");

//用于管理表格数据
MyTableModel tableModel = new MyTableModel();

//方法向 Burp 的用户界面注册一个新的标签页
api.userInterface().registerSuiteTab("Custom logger", constructLoggerTab(tableModel));

//注册一个 HTTP 请求处理器,当 HTTP 请求和响应通过 Burp 时,MyHttpHandler 会调用其方法来处理数据
api.http().registerHttpHandler(new MyHttpHandler(tableModel));

下面的部分就是通过Swing UI的方式创建UI视图了,重要的是下面这段代码

//获取 Burp 提供的用户界面 API 对象,用于创建 UI 组件
UserInterface userInterface = api.userInterface(); //创建 HTTP 请求和响应编辑器 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){ @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); super.changeSelection(rowIndex, columnIndex, toggle, extend); } };

这里的requestViewer和responseViewer就是视图UI下面的Request和Reponse那个,就是这个

1740659671_67c05bd7bcf1a1b6b42d6.png!small?1740659648508

3 MyTableModel

然后再来看一下MyTableModel,在上面的时候已经将这个MyTableModel创建出来并且放到了UI界面中,简单看一下这个里面的几个方法

这三个方法

1740659475_67c05b133bd0018719b38.png!small?1740659452274

分别对应于这个地方的Tool和URL,所以不难猜出,getColumnCount和getColumnName的返回值应该分别就是列的数量和上面的标签,而这个getValueAt其实就是每列下面要展示的值

1740659940_67c05ce4deedefe72b467.png!small?1740659917653

4 MyHttpHandler

在MyHttpHandler中,重写两个方法,handleHttpRequestToBeSent和handleHttpResponseReceived,根据官方文档,这两个方法可以处理发送的请求和响应

并且在handleHttpResponseReceived中有这个一个玩意,做的其实就是把请求和响应数据添加到tableModel中(上面的每一行中)

tableModel.add(responseReceived);

三 其他API接口说明

这里再简单介绍几个其他API接口

1 logging()

我们在initialize()中添加这么两行,然后重build一下jar包,删除旧插件重新安装一下


api.logging().logToOutput("Hello World");
api.logging().logToError("Hello Error");

1740660171_67c05dcb7bfd032fcb42b.png!small?1740660148328



你将会看到

1740660981_67c060f50f3784d43ed4a.png!small?1740660958755

1740660981_67c060f50f993d5482080.png!small?1740660958757

那么明了,这两个接口就是在Show in UI中输出信息,调试的时候用这个会很方便

2 HttpRequest

这里的话我们修改一下MyHttpHandler的构造方法,将最重要的MontoyaApi api也传进来

这里responseReceived接口中initiatingRequest()方法可以对根据这个请求获取到对应的方法,

然后我们可以使用api.http().sendRequest去发送请求

1740660981_67c060f58773000918246.png!small?1740660958759

在httpRequest中可以看到很多对于请求进行修改的方法,这样我们可以对我们的请求进行修改,插入我们的payload之类

1740660981_67c060f5915216a3170a6.png!small?1740660958761

让AI提取的文档解释

boolean isInScope();
功能:检查请求是否处于 Burp 的目标范围内。
使用场景:用于过滤或标记请求,以便用户专注于范围内的目标。
HttpService httpService();
功能:返回请求的 HTTP 服务对象,包含目标主机、端口和协议信息等。
URL and Method Information
String url();
功能:返回请求的完整 URL。
可能异常:如果请求格式不正确,会抛出 MalformedRequestException。
String method();
功能:返回请求的 HTTP 方法(如 GET、POST)。
可能异常:如果请求格式不正确,会抛出 MalformedRequestException。
String path();
功能:返回请求路径,包括查询参数。
可能异常:如果请求格式不正确,会抛出 MalformedRequestException。
String pathWithoutQuery();
功能:返回请求路径,不包含查询参数。
可能异常:如果请求格式不正确,会抛出 MalformedRequestException。
Content Type
ContentType contentType();
功能:返回请求的 Content-Type。
Parameters
List<ParsedHttpParameter> parameters();
功能:返回请求中的所有 HTTP 参数。
List<ParsedHttpParameter> parameters(HttpParameterType type);
功能:根据指定的参数类型过滤参数(如 URL 参数、POST 参数等)。
boolean hasParameters();
功能:判断请求中是否有参数。
boolean hasParameters(HttpParameterType type);
功能:判断请求中是否有指定类型的参数。
ParsedHttpParameter parameter(String name, HttpParameterType type);
功能:返回与指定名称和类型的参数对应的 ParsedHttpParameter 对象,如果没有找到则返回 null。
String parameterValue(String name, HttpParameterType type);
功能:返回指定名称和类型的参数的值,如果没有找到则返回 null。
boolean hasParameter(String name, HttpParameterType type);
功能:检查是否存在具有指定名称和类型的参数。
boolean hasParameter(HttpParameter parameter);
功能:检查是否存在与提供的 HttpParameter 对象匹配的参数。
Headers
boolean hasHeader(HttpHeader header);
功能:检查请求中是否包含指定的 HttpHeader。
boolean hasHeader(String name);
功能:检查请求中是否包含具有指定名称的头部。
boolean hasHeader(String name, String value);
功能:检查请求中是否包含具有指定名称和值的头部。
HttpHeader header(String name);
功能:返回具有指定名称的 HttpHeader 对象,如果没有找到则返回 null。
String headerValue(String name);
功能:返回具有指定名称的头部的值,如果没有找到则返回 null。
List<HttpHeader> headers();
功能:返回请求中的所有 HTTP 头部。
HTTP Version
String httpVersion();
功能:返回 HTTP 请求或响应的版本字符串(如 "HTTP/1.1" 或 "HTTP/2")。
Body
int bodyOffset();
功能:返回请求体在消息中的偏移量。
ByteArray body();
功能:返回请求体的字节数组。
String bodyToString();
功能:返回请求体的字符串表示。
Markers
List<Marker> markers();
功能:返回请求中的标记列表。
Search and Contains
boolean contains(String searchTerm, boolean caseSensitive);
功能:检查消息中是否包含指定的搜索字符串,可以选择是否区分大小写。
boolean contains(Pattern pattern);
功能:检查消息中是否包含符合指定正则表达式的部分。
General Message Information
ByteArray toByteArray();
功能:将整个 HTTP 请求消息转换为字节数组。
String toString();
功能:返回 HTTP 请求的字符串表示。
Utilities
HttpRequest copyToTempFile();
功能:将 HttpRequest 对象复制到临时文件中,并返回新的 HttpRequest 对象。
HttpRequest withService(HttpService service);
功能:返回一个新的 HttpRequest,其中 HTTP 服务信息已更新。
HttpRequest withPath(String path);
功能:返回一个新的 HttpRequest,其中路径信息已更新。
HttpRequest withMethod(String method);
功能:返回一个新的 HttpRequest,其中 HTTP 方法已更新。
Header Manipulation
HttpRequest withHeader(HttpHeader header);
功能:如果头部存在则更新,否则添加。
HttpRequest withHeader(String name, String value);
功能:如果头部存在则更新,否则添加。
HttpRequest withAddedHeader(String name, String value);
功能:添加新的 HTTP 头部。
HttpRequest withAddedHeader(HttpHeader header);
功能:添加新的 HTTP 头部。
HttpRequest withUpdatedHeader(String name, String value);
功能:更新具有指定名称的头部的值。
HttpRequest withUpdatedHeader(HttpHeader header);
功能:更新指定的头部。
HttpRequest withRemovedHeader(String name);
功能:移除具有指定名称的头部。
HttpRequest withRemovedHeader(HttpHeader header);
功能:移除指定的头部。
Body Manipulation
HttpRequest withBody(String body);
功能:更新请求体的字符串内容。
HttpRequest withBody(ByteArray body);
功能:更新请求体的字节数组内容。
Parameter Manipulation
HttpRequest withParameter(HttpParameter parameters);
功能:如果参数存在则更新,否则添加。
HttpRequest withAddedParameters(List<? extends HttpParameter> parameters);
功能:添加多个 HTTP 参数。
HttpRequest withAddedParameters(HttpParameter... parameters);
功能:添加多个 HTTP 参数。
HttpRequest withRemovedParameters(List<? extends HttpParameter> parameters);
功能:移除多个 HTTP 参数。
HttpRequest withRemovedParameters(HttpParameter... parameters);
功能:移除多个 HTTP 参数。
HttpRequest withUpdatedParameters(List<? extends HttpParameter> parameters);
功能:更新多个 HTTP 参数。
HttpRequest withUpdatedParameters(HttpParameter... parameters);
功能:更新多个 HTTP 参数。
Transformation
HttpRequest withTransformationApplied(HttpTransformation transformation);
功能:应用指定的转换并返回新的 HttpRequest。
Default Headers
HttpRequest withDefaultHeaders();
功能:添加默认的 HTTP 头部。
Markers
HttpRequest withMarkers(List<Marker> markers);
功能:返回一个新的 HttpRequest,其中标记已更新。
HttpRequest withMarkers(Marker... markers);
功能:返回一个新的 HttpRequest,其中标记已更新。
Static Methods
static HttpRequest httpRequest();
功能:创建一个新的空 HttpRequest 对象。
static HttpRequest httpRequest(ByteArray request);
功能:从字节数组创建 HttpRequest。
static HttpRequest httpRequest(String request);
功能:从字符串创建 HttpRequest。
static HttpRequest httpRequest(HttpService service, ByteArray request);
功能:从 HTTP 服务和字节数组创建 HttpRequest。
static HttpRequest httpRequest(HttpService service, String request);
功能:从 HTTP 服务和字符串创建 HttpRequest。
static HttpRequest httpRequestFromUrl(String url);
功能:从 URL 创建 HttpRequest。
static HttpRequest http2Request(HttpService service, List<HttpHeader> headers, ByteArray body);
功能:创建 HTTP/2 请求。
static HttpRequest http2Request(HttpService service, List<HttpHeader> headers, String body);
功能:创建 HTTP/2 请求。

比如我们可以通过下面这样修改请求路径为自定义的"/"+path,修改请求方法为GET(这里不能写Get,花了半天时间才发现的错误点,踩坑踩坑),并且修改请求的bady为空

httpRequest.withPath("/"+path).withMethod("GET").withBody("");

通过HttpRequest.withAddedHeader("X-Forwarded-For", "127.0.0.1")对请求添加一个请求头

3 HttpReponse

我们还需要根据返回包来判断我们的payload是否有效,HttpReponse下提供了对应的方法

1740661687_67c063b7baea39c0bc3bf.png!small?1740661664799

比如可以通过httpResponse.statusCode()获取响应值,通过httpResponse.bodyToString().contains("Whitelabel Error Page")来判断是否包含特定的响应信息

4 DNS平台

创建一个collaboratorClient ,其实就相关与我们在Bp中使用collaborator点击Get Start


CollaboratorClient collaboratorClient = montoyaApi.collaborator().createClient();

1740662069_67c065350edd87a9f970b.png!small?1740662045883

generatePayload()获取一个dns域名

String dnsDomain = collaboratorClient.generatePayload().toString();

根据dns域名获取到对应的记录数组,如果数组不为空,那么可以判断该dns被请求(这里编写的时候,payload发起请求后,先暂停两秒,防止太快而获取不到解析记录)

List<Interaction> interactions = collaboratorClient.getInteractions(InteractionFilter.interactionPayloadFilter(dnsDomain));

5 其他

这里还有一个常用,下面的两句分别判断httpResponseReceived是否来自代理或者重放,这样可以过滤其他模块的请求,放在太多无用请求


httpResponseReceived.toolSource().isFromTool(ToolType.PROXY);
httpResponseReceived.toolSource().isFromTool(ToolType.REPEATER);

在写插件的过程中,我们还会遇到的是修改之后的请求如何添加到tableModel中,这里的解决方式是,我们自己包装一个方法,在HttpHandler类和tableModel中传递这个封装的方法,而非直接使用responseReceived

1740662678_67c067965528f3301242c.png!small?1740662655251




自己初步刚刚完成的小插件,恳请大佬指点

https://github.com/Jingyi-u/SimpleScan-Burp

推荐阅读

https://github.com/Maskhe/FastjsonScan

https://github.com/saoshao/DetSql

# 漏洞 # 渗透测试 # 网络安全 # web安全 # 网络安全技术
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 景_ 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
景_ LV.2
这家伙太懒了,还未填写个人描述!
  • 10 文章数
  • 8 关注者
Java RASP简单实现
2024-11-07
Behinder 冰蝎源码阅读与去特征浅析
2024-11-01
SubFinder子域枚举源码结构分析
2024-10-30
文章目录