forked from chris1201/WooYun
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BurpSuite插件开发指南之 Java 篇.html
454 lines (338 loc) · 128 KB
/
BurpSuite插件开发指南之 Java 篇.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
<html>
<head>
<title>BurpSuite插件开发指南之 Java 篇 - Her0in</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<h1>原文地址:<a href="http://drops.wooyun.org/tools/16056">http://drops.wooyun.org/tools/16056</a></h1>
<p>
<p>此文接着 <a href="http://drops.wooyun.org/tools/14685">《BurpSuite插件开发指南之 API 下篇》</a> 。在此篇中将会介绍如何使用Java 开发 BurpSuite 的插件,重点会介绍利用 Java 的 Swing 包开发带有 GUI 的 Burp 插件。</p>
<p>《BurpSuite 插件开发指南》系列文章如下:</p>
<ul>
<li><a href="http://drops.wooyun.org/tools/14040">《BurpSuite插件开发指南之 API 篇》</a></li>
<li>《BurpSuite插件开发指南之 Java 篇》</li>
<li>《BurpSuite插件开发指南之 Python 篇》</li>
</ul>
<p>注:此系列文章是笔者利用业余时间所写,如有错误,望读者们及时指正,另外此系列文章属于入门级别的科普文,目的是普及Burp插件的编写技术。</p>
<!--more-->
<h1>0x00 Java 接口简介</h1>
<hr />
<p>知其然更要知其所以然。在真正动手编写 Burp 插件之前,有必要对Burp提供的各个接口有一定的了解,同时要有一定的编程经验和能力。那么,在此篇中读者则有必要了解 Java 的接口技术。</p>
<p>接口(英文:Interface)在 Java 编程语言中是一个比较抽象的东西。熟悉 OOP 的同学可以用“类”的思想来理解接口。但是,要明白的是,类与接口有相似的地方同时也有很多不同的地方。</p>
<h2>接口的声明</h2>
<p>接口的声明语法格式如下:</p>
<pre><code>#!java
[可见度] interface 接口名称 [extends 其他的类名] {
// 声明变量
// 抽象方法
}
</code></pre>
<p>例如,Burp 的 接口声明原型如下:</p>
<pre><code>#!java
package burp;
public interface IBurpExtender
{
void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks);
}
</code></pre>
<h2>接口的实现</h2>
<p>一个接口可以被另外一个接口继承,也可以被一个类实现。当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。不熟悉Java编程的读者要牢记这几点。</p>
<p>实现一个接口的语法如下:</p>
<pre><code>#!java
... implements 接口名称[, 其他接口1, 其他接口2..., ...] ...
</code></pre>
<p>例如,编写 Burp 插件必须编写的 BurpExtender 类实现 IBurpExtender 和 IProxyListener 接口代码如下:</p>
<pre><code>#!java
package burp;
public class BurpExtender implements IBurpExtender, IProxyListener{
// 实现 IBurpExtender 接口的 registerExtenderCallbacks 方法
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
// TODO here
}
// 实现 IProxyListener 接口的 processProxyMessage 方法
@Override
public void processProxyMessage(boolean messageIsRequest,
IInterceptedProxyMessage message) {
// TODO here
}
}
</code></pre>
<p>需要注意的是,在Burp提供的接口文档中,并不是所有的接口都可以用类实现,只有在接口的描述中说明了“该接口可以被实现”时,所对应的接口才可以被你所编写的类实现其方法。</p>
<h1>0x01 Java Swing 和 AWT 包简介</h1>
<hr />
<p>Java Swing 是 Java Foundation Classes(JFC)的一部分。在 Swing 中,包含了很多强大灵活的,跨平台的 GUI 控件。Swing 组件遵循(MVC)模型 - 视图 - 控制器架构,并提供了三个通用的顶层容器类 JFrame,JDialog 和 JApplet。在开发带有 GUI 的 BurpSuite 插件时,一般不会直接用到这三个顶层容器类,具体要看个人的设计和需求。</p>
<p>下面是一些最常用的控件:</p>
<ul>
<li>JLabel 标签控件,JLabel 的对象是在容器中放置一个文本标签。</li>
<li>JButton 按钮控件。</li>
<li>JColorChooser 颜色选择控件,用于让用户操作和选择颜色。</li>
<li>JCheckBox 选择框控件,支持分组。</li>
<li>JRadioButton 单选框控件,支持分组。</li>
<li>JList 列表控件。</li>
<li>JComboBox 组合框控件。</li>
<li>JTextField 文本框控件。</li>
<li>JPasswordField 密码输入框控件。</li>
<li>JTextArea 多行文本控件。</li>
<li>ImageIcon 绘制图标的控件。</li>
<li>JScrollbar 滚动条控件,支持水平和垂直滚动。</li>
<li>JFileChooser 选择文件对话框。</li>
<li>JProgressBar 进度条控件。</li>
<li>JPanel 面板控件,此控件在开发插件时会经常用到。</li>
</ul>
<p>Swing 是在 AWT 的基础上构建的一套新的图形界面系统,所以 AWT 是 Java 实现图形界面的基础,图形控件的事件监听和响应也是由 AWT 完成的。不过,编写 Burp 插件所用到的图形组件和事件并不多,很容易上手。</p>
<p>有关更多 GUI 组件的知识,请读者自行百度了解。在此不做过多阐述。</p>
<h1>0x02 自定义 Burp UI 标签</h1>
<hr />
<p>编写 GUI 的 Burp 插件在实际使用时更加易于操作和表达信息。当然,编写起来也十分简单,只需遵循一定的“套路”,就可以了。</p>
<p>最终编写好的基本的样式如下图所示:</p>
<p><img src="http://static.wooyun.org//drops/20160525/2016052513193014611burp_tab.jpg" alt="" /></p>
<p>代码如下:</p>
<pre><code>#!java
/*
* BurpSuite 插件开发指南之 Java 篇
* writend by Her0in
*/
package burp;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class BurpExtender implements IBurpExtender, ITab{
public PrintWriter stdout;
public IExtensionHelpers hps;
public IBurpExtenderCallbacks cbs;
public JPanel jPanelMain;
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
callbacks.setExtensionName("BurpExtender");
this.hps = callbacks.getHelpers();
this.cbs = callbacks;
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.stdout.println("hello burp!");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jPanelMain = new JPanel();
JButton jButton = new JButton("老司机,快点我!");
jButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e){
stdout.println("哔...");
}
});
// 将按钮添加到 主面板 jPanelMain 中.
jPanelMain.add(jButton);
// 设置自定义组件并添加标签
cbs.customizeUiComponent(jPanelMain);
cbs.addSuiteTab(BurpExtender.this);
}
});
}
// 实现 ITab 接口的 getTabCaption 方法
@Override
public String getTabCaption() {
return "Burp 标签测试";
}
// 实现 ITab 接口的 getUiComponent 方法
@Override
public Component getUiComponent() {
return jPanelMain;
}
}
</code></pre>
<p>从上述代码中,读者也能够看到,Java 的 Swing 图形编程有点蛋疼,需要一层层的编写。首先需要添加一个 JPanel 上去,然后在这个 JPanel 中再添加图形组件,如果还有上层的图形组件,则需要再添加一个 Panel 类型的控件。</p>
<p>在这里有一个比较快速编写 Burp GUI插件的方法,先利用 NetBeans IDE 将图形界面拖拽式的写好,然后将上述显示控件的代码替换为显示这个 JFrame 的代码。之后编写相关的事件响应代码。</p>
<h1>0x03 BurpSuite插件开发实例之 JSON 水坑 检测插件</h1>
<hr />
<p>本小节,笔者将会使用一个实例来“抛砖引玉”式的描述编写带有 GUI 的 Burp 插件。读者可以把关注点放在图形控件的放置顺序和事件处理上,可以无视 JSON 水坑检测的逻辑是否严谨以及误报率,准确率是否科学等问题。</p>
<p>最终编写好的插件如下图:</p>
<p><img src="http://static.wooyun.org//drops/20160525/2016052513192985524burp_json.jpg" alt="" /></p>
<p>顶部的控件是一个表格列表控件,会放置检测到的结果。下面两个 ITextEditor 分别显示当前 HTTP 数据包的请求信息和响应信息。</p>
<p>代码就直接贴出来吧,如下:</p>
<pre><code>#!java
/*
* BurpSuite 插件开发指南之 Java 篇
* writend by Her0in
*/
package burp;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.io.PrintWriter;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
public class BurpExtender implements IBurpExtender, ITab, IHttpListener{
public PrintWriter stdout;
public IExtensionHelpers hps;
public IBurpExtenderCallbacks cbs;
public IRequestInfo iRequestInfo;
public IResponseInfo iResponseInfo;
public JPanel jPanel_top;
public JTabbedPane jTabbedPane;
public JScrollPane jScrollPane;
public JSplitPane jSplitPaneV;
// 自己封装一个 Table 控件
private Her0inTable jsonTable;
//请求,响应信息显示
public JPanel jPanel_reqInfo_left;
public JPanel jPanel_respInfo_right;
public JSplitPane jSplitPaneInfo;
public ITextEditor iRequestTextEditor;
public ITextEditor iResponseTextEditor;
Boolean bFind = false;
String strTags = "";
@Override
public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
callbacks.setExtensionName("JSON 水坑检测");
this.hps = callbacks.getHelpers();
this.cbs = callbacks;
this.stdout = new PrintWriter(callbacks.getStdout(), true);
this.stdout.println("hello burp!");
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// 初始化垂直分隔面板
jSplitPaneV = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
jSplitPaneV.setDividerLocation(0.5);
jSplitPaneV.setOneTouchExpandable(true);
// 垂直分隔面板的顶部
jPanel_top = new JPanel();
// 设置垂直分隔面板顶部的子控件
// 放置表格控件
jTabbedPane = new JTabbedPane();
// 初始化 Burp 提供的 ITextEditor 编辑器接口
iRequestTextEditor = cbs.createTextEditor();
iRequestTextEditor.setEditable(false);
iResponseTextEditor = cbs.createTextEditor();
iResponseTextEditor.setEditable(false);
// 初始化 jsonTable
jsonTable = new Her0inTable(iRequestTextEditor, iResponseTextEditor, stdout);
// 最好放置一个 JScrollPane
JScrollPane jScrollPane1 = new JScrollPane(jsonTable.getTab());
jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
jTabbedPane.scrollRectToVisible(new Rectangle(500, 70));
jTabbedPane.addTab("JSON 水坑检测", jScrollPane1);
jScrollPane = new JScrollPane(jTabbedPane);
jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
jPanel_top.add(jScrollPane, BorderLayout.CENTER);
jPanel_top.setLayout(null);
// 添加componentResized事件 否则在改变Burp 主窗口大小时会错位
jPanel_top.addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {
}
@Override
public void componentResized(ComponentEvent e) {
if(e.getSource() == jPanel_top){
jScrollPane.setSize(jPanel_top.getSize().width - 5,
jPanel_top.getSize().height - 5);
jScrollPane.setSize(jPanel_top.getSize().width - 10,
jPanel_top.getSize().height - 10);
}
}
@Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
});
// 设置垂直分隔面板底部的子控件
// 显示请求/响应 信息的水平分隔面板初始化
jSplitPaneInfo = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
jSplitPaneInfo.setDividerLocation(0.5);
jSplitPaneInfo.setOneTouchExpandable(true);
// 初始化 请求,响应信息显示 面板
jPanel_reqInfo_left = new JPanel();
jPanel_respInfo_right = new JPanel();
jPanel_reqInfo_left.setLayout(new BorderLayout());
jPanel_respInfo_right.setLayout(new BorderLayout());
// 将 Burp 提供的 ITextEditor 编辑器 添加到请求,响应信息显示 面板中
jPanel_reqInfo_left.add(iRequestTextEditor.getComponent(),
BorderLayout.CENTER);
jPanel_respInfo_right.add(iResponseTextEditor.getComponent(),
BorderLayout.CENTER);
// 分别添加 请求,响应信息显示 面板 到 垂直分隔面板底部
jSplitPaneInfo.add(jPanel_reqInfo_left, JSplitPane.LEFT);
jSplitPaneInfo.add(jPanel_respInfo_right, JSplitPane.RIGHT);
// 最后,为垂直分隔面板添加顶部面板和水平分隔面板
jSplitPaneV.add(jPanel_top, JSplitPane.TOP);
jSplitPaneV.add(jSplitPaneInfo, JSplitPane.BOTTOM);
// 设置自定义组件并添加标签
cbs.customizeUiComponent(jSplitPaneV);
cbs.addSuiteTab(BurpExtender.this);
}
});
callbacks.registerHttpListener(this);
}
// 实现 ITab 接口的 getTabCaption 方法
@Override
public String getTabCaption() {
return "JSON 水坑检测";
}
// 实现 ITab 接口的 getUiComponent 方法
@Override
public Component getUiComponent() {
return jSplitPaneV;
}
public void CheckJson(IHttpRequestResponse messageInfo) {
try {
this.iRequestInfo = this.hps.analyzeRequest(messageInfo);
this.iResponseInfo = this.hps.analyzeResponse(messageInfo.getResponse());
} catch (Exception e) {
return ;
}
// stdout.println(messageInfo.getHttpService().getHost());
this.bFind = false;
java.util.List<IParameter> listIParameters = iRequestInfo.getParameters();
strTags = "";
for (IParameter param : listIParameters) {
String strName = param.getName().toLowerCase();
if(strName.indexOf("callback") != -1 || strName.indexOf("_callback") !=-1 ||
strName.indexOf("cb") !=-1 || strName.indexOf("_cb") != -1 ||
strName.indexOf("huidiao") !=-1 ){
strTags += "# find => " + strName;
this.bFind = true;
}
}
if(this.bFind){
Vector<String> vectorRow = new Vector<String>();
vectorRow.addElement(new String(Integer.toString(jsonTable.defaultTableModel.getRowCount())));
vectorRow.addElement(new String(this.iRequestInfo.getUrl().getHost()));
vectorRow.addElement(new String(this.iRequestInfo.getMethod()));
if(this.iRequestInfo.getUrl().getQuery() != null){
vectorRow.addElement(new String(this.iRequestInfo.getUrl().getPath() + "?" + this.iRequestInfo.getUrl().getQuery()));
}else{
vectorRow.addElement(new String(this.iRequestInfo.getUrl().getPath()));
}
vectorRow.addElement(new String(strTags));
jsonTable.defaultTableModel.addRow(vectorRow);
jsonTable.iHttpList.add(messageInfo);
}
}
@Override
public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {
if (!messageIsRequest) {
//JSON 检测
this.CheckJson(messageInfo);
}
}
}
</code></pre> </p>
</body>
</html>