Create:20170814
此文章源于一起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
相关信息提取
AccessibilityAction#ACTION_CLICK
快手个人信息展示页ProfileActivity
中的View.
APP遇到这种劫持通常想到的解决方法有两种选择:
下图为微信分享的快手个人主页
所以现在有两个防御思路三个方案来解决此问题.
阻止辅助功能模拟点击
performAccessibilityAction
方法或者设置AccessibilityDelegate
,过滤掉AccessibilityNodeInfo.ACTION_CLICK
和 AccessibilityNodeInfo.ACTION_LONG_CLICK
等事件.如果不考虑视觉障碍用户可以过滤掉全部AccessibilityNodeInfo
事件来完全禁止AccessibilityService
对app内view
的管控.阻止补刀小视频启动快手导出的ProfileActivity.
也就是进行Activity
发起方的身份认证.
Referrer
检测,通过反射拿到mReferrer
即调用方包名再验证签名.Service
中转,通过bindService
的导出方法拿到调用方uid
,再通过uid
获取待验证的包名和签名.从安全性来看方案二较好,就快手此例的业务切合度来看结合方案零和方案一比较合理.
方案利弊:
ProfileActivity
以及监控关注动作是否完成.重写performAccessibilityAction
方法,忽略AccessibilityService
传来的事件.让模拟点击失效.
1.重写View类代码
2.为View设置AccessibilityDelegate
example
方案利弊:
仅支持android5.1以及更高版本android手机.
不需要Activity
正常调用方做改动.
可以绕过,Referrer
本质不可信.
hook
操作自身进程内的ContextWrapper / ContextImpl
关于packageName
的Method
和Field
.Accessbility
或者URL scheme
通过浏览器中转一次,从而以浏览器的Referrer
启动ProfileActivity
.Activity自带的getCallingPackage()是可以获取调用方包名的,但是此法只限调用方执行的是startActivityForResult(),如果执行的是startActivity()得到的结果将是null.
这里无法限制调用方执行何种方法,所以行不通.
上图getReferrer()
有三个return Referrer
的调用,谷歌确把相对可靠一点的放在最后,应该是为了更高的可用性..
API 22也就是Android 5.1开始支持getReferrer()
方法,通过getReferrer()
得到的uri即是调用者的身份.但是前提是调用方没有使用
intent.putExtra(Intent.EXTRA_REFERRER,Uri.parse("android-app://mi.bbbbbbbb"));
intent.putExtra(Intent.EXTRA_REFERRER_NAME, "android-app://mi.ccccccc");
@Override
public Uri onProvideReferrer() {
super.onProvideReferrer();
Uri uri = Uri.parse("android-app://mi.aaaaaaaaa");
return uri;
}
也就是说getReferrer()
得到的值是可以被伪造的不是安全可靠的功能不可信,谷歌API里也提示了这点.
从代码中看来getReferrer()
本质也是intent
操作,只不过由系统隐藏完成.所以调用再次执行putExtra
操作即可覆盖之前EXTRA_REFERRER_NAME
.
此法解决了前面提到的Referrer
被伪造的问题,但是并不能解决Referrer
不可信的本质.
关键代码如下
demo app 效果如下
mReferrer
赋值依赖调起方传入的参数,所以也是能伪造的,只是伪造相对前两种姿势要麻烦一点.通过反射或者hook
操作自身进程内的ContextWrapper / ContextImpl
关于packageName
的Method
和Field
.
方案利弊:
Activity
正常调用方做改动,由startActivity
改为bindService
因为Intent并不直接携带身份信息,所以无法通过startActivity
所传的Intent直接验证调用方身份.而Bound service
可以通过Binder
的getCallingUid
得知调用方uid
,再通过PMS
拿到uid
对应的包名和应用签名.所以可以通过service
中转一下完成身份认证这个需求,将Activity
不导出转而导出Sevice
,再service
中完成包名和签名的黑白名单验证后再决定是否启动相关Activity
.即完成了身份验证.
关键代码如下
https://github.com/WooyunDota/StartActivityCheck
Accessibility
既然可以用来攻击竞品APP,那么攻击Android手机也可以的,这里以华为手机本地备份举例.
华为手机可以本地备份的数据有:
通讯录
多媒体数据
应用及数据
系统数据
这就意味着我们通过Accessbility
模拟点击窃取备份文件的话就可以得到以上数据.
如果不慎中招意味着几乎将手机上所有数据拱手送人.
攻击流程:
检测/sdcard/HuaweiBackup/backupFiles
是否有用户自己完成的历史无加密备份可用(另外一个目录backupFiles1为加密备份
).
诱导用户获取Accessbility
权限,从快手互粉/自动抢红包/免root安装这些需求来看这个攻击条件达成的难度并不高.
overlay
攻击(CVE-2017-0752
)来获取Accessbility
权限.检测空闲,检测屏幕状态,采集陀螺仪/加速度传感器.减少用户对模拟点击的感知.
利用辅助功能模拟点击完成无加密备份.开始备份后切换到后台减少感知.
从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 华为致谢修复漏洞
https://stackoverflow.com/questions/5383401/android-inject-events-permission
http://blog.csdn.net/alan480/article/details/52223920