抓取IOS的apsd進程流量
- 2019 年 10 月 8 日
- 筆記
IOS的apsd是Apple Push Service的相關進程,很多系統服務都跟他有關,比如iMessage、Homekit,因此想抓包查看他是怎麼實現的。
1.搜索發現相關資料很少,只有多年前的一個相關演講:https://blog.quarkslab.com/resources/2013-10-17_imessage-privacy/slides/iMessage_privacy.pdf
2.首先使用uncover越獄,嘗試使用ssl-kill-switch2,發現並不成功,原因不明,發了issue不只一個人有這個問題。
3. 接下來嘗試使用Frida來Hook SecTrustEvaluate(),參考部落格https://kov4l3nko.github.io/blog/2018-05-27-sll-pinning-hook-sectrustevaluate/
發現是可行的,中間人能抓到客戶端發出的第一個數據包,但是不明原因伺服器並不會回復客戶端請求。猜測是不是伺服器驗證了客戶端的證書(從蘋果官方資料中猜測是,但是我抓包沒有看到標準的TLS握手中請求客戶端證書),因此嘗試使用keychain dumper獲取客戶端apsd使用的證書,並把證書設置給中間人。
4. 使用keychain的時候有坑,首先不支援IOS12,通過Issue 36修改entitlements.xml解決,特別注意需要下載源碼按照說明重新build二進位才能使用,不然出現KILL 9錯誤。 參考pushProxy的教程,使用cydia安裝openssl後使用KeychainDumper_signed -k (記得加-k參數)可獲得私鑰。換成-i參數獲得證書。
悲劇的是,在mitmproxy里設置了客戶端證書也不行,伺服器還是不回復消息(畢竟沒開中間人也沒看到伺服器要客戶端證書啊),不知道發生了什麼。剩下的只能靠自己或者研究一下多年前的pushProxy了。
5. 由於Hook SSL證書這條路出現了不明原因的bug,所以決定Hook SSL的收發函數。
首先調查蘋果ssl的實現機制,可能是用的這個鏈接的coreTLS實現:https://opensource.apple.com/tarballs/
這裡面源碼就用了Hook發現確實在用的SecTrustEvaluate();收發函數觀察發現是SSLWrite和SSLRead,注意大小寫一定不能錯!用frida-trace發現其實SSL_write()也有,但不知為何沒有hook到調用。
最終問題解決可以看到收發的數據了,使用的程式碼如下:
1 import frida 2 import sys 3 4 5 def on_message(message, data): 6 try: 7 if message: 8 print("[*] Received data: {0}".format(message["payload"])) 9 except Exception as e: 10 print(message) 11 print(e) 12 13 14 def run_frida_script(): 15 with open("hook_sslReadWrite.js", "r") as f: 16 frida_script_code = f.read() 17 return frida_script_code 18 19 if __name__ == '__main__': 20 21 #For USB connection 22 session = frida.get_usb_device().attach("apsd") 23 script = session.create_script(run_frida_script()) 24 script.on('message', on_message) 25 script.load() 26 sys.stdin.read()
function main() { // Get SecTrustEvaluate address var SSLWrite_prt = Module.findExportByName("Security", "SSLWrite"); var SSLRead_prt = Module.findExportByName("Security", "SSLRead"); if (SSLWrite_prt == null || SSLRead_prt == NULL) { console.log("[Error] Security!SSLWrite/Read(...) not found!"); return; } //OSStatus SSLWrite(SSLContextRef context, const void *data, size_t dataLength, size_t *processed); Interceptor.attach(SSLWrite_prt, { onEnter: function (args) { console.log("SSLWrite(" + "" + ")"); this.data = args[1]; this.processed = args[3]; //send("onEnter SSLWrite"); //var length = args[2].toInt32(); //console.log(int64(args[2]).toInt32()); //send(Memory.readByteArray(args[1], parseInt(args[2]))); //console.log(Memory.readByteArray(args[1], length)); //console.log("SSLWrite() called from:n" + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("n")); }, onLeave: function (retval) { //send("onLeave"); var status = retval.toInt32(); if (status === 0 && !this.processed.isNull()) { var data = Memory.readByteArray(this.data, Memory.readPointer(this.processed).toInt32()); console.log(data); } } }); //OSStatus SSLRead(SSLContextRef context, void *data, size_t dataLength, size_t *processed); Interceptor.attach(SSLRead_prt, { onEnter: function (args) { console.log("SSLRead(" + "" + ")"); this.data = args[1]; this.processed = args[3]; }, onLeave: function (retval) { var status = retval.toInt32(); if (status === 0) { var data = Memory.readByteArray(this.data, Memory.readPointer(this.processed).toInt32()); console.log(data); } } }); } // Run the script main();
後記:發現蘋果沒有一個公開的說明push service的文檔,看到流量獲得的資訊也有限,最後只要再查資料+逆向了……