用BurpSuit的Brida自定義插件搞定加密簽名算法
Frida是一款非常強大的框架,其可向Windows、MacOS、Linux、iOS、Android,QNX的應用中注入Javascript,進而攔截應用傳輸的數據。本文僅使用到其中少部分功能,更多可以參考Frida文檔,強烈建議讀者最好是在熟悉了其基本概念以及常用功能後再進行閱讀。推薦兩篇不錯的譯文:使用Frida配合Burp Suite追蹤API調用; 如何在iOS應用程序中用Frida來繞過“越獄檢測”?大家在做滲透測試的時候有沒有遇到這樣的問題?當你要對一個協議的內容進行修改的時候,發現只要修改一個字節進行發送,服務器返回的結果就是錯誤的;用原始包進行重放操作就是沒問題的。
通過觀察發現包頭中有個sign字段對包中的內容進行校驗,所以服務器纔會返回錯誤的結果。看到這裏聰明的你一定會想到,找到sign的算法,把sign字段計算出來不就可以了嗎。但是,通過跟蹤發現sign的計算方法,被放到了so文件中並且此段算法已經被VM了,沒有這個能力還原算法還原朋友可以看看我這篇文章。
山人自有妙招,今天這篇文章的就是告訴大家說應該怎麼解決這個問題。
下面截圖是通過本文的方法的產出的結果,可以看到通過BurpSuit自動化的對有簽名驗證的協議進行批量測試。
一、必備工具:
操作系統: WIN10_X64
BurpSuit: 滲透神器,如果你還不知道這個,那麼只能說明你不是圈內人,趕快去百度一下吧。
Frida:
Frida是一款非常強大的框架,其可向Windows、MacOS、Linux、iOS、Android,QNX的應用中注入Javascript,進而攔截應用傳輸的數據。本文僅使用到其中少部分功能,更多可以參考Frida文檔,強烈建議讀者最好是在熟悉了其基本概念以及常用功能後再進行閱讀。推薦兩篇不錯的譯文:使用Frida配合Burp Suite追蹤API調用; 如何在iOS應用程序中用Frida來繞過“越獄檢測”?
Brida(Ver:0.3): BurpSuit的插件,這是此篇文章的重點。
Brida是一款 Burp Suite 擴展,作爲一座橋樑連接着Burp Suite以及Frida,以幫助用戶修改應用程序與後端服務器之間的通信數據爲己任。在分析移動端應用時遇到應用使用隨機密鑰式對稱加密,如果不知道其使用的密鑰就無法篡改其通信數據,通過Burp也就無法對所有的交換數據進行更改了,於是Brida就這樣出現在我們視野中。
GitHub: https://github.com/federicodotta/Brida
Jadx(Ver:1.1.0):
一款免費的apk反編譯軟件。
GitHub: https://github.com/skylot/jadx
Python2.7: 我使用的是Brida是v0.3版本的,所以只支持Python2。
二、目標分析:
1.靜態分析,找到關鍵位置
首先,找到要分析的APK,用jadx載入進行反編譯,查找sign算法的位置(至於如何查找算法不是本文的重點所以這裏就不詳細說查找的步驟了),找到算法call後發現如下:
tps.addHeaderParam(JNISecurity.signJava(sb.toString())
繼續跟進,發現是計算sign的函數在so文件中,用ida打開看看,發現用VM加密了。
public class JNISecurity { private static native String sign(String str); static { System.loadLibrary("xxxx");} public static String signJava(String str) { String sign = sign(str); return "" + sign;} }
雖然核心函數被VM加密了,我們看不到sign的算法是怎麼實現的,但是我們可以調用這個so文件中的算法進行計算,只要把參數傳對,不就可以讓app幫我們計算了麼?
2 還原參數算法
確定想法以後,開始看參數是怎麼形成的。通過jadx反編譯,找到傳參的地方如下:
private void signParam(tps tps) { try { StringBuilder sb = new StringBuilder(); String str = System.currentTimeMillis() + ""; sb.append("KEYKEYKEYKEYKEYKEY"); sb.append(str); if (tps.getBodyParam() != null && !tps.getBodyParam().isEmpty()) { ArrayList<String> arrayList = new ArrayList<>(); for (Map.Entry<String, String> key : tps.getBodyParam().entrySet()) { arrayList.add(key.getKey()); } Collections.sort(arrayList); for (String str2 : arrayList) { String str3 = tps.getBodyParam().get(str2); if (TextUtils.isEmpty(str3)) { str3 = ""; } sb.append(str2); sb.append(HttpUtils.EQUAL_SIGN); sb.append(str3); } } tps.addHeaderParam(JNISecurity.signJava(sb.toString(), new String("X.XX.XX"))); } catch (Exception e) { } }
上面代碼的意思是把body中字段的內容取出,一個固定的KEY加上當前的時間戳進行拼接後(KEYKEYKEYKEYKEYKEY+body+time),傳給signJava進行計算。
如:
body內容爲:nickname=99bbe4
進行拼接後的字符串:
KEYKEYKEYKEYKEYKEY99bbe41589531540770
3 動態分析,使用Brida自動計算出sign的值
如果不會安裝Brida與Frida的同學可以參考這篇文章:Brida Python3環境下的不完全折騰手冊: https://www.freebuf.com/column/232055.html
BurpSuit中的Brida插件中有一個功能,可以把用戶選定的內容,傳入到Brida通過調用frida進行hook,來執行sign的算法
brida.js腳本如下:
contextcustom1: function(message) { var data = hexToString(message); var timestamp = new Date().getTime(); data = 'KEYKEYKEYKEYKEYKEY'+timestamp+data; var sign; Java.perform(function () { try { //hook class var calclass = Java.use('com.xxxx.xxxx.JNISecurity'); //hook method sign = calclass.signJava(data); } catch (error) { console.log("[!]Exception:" + error.message); } }); return stringToHex(sign); },
上面的代碼意思其實很簡單,HOOK app中的com.xxxx.xxxx.JNISecurity這個類,填入參數(用戶選定的參數),執行signJava方法,讓app幫我們計算出sign.
準備完成後,啓動brida,並且載入brdia.js腳本。
4 效率太低,怎麼才能改進?
雖然這樣做,可以進行滲透測試了,但每改一次修改一個值,就需要
右鍵===》Cutoms1===>刪除原來的sign===》複製新生產的sign===》調整格式===>發送協議,
而且這樣只能一個一個協議的測試,速度非常的慢,慢還可以忍,關鍵還不能進行批量暴力測試,也就失去了價值。
在BurpSuit中如果當發送內容的時候自動可以自動把sign替換掉,是不是就不用這麼麻煩了,於是仔細看了看Brida的文檔,首先了解下Brida的工作方式:
太好了,Brida通過Pyro4與Frida進行聯繫,這樣就把Burp和Frida聯繫在一起了。Brida提供了這個功能(用戶自定義插件),正好做做嘗試。
5 使用自定義插件(Custom plugin with Brida stub)
這個過程可能有點繞,我畫個圖,一圖頂萬語!(圖中我省略了Pyro4和Frida與Brida的交互過程)
如上圖所示:插件接收到Burp傳過來的Reuqest和Body的內容,會自動修改Brup中要發送的Request的內容。
這裏使用的是python,如果你擅長java,也是可以的,原理是相同。
Python插件腳本關鍵代碼如下:
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): if messageIsRequest and self.check_Flag(toolFlag): # Get request bytes request = messageInfo.getRequest() # Get a IRequestInfo object, useful to work with the request analyzedRequest = self.helpers.analyzeRequest(request) headers = list(analyzedRequest.getHeaders()) bodyOffset = int(analyzedRequest.getBodyOffset()) body = request[bodyOffset:] bodyString = "".join(map(chr, body)) if self.find_header('Host: xxxx.xxxx.com', headers): # get sign from brida _sign = self.get_sign(bodyString) # gen new headers by sign _newheaders = self.gen_headers(headers, _sign) # rebuild request if len(_newheaders) > 0: _newRequest = self.helpers.buildHttpMessage( _newheaders, body) # send packet messageInfo.setRequest(_newRequest) pass
從Brida中獲取到sign的值,(這段代碼從Brida插件中的Python stub中獲得)
def get_sign(self, bodyString): uri = 'PYRO:BridaServicePyro@localhost:9999' pp = Pyro4.Proxy(uri) args = [] if len(bodyString) > 0: args.append(bodyString) else: args.append('') # get sign from brida.js script _retvalue = pp.callexportfunction('getsign', args) pp._pyroRelease() return _retvalue
6 批量暴力攻擊測試
在Burp的Extend中加入自己寫的Python插件,加入成功後,前面會顯示打鉤,表面插件加入成功。
選擇修改用戶信息的協議加入intruder中進行批量測試,測試成功。
三、 總結
本文通過一個案例,從apk反編譯到加密分析,到讓應用自動算出sign;從剛開始的手動解密sign,到後來的自動解密並替換sign,到最後的批量測試,Brida插件給我們帶來了非常大的幫助。
在網絡協議滲透測試的方面,BrupSuit用的會多一些,所以Brida插件是滲透測試人員必要掌握的一個工具。從本文可以看到,Brida幫我們在進行滲透測試的時候節省不少的時間,畢竟是先要通過人工分析後,纔能有思路達到自動化腳本的目的。
其中用到的插件與腳本, https://github.com/yearnwang/Brida_Custom_Plugs ,需要的可以去下載。
有什麼問題大家可以隨時留言給我或者Email給我。
四、 參考文獻
Brida – A step-by-step user guide https://techblog.mediaservice.net/2018/04/brida-a-step-by-step-user-guide/
Brida https://github.com/federicodotta/Brida
Brida使用Frida進行移動應用滲透測試 https://www.freebuf.com/sectool/143360.html
Brida操作指南 https://bbs.pediy.com/thread-248977.htm
Brida Python3環境下的不完全折騰手冊 https://www.freebuf.com/column/232055.html
*本文作者:Mr極品混混,轉載請註明來自FreeBuf.COM