Burpsuite插件開(kāi)發(fā)之RSA加解密

之前我們一直在探討如何通過(guò)一個(gè)抓包工具來(lái)實(shí)現(xiàn)加密解密的功能,那么在此就主要記錄了一個(gè)解密請(qǐng)求包,插入payload,再加密的插件開(kāi)發(fā)過(guò)程,插件應(yīng)用場(chǎng)景主要是用于通過(guò)分析apk的實(shí)現(xiàn)。這里做探討的目的只是方便安全測(cè)試人員的個(gè)人學(xué)習(xí),或大家滲透測(cè)試使用。

1,概述

burpsuite是一款非常好用的抓包工具,我自己也是重度用戶,所以就上手了burpsuite的插件接口開(kāi)發(fā)。詳細(xì)的代碼見(jiàn)github代碼,在文檔中數(shù)據(jù)首先是以rsa方式加密des的key得到encryptKey,然后使用des的key加密數(shù)據(jù)包得到data,再組裝成一個(gè)JSON格式串,這是加密過(guò)程,當(dāng)然解密過(guò)程就是逆向的。插件應(yīng)用場(chǎng)景主要是用于通過(guò)分析apk的實(shí)現(xiàn),或者泄露的密鑰,獲取其加解密算法,在解密后的數(shù)據(jù)包中插入payload,發(fā)現(xiàn)注入問(wèn)題等。

如下則是加密后的數(shù)據(jù)包:

1
2
3
4
c={
"data":"21BhviedgtbwK6rdlK7vzltqxOLxUmU2g5qaO5LWPYTha5fXslmL6jrMkFnJBwpZPZMNl5foxTUHw2Mae++zkWwtzWkKXI9WJ/CJqxO9uORT5I6iUmIG7bBcgnHpmlSNKfFwBvnr9vj3v5ByvW2s2/pL9rSaeD+/8XsX01NA96mC4g5pVBeU5IY9F4tdxH9yobXfN6GzEVhLeiEd30xzMA\u003d\u003d",
"encryptKey":"bjWZgigAW/ZaAA55v7Yi9AGt2qsP7BfZZISu70qc/xVUVfh5L/Mw/mMbzxkcZ6uXb1vvgXvF7hHYwjsVzvEkRK0rIfIwkcYzn160fvQ/8+F8YBMDLzTEhf8r0KjOLlJV+HgOsS4QG/G9lOU5mnupfrVA9sf54b3OvXHU0TQVG7U\u003d"
}

從數(shù)據(jù)庫(kù)包能看到大的數(shù)據(jù)是一個(gè)json格式,里面有data,和encryptKey值,encryptKey就是使用RSA加密des 的key得到的,RSA的工作方式和pem文件可通過(guò)界面設(shè)置,再接著用這個(gè)key采用des方式解密data中的內(nèi)容。操作界面如下:

burp_rsa

burp_rsa

2,InsertPoint 接口

InsertPoint顧名思義就是注入點(diǎn),就是payload插入的地方,比如request中的cookie,參數(shù)等位置。為了對(duì)一些burpsuite不支持的參數(shù)格式進(jìn)行支持就必須實(shí)現(xiàn)該接口,可以用在Active Scanner和Intruder中.

2.1 基礎(chǔ)開(kāi)發(fā)知識(shí)

最好的方式就是在原有插件的基礎(chǔ)上修改,這樣能省很多精力,當(dāng)然如果要一步一步來(lái)的話,步驟如下:

(1)包含burp的接口文件

(2)創(chuàng)建一個(gè)包名為burp,在里面創(chuàng)建BurpExtender類,實(shí)現(xiàn)IBurpExtender接口,這個(gè)BurpExtender類是所有接口的心臟,注意這里涉及到名字都不能改動(dòng),burp插件就這么規(guī)定的。

(3)實(shí)現(xiàn)唯一的接口函數(shù)

1
2
3
public?void?registerExtenderCallbacks(final?IBurpExtenderCallbacks?callbacks)?{
this.?callbacks?=?callbacks?;
}

通過(guò)callbacks獲取核心基礎(chǔ)庫(kù)能力,像日志,請(qǐng)求,返回值修改等。

(4)日志接口

1
2
3
4
5
6
7
8
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");
//打印調(diào)用棧
e.printStackTrace(stderr)

有了這些日志接口就能比較好的調(diào)試代碼了,如果要很好的跟蹤請(qǐng)求的,可以在BApp Store中添加”Custom Logger”這個(gè)插件,能夠記錄所有的請(qǐng)求和返回信息。

2.2 getInsertionPoints

下面我們就來(lái)講講如何實(shí)現(xiàn)一個(gè)InsertionPoints接口。第一步繼承IScannerInsertionPointProvider接口,實(shí)現(xiàn)getInsertionPoints()方法,同時(shí)通過(guò)callbacks.registerScannerInsertionPointProvider(this)方法注冊(cè)成為insertion point provider。下面我們就來(lái)看看getInsertionPoints()的實(shí)現(xiàn)。

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
@Override
public?List<iscannerinsertionpoint>?getInsertionPoints?(IHttpRequestResponse?baseRequestResponse)?{?//?生成insertPoints數(shù)組??
List<iscannerinsertionpoint>?insertionPoints?=?new?ArrayList<iscannerinsertionpoint>();?//?獲取請(qǐng)求參數(shù)
IRequestInfo?requestInfo?=?helpers.analyzeRequest(baseRequestResponse.getRequest());??
List<iparameter>?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")){//參數(shù)中含有c參數(shù)表示要加密的內(nèi)容
????????????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<string,?object>?entry:?jsonObj.entrySet()){
????????????????????basename?=?entry.getKey();
????????????????????basevalue?=?entry.getValue().toString();????????????????????
????????????????????//在這里傳入總的value值以便在InsertionPoint進(jìn)行分解,構(gòu)造加密后的request請(qǐng)求,構(gòu)造InsertionPoint時(shí)傳入的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;
}</string,?object></iparameter></iscannerinsertionpoint></iscannerinsertionpoint></iscannerinsertionpoint>

<string,?object>

這一段代碼的大體意思就是通過(guò)helper.analyzeRequest方法獲取所有請(qǐng)求信息,遍歷其中的參數(shù)信息,當(dāng)發(fā)現(xiàn)參數(shù)名等于”c”時(shí)就會(huì)調(diào)用解密過(guò)程,這塊的代碼需要根據(jù)參數(shù)格式自定義解析參數(shù)過(guò)程。調(diào)用解密的過(guò)程大體就是先解析JSON格式,然后解密,得到解密數(shù)據(jù)的內(nèi)容后調(diào)用

1
`new?InsertionPoint(this,?baseRequestResponse.getRequest(),?basename,?value)`

實(shí)例化一個(gè)注入點(diǎn)。一般情況下basename和value是一一對(duì)應(yīng)的,如param1=phoneNum,但是這里我們basename傳入param1,value值則是解密后的值如

1
`{"userid":"51ba27cb-514d-3d86-0000-2f7515a40613","task_id":"1450147269","param1":"000000000000000","m":"https"}`,

這么傳遞是為了方便實(shí)例化插入點(diǎn)。接著我們看下InsertionPoint的參數(shù)構(gòu)造。

2.3 InsertionPoint

1
2
3
4
5
6
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的代碼中有一個(gè)很重要的接口就是buildRequest,這個(gè)函數(shù)就是用來(lái)添加payload。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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<string,string>?map?=?JSON.parseObject(this.value,?new?TypeReference<map<string,?string>>(){}.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"?解密數(shù)據(jù)格式包一致
????return?parent.helpers.updateParameter(baseRequest,?parent.helpers.buildParameter("c",?payloadEncrypted,?IParameter.PARAM_BODY));
}</map<string,?string></string,string>

<string,string><map<string,?string>

這段代碼就是獲取payload,然后嵌入到解密后的請(qǐng)求包,然后將請(qǐng)求加密,最后調(diào)用updateParameter更新參數(shù)信息。在這里要注意parent.helpers.buildParameter("c", payloadEncrypted, IParameter.PARAM_BODY)?c是body中的請(qǐng)求參數(shù),和我們的數(shù)據(jù)格式對(duì)應(yīng),IParameter.PARAM_BODY這個(gè)參數(shù)則表明是Body中的請(qǐng)求參數(shù),如果是URl中的則是PARAM_URL。

2.4 接口關(guān)系

知道了上述接口的作用,感覺(jué)還糊里糊涂的。那就是這些接口是怎么串起來(lái)的,數(shù)據(jù)包是如何流動(dòng)的,下面我們來(lái)看下active scanning的流程。

burp-active-scan

burp-active-scan

ActiveScanner引擎從InsertionPoints Provider獲取Insertion Points,然后調(diào)用BuildRequest發(fā)送Request,Requst再經(jīng)過(guò)HttpListener的處理到達(dá)webServer。