原文地址:《"BLIND" Reversing - A Look At The Blind iOS App》
譯者:hello1900@知道創宇404實驗室
前言
“Blind是一款用于工作場合的匿名社區應用。” 換句話說,作為一名員工,如果有“暢所欲言”或以匿名方式抨擊雇主或同事的打算(當然這種情況極為常見),那么Blind可能是你的不二之選。這款有趣的小應用能夠幫助我們透過事物表象了解真實情況。
范圍與環境
我重點關注應用本身,因此使用Linkedin賬戶而非工作郵件注冊。這樣一來就產生了一些訪問限制。此外,我也并未花時間了解所有功能,僅考慮一些自己看來具有核心功能的組件,所以難免存在局限性。
環境搭建如下:
-運行iOS 9.3.3的越獄iPhone 5S
-jtool
-IDA Pro
-Hopper
-BurpSuite Pro
-Frida
越獄檢測
首先,這款應用不具備任何越獄檢測例行程序。對于你的不屑一顧我暫時保持緘默。我開始也不認為缺少此類檢查本身是安全問題,但從更寬泛、深入的防御觀點來看卻不盡然。
證書固定
第二個觀察結果是該應用沒有通過SSL證書驗證(證書固定)檢查遠程端點的真實性,因此可以通過中間人(MiTM)攻擊監聽并篡改數據。事實上,情況并不像聽起來那么糟。原因如下:1. 攻擊者必須欺騙用戶在設備上安裝惡意證書;2. 該應用對發送至后端的數據進行加密。
另一方面,攻擊者大多數情況下需要先欺騙用戶安裝惡意證書。對此,我表示贊同,因為確實存在旨在簡化流程的工具。Sensepost上的博客文章(https://sensepost.com/blog/2016/too-easy-adding-root-cas-to-ios-devices/)就是一個很好的例子。
最后,該應用程序提供兩種登錄選項:工作電子郵件與LinkedIn驗證(見下圖)。如上所述,我傾向使用后者。副作用是攻擊者可在證書未固定的情況下捕獲LinkedIn登陸憑據,當然是在安裝惡意證書的前提下。
獲取二進制文件
解決這些問題后就可以獲得二進制文件、開始逆向了。我使用 dumpdecrypted dylib,僅需 ssh登錄設備并運行以下代碼:
root@Jekyl (/var/root)# su mobile
mobile@Jekyl (/var/mobile/Documents)# DYLD_INSERT_LIBRARIES=/var/root/dumpdecrypted.dylib /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind
mach-o decryption dumper
DISCLAIMER: This tool is only meant for security research purposes, not for application crackers.
[+] detected 64bit ARM binary in memory.
[+] offset to cryptid found: @0x1000d4f28(from 0x1000d4000) = f28
[+] Found encrypted data at address 00004000 of length 7995392 bytes - type 1.
[+] Opening /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind for reading.
[+] Reading header
[+] Detecting header type
[+] Executable is a plain MACH-O image
[+] Opening teamblind.decrypted for writing.
[+] Copying the not encrypted start of the file
[+] Dumping the decrypted data into the file
[+] Copying the not encrypted remainder of the file
[+] Setting the LC_ENCRYPTION_INFO->cryptid to 0 at offset f28
[+] Closing original file
[+] Closing dump file
應注意使用root權限在iOS 9.3.3版本運行DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib可殺掉被注入進程:
root@Jekyl (/var/root)# DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib /private/var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind
zsh: killed DYLD_INSERT_LIBRARIES=dumpdecrypted.dylib
root@Jekyl (/var/root)#
解決辦法是先切換至手機再cd至上圖/var/mobile/Document。還應注意我們之所以能夠注入自己的 dylib 是因為Blind應用沒有 __RESTRICT Segment。
LC_SEGMENT_64 Mem: 0x100008000-0x100008000 __RESTRICT
Mem: 0x100008000-0x100008000 __RESTRICT.__restrict
這是個null segment (size 0),用于通知 DLYD 不要相信任何 DLYD* 環境變量。
識別端點
我在查看二進制文件時通常會轉儲字符串并搜索URL端點,然后用該列表確認Burpsuite流量。
macho-reverser:BLIND macho-reverser$ jtool -d __TEXT.__cstring teamblind.decrypted | grep "http"
Address : 0x1006dcfd0 = Offset 0x6dcfd0
0x1006df366: https://api.linkedin.com/v1/people/~:(id,email-address,first-name,last-name,headline,num-connections,industry,summary,specialties,positions:(id,title,summary,start-date,end-date,is-current,company:(id,name,universal-name,type,size,industry,ticker,email-domains)),educations:(id,school-name,field-of-study,start-date,end-date,degree,activities,notes),associations,interests,num-recommenders,date-of-birth,publications:(id,title,publisher:(name),authors:(id,name),date,url,summary),patents:(id,title,summary,number,status:(id,name),office:(name),inventors:(id,name),date,url),languages:(id,language:(name),proficiency:(level,name)),skills:(id,skill:(name)),certifications:(id,name,authority:(name),number,start-date,end-date),courses:(id,name,number),recommendations-received:(id,recommendation-type,recommendation-text,recommender),honors-awards,three-current-positions,three-past-positions,volunteer)?format=json
0x1006df80e: http://us.teamblind.com
0x1006e19ad: https://api.linkedin.com/v1/people/~:(id,email-address)?format=json
0x1006e75df: https://m.facebook.com/settings/email
0x1006e760c: https://www.linkedin.com/m/settings/email
0x1006ea5ec: https://docs.google.com/forms/d/e/1FAIpQLSc_J26TtkDL7HXcLeFXC2jy6lb1PmJSPnh51_ng7fr1638p_Q/viewform
0x1006ee9c3: https://www.linkedin.com/uas/oauth2/authorization?response_type=code&client_id=%@&scope=%@&state=%@&redirect_uri=%@
0x1006f4865: https://krapi.teamblind.com
0x1006f4881: https://usapi.teamblind.com
0x1006f489d: http://kr.stage.teamblind.com:8080
0x1006f48c0: http://us.stage.teamblind.com:8080
0x1006f48e3: http://dev.teamblind.com:8080
0x1006f4901: http://us.dev.teamblind.com:8080
0x1006f4922: https://kr.teamblind.com
0x1006f493b: https://us.teamblind.com
0x1006f4954: https://krnotifier.teamblind.com
0x1006f4975: https://usnotifier.teamblind.com
----
也可以用它獲取其他潛在目標列表。于是,啟動Burpsuite并檢查流量。如前文所述,Blind應用能否實現證書固定并沒有那么重要,因為該應用對發送至后端的數據進行加密。下圖為常用請求示例。
唯一能夠確定的是早前識別的鏈接。所以說我們實際上處于“盲”狀態。但如果數據經過加密,那么加密秘鑰的存儲或生成的方式與位置是什么?能否看到應用發送至服務器的明文數據?
提取類
為了回答這些問題,首先轉儲類,看看是否存在有價值的內容。列出代碼段后發現關于Objective-C的引用:
macho-reverser:BLIND macho-reverser$ jtool -l teamblind.decrypted
LC 00: LC_SEGMENT_64 Mem: 0x000000000-0x100000000 __PAGEZERO
LC 01: LC_SEGMENT_64 Mem: 0x100000000-0x1007a4000 __TEXT
Mem: 0x100007a90-0x100663f18 __TEXT.__text (Normal)
Mem: 0x100663f18-0x10066723c __TEXT.__stubs (Symbol Stubs)
Mem: 0x10066723c-0x10066a560 __TEXT.__stub_helper (Normal)
Mem: 0x10066a560-0x100671ec0 __TEXT.__const
Mem: 0x100671ec0-0x1006dcfc9 __TEXT.__objc_methname (C-String Literals)
Mem: 0x1006dcfd0-0x10074ca58 __TEXT.__cstring (C-String Literals)
Mem: 0x10074ca58-0x100754bb2 __TEXT.__objc_classname (C-String Literals)
Mem: 0x100754bb2-0x100767daa __TEXT.__objc_methtype (C-String Literals)
Mem: 0x100767daa-0x100768e18 __TEXT.__ustring
Mem: 0x100768e18-0x100788c4c __TEXT.__gcc_except_tab
Mem: 0x100788c50-0x10078b967 __TEXT.__swift3_typeref
Mem: 0x10078b968-0x10078c6a0 __TEXT.__swift3_capture
Mem: 0x10078c6a0-0x10078d720 __TEXT.__swift3_fieldmd
Mem: 0x10078d720-0x10078e67d __TEXT.__swift3_reflstr
Mem: 0x10078e680-0x10078edc8 __TEXT.__swift3_assocty
Mem: 0x10078edc8-0x10078f3c8 __TEXT.__swift2_proto
Mem: 0x10078f3c8-0x10078f478 __TEXT.__swift2_types
Mem: 0x10078f478-0x10078f4dc __TEXT.__swift3_builtin
Mem: 0x10078f4dc-0x1007a3d20 __TEXT.__unwind_info
Mem: 0x1007a3d20-0x1007a4000 __TEXT.__eh_frame
LC 02: LC_SEGMENT_64 Mem: 0x1007a4000-0x100980000 __DATA
Mem: 0x1007a4000-0x1007a4ba8 __DATA.__got (Non-Lazy Symbol Ptrs)
Mem: 0x1007a4ba8-0x1007a6dc0 __DATA.__la_symbol_ptr (Lazy Symbol Ptrs)
Mem: 0x1007a6dc0-0x1007a6e00 __DATA.__mod_init_func (Module Init Function Ptrs)
Mem: 0x1007a6e00-0x1007cfd20 __DATA.__const
Mem: 0x1007cfd20-0x10080f300 __DATA.__cfstring
Mem: 0x10080f300-0x100811498 __DATA.__objc_classlist (Normal)
Mem: 0x100811498-0x1008114d0 __DATA.__objc_nlclslist (Normal)
Mem: 0x1008114d0-0x100811890 __DATA.__objc_catlist (Normal)
Mem: 0x100811890-0x1008118e8 __DATA.__objc_nlcatlist (Normal)
Mem: 0x1008118e8-0x1008123b0 __DATA.__objc_protolist
Mem: 0x1008123b0-0x1008123b8 __DATA.__objc_imageinfo
Mem: 0x1008123b8-0x10092bf38 __DATA.__objc_const
Mem: 0x10092bf38-0x100944b20 __DATA.__objc_selrefs (Literal Pointers)
Mem: 0x100944b20-0x100944c88 __DATA.__objc_protorefs
Mem: 0x100944c88-0x100946ee0 __DATA.__objc_classrefs (Normal)
Mem: 0x100946ee0-0x100948918 __DATA.__objc_superrefs (Normal)
Mem: 0x100948918-0x10094ee80 __DATA.__objc_ivar
Mem: 0x10094ee80-0x100965188 __DATA.__objc_data
------
我們可以通過jtool - JCOLOR=1 jtool -v -d objc teamblind.decrypted的 objc 選項轉儲類與方法。
還需要說明一點,雖然本文使用IDA,讀者完全可以根據自身反匯編需要使用jtool,例如研究某個特殊類時輸入jtool -d UserControl:getSecretUserDefaultString: teamblind.decrypted。
破解加密值
現在,我們已經成功攔截流量,但如何破解加密流量成為難題。不妨先找出加密實現方法。如上文所述,Blind允許通過工作郵件或LinkedIn賬戶登錄。登錄后將看到創建賬戶選項:
應用設置可在com.teamblind.blind.plist中查找,具體位置在 /private/var/mobile/Containers/Data/Application/<app_id>/Library/Preferences/com.tea mblind.blind.plist。此時,檢查文件就會發現其中包含明文電子郵件以及登錄時填寫的公司信息。可以使用plutil實用程序讀取文件。
一旦輸入密碼、用戶名,點擊“開始”后就是另一番景象了。

現在,你的電子郵件不再以明文存儲而是經過加密,新增了密碼與其他幾個值。牢記千萬不要在plist文件中存儲密碼等敏感信息。敏銳的讀者可能會注意到我并沒有隱藏password_enc值。秘鑰名稱以_enc結尾表示該值可能被加密,但事實是否果真如此?另外,應注意該值是加密過程必不可少的一部分,具體原因將在后文介紹。接下來,我們將繼續探索關于這個值的更多細節。
“加密”密碼僅是一個md5哈希值,可以在AuthCompleteViewController的requestPassword中看到。
在 0x000000010004EB50 位置得到用戶提供值后計算 0x000000010004EB8C 位置的md5 哈希值。為了證實這一點,我們在與上文plist取值相同處使用Python。現在,我的超級密碼一目了然。
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update("password#1")
>>> print m.hexdigest()
5486b4af453c7830dcea12f347137b07
>>>
識別ViewControllers
為了確定需要檢查的類,我首先來到賬戶創建頁面,用cycript 確定ViewController外觀:
root@Jekyl (/var/root)# ps aux | grep blind
mobile 4136 0.1 5.8 815696 59532 ?? Ss 4:10PM 0:06.85 /var/containers/Bundle/Application/3C411AB3-6018-4604-97D2-DC2A546EAB85/teamblind.app/teamblind
root 4139 0.0 0.0 657104 212 s000 R+ 4:11PM 0:00.01 grep blind
root@Jekyl (/var/root)# cycript -p 4136
cy# [[[UIWindow keyWindow] rootViewController] _printHierarchy].toString()
"<UINavigationController 0x15615d000>, state: appeared, view: <UILayoutContainerView 0x157415a30>\n | <RootViewController 0x1570db260>, state: disappeared, view: <UIView 0x157337ab0> not in the window\n | <AuthCompleteViewController 0x155f587c0>, state: appeared, view: <UIView 0x155da07a0>"
cy#
別忘了你的電子郵件經過加密處理。加密慣例也在requestPassword 方法中呈現。你的電子郵件首先通過 plist(NSUserDefaults) 找回,然后傳輸至NSString ([NSString encryptHES256:]) encryptHES256 方法。
encryptHES256方法在過渡至AES256EncryptWithKey方法(涵蓋加密過程)前生成帶有密碼簡單異或的加密秘鑰和一些“隨機”值。從技術角度看,此方法調用另一個功能,但整體情況已趨向明朗,不難發現“隨機性”。

Frida
稍微借助Frida就可以看到實際效果。對于還不了解 Frida的讀者,我強烈建議您將這款工具添加至兵器庫并在使用go腳本前檢查Frida CodeShare。當然,代碼運行前的例行檢查無論何時都是必要步驟。
通過Frida與CodeShare ObjC method observer腳本,我們能夠觀察到AES256EncryptWithKey方法起到的作用:
macho-reverser:BLIND macho-reverser$ frida -U --codeshare mrmacete/objc-method-observer -f com.teamblind.blind
____
/ _ | Frida 10.6.15 - A world-class dynamic instrumentation framework
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at http://www.frida.re/docs/home/
Spawned `com.teamblind.blind`. Use %resume to let the main thread start executing!
[iPhone::com.teamblind.blind]-> %resume
[iPhone::com.teamblind.blind]-> observeSomething('*[* *AES256EncryptWithKey:*]');
(0x125fcdca0) -[NSData AES256EncryptWithKey:]
AES256EncryptWithKey: password#1^0123456789abcdefghijk
0x1001b25cc teamblind!0x11e5cc
0x1000e2c7c teamblind!0x4ec7c
----
現在,密碼與電子郵件加密方式已知。基本說來,重復以上步驟就能找到其他加密值。接下來,了解實際流量。
如上文所述,設備出口流量監控結果顯示,所有請求均包括一個載荷。在IDA中搜索字符串后發現多數請求參數在[NetworkControl encRequestWithParams:showAlert:completionBlock:failBlock:] 方法中設置。

encRequestWithParams
此方法首先嘗試找回之前生成的加密秘鑰與初始化向量(IV),如果失敗則調用 EncriptControl 類 makeKeyAndIvForEnc (-[EncriptControl makeKeyAndIvForEnc]) 方法。沒錯,是帶有IV的Encript。 或許可稱之為隱匿式安全……:)

makeKeyAndIvForEnc
這種做法的有趣之處在于加密秘鑰通過用戶密碼與硬編碼值組合生成。還記得之前提到的加密密碼(password_enc)嗎?該方法首先嘗試將其找回:

根據硬編碼值生成另一個md5哈希值:
如果涉及用戶密碼找回問題,則再生成一個哈希值:

最后,秘鑰設置完畢,以 hash1+hash2 或 hash1+password_enc 組合結尾。
在此例中,加密秘鑰應為 md5("QkdEhdk") + md5(“password#1"),并由此得到“c07bcdc2 3522ed81 fb76db0c 0c4387cf 5486b4af 453c7830 dcea12f3 47137b07”。
該方法的其余部分用于設置初始向量(IV):
沖破黑暗
NetworkControl 類 encRequestWithParams 方法通過調用EncriptControl 類makeKeyAndIvForEnc設置加密。設置完畢后使用encRequestWithParams 方法調用 EncriptControl 類makePayloadDataWithJsonString。該方法使用之前提及的加密秘鑰與IV調用CocoaSecurity aesEncryp,結果返回base64 編碼密文,也就是Burp呈現的內容。
暫時返回 jtool -d objc dump,注意 EncriptControl 類實例變量:
收集到所有線索后編寫Frida腳本,獲得實例變量,即加密秘鑰、明文數據與相應密文:
if(ObjC.available){
var makeKandIv = ObjC.classes.EncriptControl["- makePayloadDataWithJsonString:"];
Interceptor.attach(makeKandIv.implementation, {
onEnter: function(args) {
/* Get Class/Params */
var obj = ObjC.Object(args[0]);
var params = ObjC.Object(args[2]);
/* Get ivars */
var ivar = obj.$ivars;
// Print ivars values
console.log("-----------------------------------------------------------\n");
console.log("_encKey: " + ivar["_encKey"] + "\n");
console.log("_encIv: " + ivar["_encIv"] + "\n");
console.log("_encIvStr: " + ivar["_encIvStr"] + "\n");
console.log("_encKeyForDM: " + ivar["_encKeyForDM"] + "\n");
console.log("_encKeyForDM: " + ivar["_encIvForDM"] + "\n");
console.log("-----------------------------------------------------------\n");
console.log("PARAMS: " + params);
},
onLeave: function onLeave(retval) {
console.log("Encrypted Payload: " + new ObjC.Object(retval).toString() + "\n");
}
});
}
現在變成:
此外,連接EncriptControl 類convertDictionaryEncWithResultStr: 方法后打印出服務器響應明文。這時需要考慮將Brida Burpsuite 插件用于其他選項。
結語
Ok,今天就到此為止。如前文所述,我沒有注冊Blind 賬戶,因此無法使用會員功能。但這些都無妨,我只對Burp上的一些數據感興趣。考慮到應用程序性質與要求,我打算探索更多內容。因此,并無惡意流量發送至Blind服務器。
Happy hacking!!!
本文可用于圍繞Blind應用開展進一步調研。對于提供信息的采用,本博客不承擔任何責任。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/440/
暫無評論