繞過安卓SSL驗證證書的四種方式
在安全界打拚多年的行家一定對以前的安卓移動應用程序的安全性印象深刻,比如你可以毫不顧忌所有的SSL錯誤,並隨意攔截和修改SSL的通信。不過這種好日子已經到頭了,目前大多數的應用程序都會檢查證書是否是由有效的可信證書頒發機構(CA)頒發的。作為測試人員,我的重要任務之一就是要驗證證書是否總是有效和可信的,為此我選用了中間人攻擊(MITM)的方式來嘗試修改其通信。本文,我將介紹4種可以繞過Android SSL證書檢查的技術:
1.將自定義CA添加到受信任的證書存儲區;
2.使用自定義CA證書覆蓋已封裝的CA證書;
3.使用Frida hook並繞過SSL證書檢查;
4.逆向自定義證書代碼。
這四個技術的執行複雜度是從簡單到複雜依次排列的,不過請注意,本文只會介紹大致的操作框架,並不會過多的強調技術細節。
為什麼會選擇SSL MITM進行測試
為什麼我會選擇對移動應用程序進行SSL MITM,因為為了查看和模糊移動應用程序的網路服務調用,我需要使用攔截代理(如BurpSuite或ZAP)。當使用代理攔截SSL通信時,來自客戶端的SSL連接會在代理處被終止。默認情況下,由Burp等工具生成的自簽名證書將不具有有效的信任鏈,並且如果證書無法驗證為可信,則大多數移動應用程序將終止連接,而不會通過不安全的渠道進行連接。所有這4中技術的共同目標,就是試圖讓移動應用程序信任攔截代理提供的證書。
將自定義CA添加到受信任的證書存儲區
避免SSL錯誤的最簡單方法是擁有一個有效的可信證書,如果你可以將新的、受信任的CA安裝到設備上,則使用這種技術就相對容易一些。如果操作系統信任你的CA,則它將信任你的CA簽名的證書。
Android有兩個內置的證書存儲,分別跟蹤系統存儲操作系統(包含預安裝的CA)和用戶存儲操作系統(存儲用戶安裝的CA))信任的CA。
默認情況下,所有應用的安全連接(使用TLS和HTTPS協議)均信任預安裝的系統CA,而針對Android 6.0(API級別23)及更低級別的應用程序也會默認信任用戶添加的CA存儲。應用程序可以使用base-config(針對應用程序範圍的自定義)或domain-config(針對每個域的自定義)自定義自己的連接。
這意味著,如果我嘗試將MITM應用於Android 6.0或更低版本的應用程序,就可以簡單地將我的CA添加到用戶添加的CA存儲中。當應用程序驗證我自定義證書的信任鏈時,它會在信任庫中找到我的自定義CA,並信任我的證書。但是,如果應用程序的目標版本是6.0以上的Android版本,則不會信任用戶添加的CA存儲。為了解決這個問題,我可以編輯應用程序的manifest,強制它實現以Android 6.0版本的環境實現。目標API級別會在AndroidManifest.xml文件的「manifest」元素的「platformBuildVersionCode」屬性中指定。
上面的manifest元素的目標是「platformBuildVersionCode = 25」,我需要將其更改為23。
當應用程序使用此更新的manifest重新封裝時,它將信任用戶添加的CA存儲。再或者,如果需要在特定版本的平台上運行,則可以在APK的「/res/xml/network_security_config.xml」配置文件中定義特定的信任錨(Trust Anchor)。例如,你可以用以下文件定義需要存儲在/res /raw /my_ca的新的可信CA:
如果應用程序只是驗證所提交的證書是否有效,那麼該技術就可以實現SSL MITM。
用自定義CA證書覆蓋已封裝的CA證書
如果你已成功將證書安裝到用戶添加的CA存儲中,那麼應用程序的運行版本就是Android 6.0,並且當你嘗試瀏覽其他受SSL保護的資源時,證書也顯示為有效。不過你也許會奇怪,難道應用程序不會因SSL錯誤而崩潰嗎?由於開發者可能已經採取了額外的措施來限制應用程序所信任的CA,所以不會崩潰。回想一下技術1,我定義了一個自定義的信任錨,並提供了一個CA證書的路徑,這也是開發人員保護應用程序免受SSL攔截的方法。
如果自定義的證書鏈正在與應用程序一起使用,則提取APK並用我的自定義CA應該足以使我的攔截證書可信。請注意,在某些情況下,可能需要信任鏈的附加驗證,所以此方法可能會產生一些其它後果。
使用諸如APK Studio之類的工具打開APK,會使與已部署的應用程序捆綁在一起的證書顯而易見。在上圖中,證書位於『assets』目錄下。我的自定義CA中覆蓋一個名為「UniversalRootCA」的證書,這會讓應用程序接受我的自定義證書。
使用Frida hook並繞過SSL證書檢查
如果安裝自己的CA還不足以成功代理SSL通信,那麼應用程序就可能正在執行某種SSL Pinning或額外的SSL驗證。通常,為了繞過這種類型的驗證,我需要hook應用程序的代碼,並干擾驗證過程本身。這種類型的干擾僅限於root/jailbreak的手機,但在共享庫frida-gadget的幫助下,現在可以使用Android應用程序,並在不支持設備的情況下訪問Frida功能的完整套件。
如果你之前執行過移動應用程序滲透測試,那麼你可能熟悉Frida框架。至於如何完全覆蓋Frida的功能,則不在本文的講解範圍。簡而言之,它是一個允許你在運行時篡改應用程序代碼的框架。通常,Frida將作為一個獨立的程序在操作系統上運行,不過前提是要有一個獲得Root許可權的設備。為了避免這種情況,我可以將Frida Gadget插入到目標APK中, Frida Gadget包含了Frida的大部分功能,但封裝在一個動態庫中,在運行時由目標應用程序載入,允許你測試和修改目標應用程序的代碼。
要載入Frida Gadget,就需要提取APK,插入動態庫,編輯一些smali代碼,這樣我的動態庫就會在應用程序啟動時被調用,然後重新封裝APK並安裝它。詳細過程你可以點此查看,不過請注意需要手工完成一次,以便了解協同工作的詳細過程。但為了節省時間,我還可以使用另一種工具——objection ,objection 是一個輕量級的依賴注入框架。我只需要在命令行上提供目標APK ,Objection會自動完成整個過程。
C: >objection patchapk -s test_app.apk
No architecture specified. Determining it using `adb`...
Detected target device architecture as: armeabi-v7a
Github FridaGadget is v10.6.28, local is v10.6.13. Updating...
Downloading armeabi-v7a library to C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
Unpacking C:.objectionandroidarmeabi-v7alibfrida-gadget.so.xz...
Cleaning up downloaded archives...
Using Gadget version: 10.6.28
Unpacking test_app.apk
App already has android.permission.INTERNET
Reading smali from: C:Temp mp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
Injecting loadLibrary call at line: 10
Writing patched smali back to: C:Temp mp8dxqks1u.apktempsmalicom/test/app/TestMainActivity.smali
Creating library path: C:Temp mp8dxqks1u.apktemplibarmeabi-v7a
Copying Frida gadget to libs path...
Rebuilding the APK with the frida-gadget loaded...
Built new APK with injected loadLibrary and frida-gadget
Signing new APK.
jar signed.
Signed the new APK
Performing zipalign
Zipaling completed
Copying final apk from C:UserscwassAppDataLocalTemp mp8dxqks1u.apktemp.aligned.objection.apk to current directory...
Cleaning up temp files...
這樣,我就會在我的工作目錄中有一個名為「test_app.objection.apk」的文件——objection。默認情況下,將「.objection」附加到原始APK的名稱中。我可以像安裝任何其他APK一樣安裝此APK ,這樣它就會被adb install test_app.objection.apk推送到我的連接設備上。在目標設備上安裝了objectionAPK後,運行應用程序應該會在應用程序啟動屏幕上暫停。此時,我可以連接到Frida伺服器。
C:>frida-ps -U
PID Name
---- ------
6383 Gadget
C:>frida -U gadget
____
/ _ | Frida 10.3.14 - 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/
[Motorola Moto G (5) Plus::gadget]-> Java.available
true
Alternatively, Objection supports interaction with the listening Frida server by using the 『explore』 command:
C:>objection explore
___| |_ |_|___ ___| |_|_|___ ___
| . | . | | | -_| _| _| | . | |
|___|___|_| |___|___|_| |_|___|_|_|
|___|(object)inject(ion) v1.2.2
Runtime Mobile Exploration
by: @leonjza from @sensepost
[tab] for command suggestions
com.test.app on (motorola: 7.0) [usb] # android hooking search classes TrustManager
android.security.net.config.RootTrustManager
android.app.trust.ITrustManager$Stub$Proxy
android.app.trust.ITrustManager
android.security.net.config.NetworkSecurityTrustManager
android.security.net.config.RootTrustManagerFactorySpi
android.app.trust.TrustManager
android.app.trust.ITrustManager$Stub
com.android.org.conscrypt.TrustManagerImpl
com.android.org.conscrypt.TrustManagerImpl$ExtendedKeyUsagePKIXCertPathChecker
com.android.org.conscrypt.TrustManagerImpl$TrustAnchorComparator
com.android.org.conscrypt.TrustManagerFactoryImpl
javax.net.ssl.TrustManagerFactory$1
javax.net.ssl.TrustManager
javax.net.ssl.TrustManagerFactory
javax.net.ssl.X509TrustManager
javax.net.ssl.TrustManagerFactorySpi
javax.net.ssl.X509ExtendedTrustManager
[Ljavax.net.ssl.TrustManager;
此時,你應該能夠從內置的SSL Pinning繞過函數中獲取以下內容:
逆向自定義證書驗證碼
最後,開發人員可能會選擇提供自己的SSL庫,而不是依靠系統庫來處理SSL證書驗證。如果是這種情況,我可能還需要提取APK並將smali逆向回Java,以便我可以查找負責處理證書驗證的代碼。
使用"dex2jar",語法如下:
生成的.jar文件應該可以在你最喜歡的Java逆向工具(如JD-GUI)中打開。
一旦確定了負責證書驗證的代碼,你就可以將其完全修復或使用Frida hook所需的功能。為了避免重新構建整個應用程序,通常更有效的方法就是是將負責證書驗證的函數hook。
接著使用第3種技術就可以完成對應用程序的測試。這樣,你應該就能夠使用Frida命令行工具或Objection介面來hook函數。
總結
上面提到的這四種技術應該能滿足你在不同的運行環境中,攔截Android SSL通信,並繞過常見的防禦措施。另外,通過對objection和Frida的簡要介紹,你大概知道了它們具有繞過SSL Pinning和其他防禦措施的能力。
※黎巴嫩國家APT組織「黑山貓Dark Caracal」浮出水面
TAG:嘶吼RoarTalk |