Android Accessibility點擊劫持攻防

作者:瘦蛟舞@小米安全

0x00 快手互粉劫持事件

此文章源於一起Accessibility模擬點擊劫持.

補刀小視頻和快手互為競品應用,目標群體類似.而快手用戶量級明顯多於補刀.快手很多用戶有互粉需求,於是補刀小視頻開發了快手互粉助手來吸引快手用戶安裝.互粉助手這個功能主要是利用Accessibility.

之前接觸Android輔助功能AccessibilityService模擬點擊都是用於諸如應用市場的免root自動安裝功能或者紅包助手自動搶紅包功能,另外還有一些惡意軟體會使用這個特性.

此次用於劫持其他App達到推廣自身的目的倒是令人感到好奇於是分析了一下寫出此文.供以後有類似場景需求的做參考.

劫持男豬腳補刀小視頻利用Android模擬點擊的介面做了一個快手互粉的功能,下面先分析一下補刀APP是如何完成此功能的.

互粉功能入口com.yy.budao/.ui.tools.AddFansWebActivity

AccessbilityService輔助功能的授權需要用戶手動去完成.(通過一些Android系統漏洞可以繞過此步驟)

通過快手的scheme偽協議kwai://profile/uid啟動到需要互粉用戶的個人界面

08-14 10:29:03.869 893-3614/? I/ActivityManager: START u0 {act=android.intent.action.VIEW dat=kwai://profile/18070291 pkg=com.smile.gifmaker cmp=com.smile.gifmaker/com.yxcorp.gifshow.activity.ProfileActivity} from pid 1198

08-14 10:29:03.989 893-917/? I/ActivityManager: Displayed com.smile.gifmaker/com.yxcorp.gifshow.activity.ProfileActivity: +106ms

adb手動驗證一下adb shell am start -n com.smile.gifmaker/com.yxcorp.gifshow.activity.ProfileActivity -d kwai://profile/18070291

最後由輔助功能完成模擬點擊關注

補刀APP對快手APP的Activity和VIEW相關信息提取

0x0010即是輔助功能的點擊事件AccessibilityAction#ACTION_CLICK

快手個人信息展示頁ProfileActivity中的View.

APP遇到這種劫持通常想到的解決方法有兩種選擇:

  • 不導出被劫持啟動的Activity,但是快手這裡確實需要導出給正常APP如微信打開以提升用戶體驗.
  • 通過申明permission保護Activity,但是如果級別為dangerous劫持者同樣可以申明此permission,級別為signature又與微信簽名不同不能實現.

下圖為微信分享的快手個人主頁

所以現在有兩個防禦思路三個方案來解決此問題.

  • 阻止輔助功能模擬點擊
    • 方案零:重寫View類的performAccessibilityAction方法或者設置AccessibilityDelegate,過濾掉AccessibilityNodeInfo.ACTION_CLICK 和 AccessibilityNodeInfo.ACTION_LONG_CLICK等事件.如果不考慮視覺障礙用戶可以過濾掉全部AccessibilityNodeInfo事件來完全禁止AccessibilityService對app內view的管控.
  • 阻止補刀小視頻啟動快手導出的ProfileActivity.也就是進行Activity發起方的身份認證.
    • 方案一:Referrer檢測,通過反射拿到mReferrer即調用方包名再驗證簽名.
    • 方案二:Service中轉,通過bindService的導出方法拿到調用方uid,再通過uid獲取待驗證的包名和簽名.

從安全性來看方案二較好,就快手此例的業務切合度來看結合方案零和方案一比較合理.

0x01 方案零:重寫performAccessibilityAction

方案利弊:

  • 兼容全版本android手機(泛指API14+)
  • 不需要正常Activity調用方(比如微信微博瀏覽器)做改動
  • 有被繞過可能,劫持者只需要單獨將點擊事件剔除整個自動互粉流程,讓點擊關注由用戶完成即可.補刀APP主要負責啟動快手個人用戶界面ProfileActivity以及監控關注動作是否完成.

重寫performAccessibilityAction方法,忽略AccessibilityService傳來的事件.讓模擬點擊失效.

  1. 重寫View類代碼

2.為View設置AccessibilityDelegate

example

0x02 方案一:Referrer檢測

方案利弊:

  • 僅支持android5.1以及更高版本android手機.
  • 不需要Activity正常調用方做改動.
  • 可以繞過,Referrer本質不可信.
    • 通過反射或者 hook 操作自身進程內的 ContextWrapper / ContextImpl關於packageName的Method和Field.
    • 劫持者可以結合Accessbility 或者 URL scheme通過瀏覽器中轉一次,從而以瀏覽器的Referrer啟動ProfileActivity.

送分姿勢1:getCallingPackage()

Activity自帶的getCallingPackage()是可以獲取調用方包名的,但是此法只限調用方執行的是startActivityForResult(),如果執行的是startActivity()得到的結果將是null.

這裡無法限制調用方執行何種方法,所以行不通.

送分姿勢2:getReferrer()

上圖getReferrer()有三個return Referrer的調用,谷歌確把相對可靠一點的放在最後,應該是為了更高的可用性..

API 22也就是Android 5.1開始支持getReferrer()方法,通過getReferrer()得到的uri即是調用者的身份.但是前提是調用方沒有使用

intent.putExtra(Intent.EXTRA_REFERRER,Uri.parse("android-app://mi.bbbbbbbb"));nnintent.putExtra(Intent.EXTRA_REFERRER_NAME, "android-app://mi.ccccccc");nn@Overridennpublic Uri onProvideReferrer() {nn super.onProvideReferrer();nn Uri uri = Uri.parse("android-app://mi.aaaaaaaaa");nn return uri;nn}n

也就是說getReferrer()得到的值是可以被偽造的不是安全可靠的功能不可信,谷歌API里也提示了這點.

從代碼中看來getReferrer()本質也是intent操作,只不過由系統隱藏完成.所以調用再次執行putExtra操作即可覆蓋之前EXTRA_REFERRER_NAME.

送分姿勢3:通過反射拿到Field mReferrer

此法解決了前面提到的Referrer被偽造的問題,但是並不能解決Referrer不可信的本質.

關鍵代碼如下

demo app 效果如下

mReferrer賦值依賴調起方傳入的參數,所以也是能偽造的,只是偽造相對前兩種姿勢要麻煩一點.通過反射或者 hook 操作自身進程內的 ContextWrapper / ContextImpl 關於packageName的Method和Field.

0x03 方案二:Service中轉

方案利弊:

  • 支持全版本android手機
  • 安全性較好,難被繞過
  • 需要Activity正常調用方做改動,由startActivity改為bindService

因為Intent並不直接攜帶身份信息,所以無法通過startActivity所傳的Intent直接驗證調用方身份.而Bound service可以通過Binder的getCallingUid得知調用方uid,再通過PMS拿到uid對應的包名和應用簽名.所以可以通過service中轉一下完成身份認證這個需求,將Activity不導出轉而導出Sevice,再service中完成包名和簽名的黑白名單驗證後再決定是否啟動相關Activity.即完成了身份驗證.

關鍵代碼如下

0x04 demo代碼

github.com/WooyunDota/S

0x05 延展攻擊Android手機

Accessibility既然可以用來攻擊競品APP,那麼攻擊Android手機也可以的,這裡以華為手機本地備份舉例.

華為手機可以本地備份的數據有:

  • 通訊錄
  • 多媒體數據
    • 相機照片
    • 相機視頻
    • 錄音
  • 應用及數據
    • 微信
    • 微博
    • …..
  • 系統數據
    • 簡訊記錄
    • 通話記錄
    • 日曆日程
    • 備忘錄
    • 鬧鐘
    • WIFI密碼
    • 瀏覽器數錢
    • ….

這就意味著我們通過Accessbility模擬點擊竊取備份文件的話就可以得到以上數據.

如果不慎中招意味著幾乎將手機上所有數據拱手送人.

攻擊流程:

  1. 檢測/sdcard/HuaweiBackup/backupFiles是否有用戶自己完成的歷史無加密備份可用(另外一個目錄backupFiles1為加密備份).
  2. 誘導用戶獲取Accessbility許可權,從快手互粉/自動搶紅包/免root安裝這些需求來看這個攻擊條件達成的難度並不高.
    1. 可以利用overlay攻擊(CVE-2017-0752)來獲取Accessbility許可權.
    2. 也可以利用比如」華為wifi密碼查看器」這類功能引誘用戶開啟許可權.
  1. 檢測空閑,檢測屏幕狀態,採集陀螺儀/加速度感測器.減少用戶對模擬點擊的感知.
  2. 利用輔助功能模擬點擊完成無加密備份.開始備份後切換到後台減少感知.
  3. 從sdcard中竊取無加密的備份數據.

攻擊場景分兩種:

1.惡意應用,獲取機主隱私數據,比如wifi密碼,通信錄,簡訊等數據.對應無設備鎖檢測的app甚至可以直接利用其備份數據登錄app.對於有設備檢測的app則需要進一步繞過利用,比如微信的聊天記錄需要單獨再次解密.

2.接觸手機,繞過如沙箱保護/應用鎖等限制獲取數據.比如拿到其公司wifi密碼登錄內網.

做幾個demo

  1. 查看wifi密碼

2.以微信數據為例,惡意APP可以通過此方式突破沙箱限制獲取微信內的數據.接觸手機的人也可以繞過應用鎖查看微信聊天記錄

既然華為拿了微信的數據,那麼解密肯定不是問題.

微信的聊天記錄存儲在EnMicroMsg.db中

加密的秘鑰為(手機IMEI + 微信uin)取MD5的前7位小寫.

華為存儲備份文件的方式,記錄文件路徑和File_index索引

再將索引對應的大文件進行拆分存儲.

根據file_index拼接處完整EnMicroMsg.db. 在從shared_prefs中檢索出uin得到db的解密秘鑰.即可查看聊天記錄.

獲取IMEI的文件,從shared_prefs中拿IMEI有兩個好處1.不用考慮雙卡問題,2.不用申請READ_PHONE_STATE許可權.

demoGIF

以上問題均已提前告知相關廠商,廠商回復以及相關進度如下:

2017-09-11 通知華為PSIRT

2017-12-13 華為致謝修復漏洞

0x06 參考

stackoverflow.com/quest

stackoverflow.com/quest

blog.csdn.net/alan480/a

blog.csdn.net/u01355352

jianshu.com/p/ea38d4370

登錄 安全客 - 有思想的安全新媒體 來獲取更多資訊~


推薦閱讀:

TAG:Android | 互联网 | 网络安全 |