Burpsuite插件開發之RSA加解密

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. callbackscallbacks = 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()的實現。
- @Override
- public List<IScannerInsertionPoint> getInsertionPoints (IHttpRequestResponse baseRequestResponse) { // 生成insertPoints數組
- List<IScannerInsertionPoint> insertionPoints = new ArrayList<IScannerInsertionPoint>(); // 獲取請求參數
- 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")){//參數中含有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<String, Object> 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格式,然后解密,得到解密數據的內容后調用
- `new InsertionPoint(this, baseRequestResponse.getRequest(), basename, value)`
實例化一個注入點。一般情況下basename和value是一一對應的,如param1=phoneNum,但是這里我們basename傳入param1,value值則是解密后的值如
- `{"userid":"51ba27cb-514d-3d86-0000-2f7515a40613","task_id":"1450147269","param1":"000000000000000","m":"https"}`,
這么傳遞是為了方便實例化插入點。接著我們看下InsertionPoint的參數構造。
2.3 InsertionPoint
- 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。
- @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" 解密數據格式包一致
- 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。