1. 程式人生 > 其它 >frida 找不到so_當Frida來“敲”門

frida 找不到so_當Frida來“敲”門

技術標籤:frida 找不到so

0x1 滲透測試瓶頸

目前,碰到越來越多的大客戶都會將核心資產業務集中在統一的APP上,或者對自己比較重要的APP,如自己的主業務,辦公APP進行加殼,流量加密,投入了很多精力在移動端的防護上。

131cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

而現在挖漏洞除了拿到shell以外,客戶又要求可以儘可能的挖到核心業務系統的漏洞,並將漏洞範圍訂在主域名,核心業務系統現在又基本集中在移動端,移動端現在都會進行APP加殼,流量加密。這就導致無法進行平常滲透測試過程,像老生常談的中間人攻擊,進行攔截,篡改資料包就很難進行。

接下來就嘗試解決中間人攻擊的問題,目標是

1.看到明文的request和response的資料包;

2.做到可以攔截,篡改資料包。

0x2 frida

frida是平臺原生app的Greasemonkey,說的專業一點,就是一種動態插樁工具,可以插入一些程式碼到原生app的記憶體空間去,(動態地監視和修改其行為),這些原生平臺可以是Win、Mac、Linux、Android或者iOS。而且frida還是開源的。

161cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

環境需要越獄的IOS或者ROOT的Android。安裝的版本需要一致

MAC:

191cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

越獄Iphone:

1c1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

通過USB連結越獄手機,可以執行frida-ps -aU 就代表環境安裝成功

1f1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

0x3 越獄檢測繞過

啟動目標APP時,APP自身會進行環境檢測,如果處於越獄環境會提示如下:

221cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

點選“我知道了”就直接退出APP。

所以先嚐試先繞過第一步越獄環境檢測。可以先嚐試搜尋包含“jail,jeil,jb,break"關鍵字的函式

關於函式追蹤可以使用frida-trace,如:

# Trace recv* and send* APIs in Safari$ frida-trace -i "recv*" -i "send*" Safari# Trace ObjC method calls in Safari$ frida-trace -m "-[NSView drawRect:]" Safari​# Launch SnapChat on your iPhone and trace crypto API calls$ frida-trace -U -f com.toyopagroup.picaboo -I "libcommonCrypto*"

burp的外掛brida也支援對函式名進行檢索hook,和"Jail"相關的越獄檢測函式如下:

**** Result of the search of JailOBJC: +[BLYDevice isJailBreak]OBJC: +[IFlySystemInfo isJailbroken]OBJC: +[UIScreen _shouldDisableJail]OBJC: +[UIStatusBarWindow isIncludedInClassicJail]OBJC: -[_UIHostedWindow _isConstrainedByScreenJail]OBJC: -[_UIRootWindow _isConstrainedByScreenJail]OBJC: -[_UISnapshotWindow _isConstrainedByScreenJail]OBJC: -[BLYDevice isJailbroken]OBJC: -[BLYDevice setJailbrokenStatus:]OBJC: -[RCCountly isJailbroken]OBJC: -[UIClassicWindow _isConstrainedByScreenJail]OBJC: -[UIDevice isJailbroken]OBJC: -[UIStatusBarWindow _isConstrainedByScreenJail]OBJC: -[UITextEffectsWindowHosted _isConstrainedByScreenJail]OBJC: -[UIWindow _clampPointToScreenJail:]OBJC: -[UIWindow _isConstrainedByScreenJail]

想將目標定在“OBJC: +[BLYDevice isJailBreak]”

frida啟動APP,並載入指令碼的命令如下:

frida -U -f com.x.x -l js-scripts

js指令碼編寫可以看官方文件:https://frida.re/docs/javascript-api/

//hook傳入值,ObjC: args[0] = self, args[1] = selector, args[2-n] = arguments Interceptor.attach(myFunction.implementation, {   onEnter: function(args) {    var myString = new ObjC.Object(args[2]);    console.log("String argument: " + myString.toString());  }});//hook返回值,Interceptor.attach(Module.getExportByName('libc.so', 'read'), {  onEnter: function (args) {    this.fileDescriptor = args[0].toInt32();  },  onLeave: function (retval) {    if (retval.toInt32() > 0) {      /* do something with this.fileDescriptor */    }}});

定義js指令碼後,嘗試hook出“OBJC: +[BLYDevice isJailBreak]”的傳入值和返回值,

function hook_specific_method_of_class(className, funcName){    var hook = ObjC.classes[className][funcName];    Interceptor.attach(hook.implementation, {      onEnter: function(args) {        // args[0] is self        // args[1] is selector (SEL "sendMessageWithText:")        // args[2] holds the first function argument, an NSString        console.log("[*] Class Name: " + className);        console.log("[*] Method Name: " + funcName);        //For viewing and manipulating arguments        //console.log("[-] Value1: "+ObjC.Object(args[2]));        //console.log("[-] Value2: "+(ObjC.Object(args[2])).toString());        console.log("[-]arg value   "+args[2]);        Interceptor.attach(hook.implementation,             {              onLeave: function(retval) {                console.log("[*] Class Name: " + className);                console.log("[*] Method Name: " + funcName);                console.log("[-] Return Value: " + retval);             }}            );      }    });}//Your class name  and function name herehook_specific_method_of_class("BLYDevice", "- isJailbroken")
251cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

篡改後,發現未能繞過,可能不是這個函式做最終的邏輯判斷,想到竟然都彈窗提示了,和UI有關係。

那麼可能是“OBJC: -[UIDevice isJailbroken]這個類,最終構造繞過越獄檢測程式碼如下:

if (ObjC.available){    try    {        var className = "UIDevice";        var funcName = "- isJailbroken";        var hook = eval('ObjC.classes.' + className + '["' + funcName + '"]');//目標類+方法        Interceptor.attach(hook.implementation,         {          onLeave: function(retval) {            console.log("[*] Class Name: " + className);            console.log("[*] Method Name: " + funcName);            console.log("[-] Return Value: " + retval);//輸出原本的返回值            var newretval = ptr("0x0")             retval.replace(newretval)//替換新的返回值            console.log("[-] New Return Value: " + newretval)         }}        );    }    catch(err)    {        console.log("[!] Exception2: " + err.message);    }    }else{    console.log("Objective-C Runtime is not available!");}

執行結果如下:

291cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

成功繞過。

2c1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

0x4 HOOK加解密函式

越獄檢測繞過後,進一步開始嘗試定位加解密的函式。

關於定位加解密函式這塊在Android可以嘗試使用traceview去分析追蹤函式。

https://developer.android.google.cn/studio/profile/traceview

301cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

IOS可以嘗試使用runtime去追蹤函式,uidump從介面按鈕入手,Nslog日誌等位置入手,或者直接找相關關鍵字的函式去入手。

例如crypt(decryot,encrypt),HTTP,Network,目標廠商的名字簡寫找不到,可以嘗試搜尋NSString系統庫等。

這邊推薦一個大佬的GitHub專案。使用可以參考這個GitHub專案,非常好用,先用之前寫好的繞過越獄檢測的指令碼啟動APP,這邊通過查詢函式名找到對方關鍵的加解密函式“*encryptor”。

github專案:https://github.com/lyxhh/lxhToolHTTPDecrypt

331cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

hook此函式的所有方法,在點選登入按鈕後,觀察到有請求的資料包被當做引數傳入到-[XXEncryptor RSAEncrypt:]方法內,並返回了加密後的字串。-[XXEncryptor setRSAPublicKey:]根據定義的方法名判斷應該是RSA公鑰資訊。

371cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

其他方法則去處理了返回包。如-[XXEncrytor AESDecrypt:]方法,將服務端返回的加密欄位,使用AES對稱解密解密為明文。

3b1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

之前我們在Hook請求包函式的時候發現明文的資料包裡面帶有aeskey,說明此處的邏輯應該是:

本地生成aeskey代入到request包->使用定義的RSA公鑰加密request->傳送到服務端並解密request後->處理請求包內容,並使用AESkey加密Response返回到客戶端->客戶端在使用Aeskey解密服務端的Response包。

3d1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

大概是這麼一個流程,事實也證明返回包確實可以使用hook到的aeskey進行解密。

421cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

後面的思路是hook[XXEncrytor AESDecrypt:]解密方法去解密請求包和返回包,返回包是可以解,但是突然想到請求包是RSA非對稱的,需要私鑰。想嘗試在客戶端找到RSA的私鑰或者RSA解密方法,結果也確實有RSADecrypt方法。

461cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

但是事實是,從頭到尾這個方法都沒有被使用過,沒有引數被傳入,也沒有返回值。所以想,可能本地不做請求包的解密。那麼呼叫他的函式解密返回包可行,但解密請求包不行。但是咱們之前是有Hook到明文的request,可以再request被傳入到-[XXEncryptor RSAEncrypt]方法前,先去修改arg。

4a1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

具體操作方法可以參考lyxhh,將加密前的請求包轉入Burp後就可以實現篡改資料了。

lyxhh:https://github.com/lyxhh/lxhToolHTTPDecrypt

4d1cf1ab-6e2f-eb11-8da9-e4434bdf6706.png

新手的話可以先用la0s的JS,先看看對方是不是使用了IOS統一封裝的Crypto庫,js指令碼如下:

JS:https://la0s.github.io/2018/12/07/iOS_Crypto/

/ Intercept the CCCrypt call.Interceptor.attach(Module.findExportByName('libcommonCrypto.dylib', 'CCCrypt'), {    onEnter: function (args) {        // Save the arguments        this.operation   = args[0]        this.CCAlgorithm = args[1]        this.CCOptions   = args[2]        this.keyBytes    = args[3]        this.keyLength   = args[4]        this.ivBuffer    = args[5]        this.inBuffer    = args[6]        this.inLength    = args[7]        this.outBuffer   = args[8]        this.outLength   = args[9]        this.outCountPtr = args[10]        console.log('CCCrypt(' +             'operation: '   + this.operation    +', ' +            'CCAlgorithm: ' + this.CCAlgorithm  +', ' +            'CCOptions: '   + this.CCOptions    +', ' +            'keyBytes: '    + this.keyBytes     +', ' +            'keyLength: '   + this.keyLength    +', ' +            'ivBuffer: '    + this.ivBuffer     +', ' +            'inBuffer: '    + this.inBuffer     +', ' +            'inLength: '    + this.inLength     +', ' +            'outBuffer: '   + this.outBuffer    +', ' +            'outLength: '   + this.outLength    +', ' +            'outCountPtr: ' + this.outCountPtr  +')')        if (this.operation == 0) {            // Show the buffers here if this an encryption operation            console.log("In buffer:")            console.log(hexdump(ptr(this.inBuffer), {                length: this.inLength.toInt32(),                header: true,                ansi: true            }))            console.log("Key: ")            console.log(hexdump(ptr(this.keyBytes), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))            console.log("IV: ")            console.log(hexdump(ptr(this.ivBuffer), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))        }    },    onLeave: function (retVal) {        if (this.operation == 1) {            // Show the buffers here if this a decryption operation            console.log("Out buffer:")            console.log(hexdump(ptr(this.outBuffer), {                length: Memory.readUInt(this.outCountPtr),                header: true,                ansi: true            }))            console.log("Key: ")            console.log(hexdump(ptr(this.keyBytes), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))            console.log("IV: ")            console.log(hexdump(ptr(this.ivBuffer), {                length: this.keyLength.toInt32(),                header: true,                ansi: true            }))        }    }})

如果只能hook到部分明文流量,再考慮去對方定義的函式裡去找關鍵的加密函式,如這個APP的關鍵的XXEncryptor類。