Janus 二元神漏洞測試
同步發表於:http://blog.hacktons.cn/2017/12/25/janus-demo/
背景
12月9號,Andorid對外曝光了一個名為Janus
的重量級系統漏洞CVE-2017-13156)
, 由安全研究公司Guard Square發現。
Janus
原意是神話中的二元身,用於描述這個漏洞還真是貼切。
整個漏洞其實建立在文件校驗規則之上:
一個文件即是APK,又是DEX,在安裝APK和執行階段的校驗規則差異,導致可以在APK頭部附加一個惡意DEX來欺騙系統
下面我們從市場上隨意下載一個apk來做測試。
測試APK
本文涉及的測試APK,只用於單擊研究之用,請勿惡意散播或上傳,由此引發的糾紛與作者無關
可以從豌豆莢,應用寶等市場下一個測試用的APK,為了方便,我們需要選用一些體積較小的apk,如果apk較大很有可能經過了分包,替換工作會麻煩點。
這裏比較惡心的是,下載到的apk並不是我們選取的安裝包,而是豌豆莢市場,既然豌豆莢這麽強勢要入鏡,那麽姑且直接分析豌豆莢市場吧。
MD5 (Wandoujia_224660_web_inner_referral_binded.apk) = d3c1d9b2a74a3f8fd9fce38d38423c58
簽名檢查
首先檢查下豌豆莢的這個apk是不是v2簽名的,因為我們要測試的Janus
只能在v1下驗證
檢查簽名信息可以通過*.SF來確認,根據公開信息,如果v2簽名的話,會在SF文件內寫入一個字段X-Android-APK-Signed:2
豌豆莢
的SF文件名字是META-INF/DEAMON2.SF
, 比較幸運啊,可以確認其使用的就是v1簽名。
aven$ unzip -l Wandoujia_224660_web_inner_referral_binded.apk |grep META-INF
120009 12-15-17 14:38 META-INF/MANIFEST.MF
120130 12-15-17 14:38 META-INF/DEAMON2.SF
891 12-15-17 14:38 META-INF/DEAMON2.RSA
aven$ unzip -p Wandoujia_224660_web_inner_referral_binded.apk META-INF/DEAMON2.SF|less Signature-Version: 1.0 SHA1-Digest-Manifest-Main-Attributes: jq/6qzaCk3O+H4OBJsDhMXm+FvE= Created-By: 1.6.0_30 (Sun Microsystems Inc.) SHA1-Digest-Manifest: Dts4zfEM9pZstNDahVfVh4e4jGA= Name: res/drawable-xhdpi-v4/il.png SHA1-Digest: QCves3Cr/wm3X2w4PR4ESXGMBOw= Name: res/layout/dh.xml SHA1-Digest: DCuKb0PRLuNV6jTEbSDGMTEW174=
包名確認
接下來我們需要構造一個新的dex,嫁接到豌豆莢的apk前面;這裏需要確認豌豆莢使用的包名:com.wandoujia.phoenix2
package: name='com.wandoujia.phoenix2' versionCode='16861' versionName='5.68.21'
sdkVersion:'14'
targetSdkVersion:'16'
另外值得一提的是,豌豆莢的權限還是比較流氓
的會要求大量敏感權限,因此在使用該市場的時候註意權限的問題,否則很有可能裸奔了:
比如讀/寫短信,讀/寫通訊錄等等,還有一些第三方權限
uses-permission:'android.permission.READ_SMS'
uses-permission:'android.permission.RECEIVE_SMS'
uses-permission:'android.permission.MANAGE_ACCOUNTS'
uses-permission:'android.permission.AUTHENTICATE_ACCOUNTS'
uses-permission:'android.permission.USE_CREDENTIALS'
uses-permission:'android.permission.READ_SETTINGS'
uses-permission:'android.permission.READ_EXTERNAL_STORAGE'
uses-permission:'android.permission.SEND_SMS'
uses-permission:'android.permission.WRITE_EXTERNAL_STORAGE'
uses-permission:'android.permission.MOUNT_UNMOUNT_FILESYSTEMS'
uses-permission:'android.permission.INTERNET'
uses-permission:'android.permission.ACCESS_NETWORK_STATE'
uses-permission:'android.permission.ACCESS_WIFI_STATE'
uses-permission:'android.permission.CHANGE_WIFI_STATE'
uses-permission:'android.permission.CHANGE_WIFI_MULTICAST_STATE'
uses-permission:'android.permission.SET_WALLPAPER'
uses-permission:'android.permission.SET_WALLPAPER_HINTS'
uses-permission:'android.permission.WRITE_SETTINGS'
uses-permission:'android.permission.CAMERA'
uses-permission:'android.permission.FLASHLIGHT'
uses-permission:'com.android.launcher.permission.INSTALL_SHORTCUT'
uses-permission:'com.android.launcher.permission.UNINSTALL_SHORTCUT'
uses-permission:'android.permission.READ_PHONE_STATE'
uses-permission:'android.permission.MODIFY_AUDIO_SETTINGS'
uses-permission:'android.permission.SYSTEM_ALERT_WINDOW'
uses-permission:'android.permission.ACCESS_SUPPERUSER'
uses-permission:'android.permission.GET_PACKAGE_SIZE'
uses-permission:'android.permission.KILL_BACKGROUND_PROCESSES'
uses-permission:'android.permission.CLEAR_APP_CACHE'
uses-permission:'android.permission.DISABLE_KEYGUARD'
uses-permission:'com.android.launcher.permission.READ_SETTINGS'
uses-permission:'com.android.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.android.launcher3.permission.READ_SETTINGS'
uses-permission:'com.android.launcher3.permission.WRITE_SETTINGS'
uses-permission:'com.meizu.flyme.launcher.permission.READ_SETTINGS'
uses-permission:'com.meizu.flyme.launcher.permission.WRITE_SETTINGS'
uses-permission:'org.adw.launcher.permission.READ_SETTINGS'
uses-permission:'org.adw.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.qihoo360.launcher.permission.READ_SETTINGS'
uses-permission:'com.qihoo360.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.lge.launcher.permission.READ_SETTINGS'
uses-permission:'com.lge.launcher.permission.WRITE_SETTINGS'
uses-permission:'net.qihoo.launcher.permission.READ_SETTINGS'
uses-permission:'net.qihoo.launcher.permission.WRITE_SETTINGS'
uses-permission:'org.adwfreak.launcher.permission.READ_SETTINGS'
uses-permission:'org.adwfreak.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.huawei.launcher3.permission.READ_SETTINGS'
uses-permission:'com.huawei.launcher3.permission.WRITE_SETTINGS'
uses-permission:'com.fede.launcher.permission.READ_SETTINGS'
uses-permission:'com.fede.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.sec.android.app.twlauncher.settings.READ_SETTINGS'
uses-permission:'com.sec.android.app.twlauncher.settings.WRITE_SETTINGS'
uses-permission:'com.anddoes.launcher.permission.READ_SETTINGS'
uses-permission:'com.anddoes.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.lenovo.launcher.permission.READ_SETTINGS'
uses-permission:'com.lenovo.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.google.android.launcher.permission.READ_SETTINGS'
uses-permission:'com.google.android.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.oppo.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.oppo.launcher.permission.READ_SETTINGS'
uses-permission:'com.yulong.android.launcher3.permission.WRITE_SETTINGS'
uses-permission:'com.yulong.android.launcher3.permission.READ_SETTINGS'
uses-permission:'com.huawei.android.launcher.permission.READ_SETTINGS'
uses-permission:'com.huawei.android.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.htc.launcher.permission.READ_SETTINGS'
uses-permission:'com.htc.launcher.permission.WRITE_SETTINGS'
uses-permission:'com.bbk.launcher2.permission.READ_SETTINGS'
uses-permission:'com.bbk.launcher2.permission.WRITE_SETTINGS'
uses-permission:'android.permission.WAKE_LOCK'
uses-permission:'android.permission.BROADCAST_PACKAGE_ADDED'
uses-permission:'android.permission.BROADCAST_PACKAGE_CHANGED'
uses-permission:'android.permission.BROADCAST_PACKAGE_INSTALL'
uses-permission:'android.permission.BROADCAST_PACKAGE_REPLACED'
uses-permission:'android.permission.RESTART_PACKAGES'
uses-permission:'android.permission.GET_TASKS'
uses-permission:'android.permission.RECEIVE_BOOT_COMPLETED'
uses-permission:'android.permission.CHANGE_NETWORK_STATE'
uses-permission:'android.permission.GET_ACCOUNTS'
uses-permission:'android.permission.VIBRATE'
uses-permission:'android.permission.BIND_ACCESSIBILITY_SERVICE'
uses-permission:'android.permission.READ_CONTACTS'
uses-permission:'android.permission.WRITE_CONTACTS'
uses-permission:'android.permission.CALL_PHONE'
uses-permission:'android.permission.WRITE_SMS'
uses-permission:'android.permission.WRITE_CALL_LOG'
uses-permission:'android.permission.READ_CALL_LOG'
uses-permission:'android.permission.AUTHENTICATE_ACCOUNTS'
uses-permission:'android.permission.WRITE_SYNC_SETTINGS'
uses-permission:'android.permission.MANAGE_ACCOUNTS'
uses-permission:'android.permission.ACCESS_FINE_LOCATION'
uses-permission:'android.permission.ACCESS_COARSE_LOCATION'
uses-permission:'com.wandoujia.phoenix2.permission.MIPUSH_RECEIVE'
uses-permission:'android.permission.PACKAGE_USAGE_STATS'
uses-permission:'android.permission.PERSISTENT_ACTIVITY'
uses-permission:'android.permission.ACCESS_MTK_MMHW'
Hack
接下來開始編碼工作,明確下我們的目標:
- 替換Application,並且在app進程啟動時彈出一個toast;
- 替換啟動頁,顯示一個特殊文案;
因此首先安確認下豌豆莢的自定義application:com.pp.assistant.PPApplication
。
aven$ aapt dump xmltree Wandoujia_224660_web_inner_referral_binded.apk AndroidManifest.xml|less
E: application (line=155)
A: android:theme(0x01010000)=@0x7f0a0001
A: android:label(0x01010001)=@0x7f0c038a
A: android:icon(0x01010002)=@0x7f02009d
A: android:name(0x01010003)="com.pp.assistant.PPApplication" (Raw: "com.pp.assistant.PPApplication")
A: android:stateNotNeeded(0x01010016)=(type 0x12)0xffffffff
A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x3
A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff
創建同名的PPApplication的,然後加上toast即可,接下來編譯得到新的apk,並將其中的dex抽離出來備用。
插曲
在實際插入dex的時候,遇到了一些小插曲,比如插入完後,啟動崩潰,所以如果是插入全新的dex的話,需要確認和原有dex的關系,如果完全摒棄原有邏輯,那麽需要手動補全manifest中聲明的ContentProvider
和BroadcastReceiver
,Activity根據需要替換,Service可選替換
另外合並apk和dex不是簡單的字節疊加,需要修改最終apk的偏移量,確保zip的正確性。筆者使用的是一個Python腳本
https://github.com/V-E-O/PoC/tree/master/CVE-2017-13156
效果
搞定之後,可以直接安裝apk,也可以覆蓋升級安裝,接下來啟動app就可以看到完全不同的效果;
在這裏我們出於實驗性質,將豌豆莢市場的application和啟動Activity做了整體替換,因此直接感受就是原有邏輯全部沒有了,如果我們通過反編譯後增量修改的方式來新增dex,納悶可以實現和原app功能幾乎一致的串改,這樣可以惡意插入代碼,同時不容易被用戶發現。
修復
這個bug看起來挺嚴重的,不過實際上影響有限,如果用戶通過正規市場下載程序基本沒什麽問題,同時Android官方已經做fix,相信後續很快就會在新版本中生效。
對於開發者來說比較被動,最好升級簽名為V2,別的就沒有屏蔽辦法了,比較問題出在系統校驗上面。
Janus 二元神漏洞測試