
burpsuite是一款非常好用的抓包工具,我自己也是重度用户,所以就上手了burpsuite的插件接口开发,本文主要记录了一个解密请求包,插入payload,再加密的插件开发过程,插件应用场景主要是用于通过分析apk的实现。这里做探讨的目的只是方便安全测试人员的个人学习,或大家渗透测试使用。
详细的代码见github代码,在文档中数据首先是以rsa方式加密des的key得到encryptKey,然后使用des的key加密数据包得到data,再组装成一个JSON格式串,这是加密过程,当然解密过程就是逆向的。插件应用场景主要是用于通过分析apk的实现,或者泄露的密钥,获取其加解密算法,在解密后的数据包中插入payload,发现注入问题等。
如下则是加密后的数据包:
c={
"data":"21BhviedgtbwK6rdlK7vzltqxOLxUmU2g5qaO5LWPYTha5fXslmL6jrMkFnJBwpZPZMNl5foxTUHw2Mae++zkWwtzWkKXI9WJ/CJqxO9uORT5I6iUmIG7bBcgnHpmlSNKfFwBvnr9vj3v5ByvW2s2/pL9rSaeD+/8XsX01NA96mC4g5pVBeU5IY9F4tdxH9yobXfN6GzEVhLeiEd30xzMA\u003d\u003d",
"encryptKey":"bjWZgigAW/ZaAA55v7Yi9AGt2qsP7BfZZISu70qc/xVUVfh5L/Mw/mMbzxkcZ6uXb1vvgXvF7hHYwjsVzvEkRK0rIfIwkcYzn160fvQ/8+F8YBMDLzTEhf8r0KjOLlJV+HgOsS4QG/G9lOU5mnupfrVA9sf54b3OvXHU0TQVG7U\u003d"
}
从数据库包能看到大的数据是一个json格式,里面有data,和encryptKey值,encryptKey就是使用RSA加密des 的key得到的,RSA的工作方式和pem文件可通过界面设置,再接着用这个key采用des方式解密data中的内容。操作界面如下:
2,InsertPoint 接口
InsertPoint顾名思义就是注入点,就是payload插入的地方,比如request中的cookie,参数等位置。为了对一些burpsuite不支持的参数格式进行支持就必须实现该接口,可以用在Active Scanner和Intruder中.
2.1 基础开发知识
最好的方式就是在原有插件的基础上修改,这样能省很多精力,当然如果要一步一步来的话,步骤如下:
(1)包含burp的接口文件
(2)创建一个包名为burp,在里面创建BurpExtender类,实现IBurpExtender接口,这个BurpExtender类是所有接口的心脏,注意这里涉及到名字都不能改动,burp插件就这么规定的。
(3)实现唯一的接口函数
public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) {
this. callbacks = callbacks ;
}
通过callbacks获取核心基础库能力,像日志,请求,返回值修改等。
(4)日志接口
PrintWriter stdout = new PrintWriter(callbacks.getStdout(), true);
PrintWriter stderr = new PrintWriter(callbacks.getStderr(), true);
//输出到插件的output
stdout.println("Hello output");
// 输出到alerts tab
callbacks.issueAlert("Hello alerts");
//打印调用栈
e.printStackTrace(stderr)
有了这些日志接口就能比较好的调试代码了,如果要很好的跟踪请求的,可以在BApp Store中添加”Custom Logger”这个插件,能够记录所有的请求和返回信息。
2.2 getInsertionPoints
下面我们就来讲讲如何实现一个InsertionPoints
接口。第一步继承IScannerInsertionPointProvider
接口,实现getInsertionPoints()方法,同时通过callbacks.registerScannerInsertionPointProvider(this)
方法注册成为insertion point provider。下面我们就来看看getInsertionPoints()
的实现。
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
|
@
Override
public
List
&
lt
;
IScannerInsertionPoint
&
gt
;
getInsertionPoints
(
IHttpRequestResponse
baseRequestResponse
)
{
// 生成insertPoints数组
List
&
lt
;
IScannerInsertionPoint
&
gt
;
insertionPoints
=
new
ArrayList
&
lt
;
IScannerInsertionPoint
&
gt
;
(
)
;
// 获取请求参数
IRequestInfo
requestInfo
=
helpers
.
analyzeRequest
(
baseRequestResponse
.
getRequest
(
)
)
;
List
&
lt
;
IParameter
&
gt
;
requestParams
=
requestInfo
.
getParameters
(
)
;
for
(
IParameter
parameter
:
requestParams
)
{
String
value
=
parameter
.
getValue
(
)
;
value
=
helpers
.
urlDecode
(
value
)
.
trim
(
)
;
EncryptBean
encryptBean
=
new
EncryptBean
(
)
;
if
(
parameter
.
getName
(
)
.
trim
(
)
.
equals
(
"c"
)
)
{
//参数中含有c参数表示要加密的内容
encryptBean
=
JSON
.
parseObject
(
value
,
EncryptBean
.
class
)
;
stdout
.
println
(
"private key: "
+
key
.
privateKey
+
" public key "
+
key
.
publicKey
)
;
try
{
value
=
decryptRSAAndDES
(
key
,
encryptBean
)
;
stdout
.
println
(
"after decrypted:Will scan data at parameter "
+
parameter
+
" with value decrypted "
+
value
)
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
stderr
)
;
}
if
(
value
.
isEmpty
(
)
)
continue
;
try
{
String
basename
=
parameter
.
getName
(
)
;
//insertionPoints.add(new InsertionPoint(this, baseRequestResponse.getRequest(), basename, value));
JSONObject
jsonObj
=
JSON
.
parseObject
(
value
)
;
String
basevalue
=
""
;
for
(
Map
.
Entry
&
lt
;
String
,
Object
&
gt
;
entry
:
jsonObj
.
entrySet
(
)
)
{
basename
=
entry
.
getKey
(
)
;
basevalue
=
entry
.
getValue
(
)
.
toString
(
)
;
//在这里传入总的value值以便在InsertionPoint进行分解,构造加密后的request请求,构造InsertionPoint时传入的value为总的value值
insertionPoints
.
add
(
0
,
new
InsertionPoint
(
this
,
baseRequestResponse
.
getRequest
(
)
,
basename
,
value
)
)
;
stdout
.
println
(
"in for:Will scan AES encrypted data at parameter "
+
basename
+
" with value "
+
value
)
;
}
}
catch
(
Exception
e
)
{
}
}
}
return
insertionPoints
;
}
|
这一段代码的大体意思就是通过helper.analyzeRequest方法获取所有请求信息,遍历其中的参数信息,当发现参数名等于”c”时就会调用解密过程,这块的代码需要根据参数格式自定义解析参数过程。调用解密的过程大体就是先解析JSON格式,然后解密,得到解密数据的内容后调用
1
2
|
`
new
InsertionPoint
(
this
,
baseRequestResponse
.
getRequest
(
)
,
basename
,
value
)
`
|
实例化一个注入点。一般情况下basename和value是一一对应的,如param1=phoneNum,但是这里我们basename传入param1,value值则是解密后的值如
1
2
|
`
{
"userid"
:
"51ba27cb-514d-3d86-0000-2f7515a40613"
,
"task_id"
:
"1450147269"
,
"param1"
:
"000000000000000"
,
"m"
:
"https"
}
`,
|
这么传递是为了方便实例化插入点。接着我们看下InsertionPoint的参数构造。
2.3 InsertionPoint
1
2
3
4
5
6
7
|
InsertionPoint
(
BurpExtender
newParent
,
byte
[
]
baseRequest
,
String
basename
,
String
basevalue
)
{
this
.
parent
=
newParent
;
this
.
baseRequest
=
baseRequest
;
this
.
baseName
=
basename
;
//this.baseValue = basevalue;
this
.
value
=
basevalue
;
this
.
baseValue
=
JSON
.
parseObject
(
basevalue
)
.
getString
(
basename
)
;
}
|
在InsertionPoint的代码中有一个很重要的接口就是buildRequest,这个函数就是用来添加payload。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
@
Override
public
byte
[
]
buildRequest
(
byte
[
]
payload
)
{
String
payloadPlain
=
parent
.
helpers
.
bytesToString
(
payload
)
;
String
payloadEncrypted
=
""
;
String
tmpAESKey
=
"0123456789abcdef"
;
parent
.
stdout
.
println
(
"payloadPlain:"
+
payloadPlain
)
;
parent
.
callbacks
.
issueAlert
(
"payloadPlain:"
+
payloadPlain
)
;
try
{
Map
&
lt
;
String
,
String
&
gt
;
map
=
JSON
.
parseObject
(
this
.
value
,
new
TypeReference
&
lt
;
Map
&
lt
;
String
,
String
&
gt
;
&
gt
;
(
)
{
}
.
getType
(
)
)
;
map
.
put
(
this
.
baseName
,
getBaseValue
(
)
+
payloadPlain
)
;
String
allPayloadPlain
=
JSON
.
toJSONString
(
map
)
;
payloadEncrypted
=
parent
.
encryptRSAAndDES
(
allPayloadPlain
,
tmpAESKey
,
parent
.
key
)
;
}
catch
(
Exception
e
)
{
parent
.
callbacks
.
issueAlert
(
e
.
toString
(
)
)
;
}
parent
.
stdout
.
println
(
"Inserting "
+
payloadPlain
+
" ["
+
payloadEncrypted
+
"] in parameter "
+
baseName
)
;
// TODO: Only URL parameters, must change to support POST parameters, cookies, etc.
//"c" 解密数据格式包一致
return
parent
.
helpers
.
updateParameter
(
baseRequest
,
parent
.
helpers
.
buildParameter
(
"c"
,
payloadEncrypted
,
IParameter
.
PARAM_BODY
)
)
;
}
|
这段代码就是获取payload,然后嵌入到解密后的请求包,然后将请求加密,最后调用updateParameter更新参数信息。在这里要注意parent.helpers.buildParameter("c", payloadEncrypted, IParameter.PARAM_BODY)
c是body中的请求参数,和我们的数据格式对应,IParameter.PARAM_BODY
这个参数则表明是Body中的请求参数,如果是URl中的则是PARAM_URL
2.4 接口关系
知道了上述接口的作用,感觉还糊里糊涂的。那就是这些接口是怎么串起来的,数据包是如何流动的,下面我们来看下active scanning的流程。
ActiveScanner引擎从InsertionPoints Provider获取Insertion Points,然后调用BuildRequest发送Request,Requst再经过HttpListener的处理到达webServer。
参考文献:
http://drops.wooyun.org/papers/3962
http://2015.zeronights.ru/assets/files/42-Elkin-Bulatenko.pdf