安卓Activity劫持与反劫持
0x00前言
近日,挪威一家APP安全公司Promon发现并报道了一个特性漏洞已经被多个恶意应用利用的分析报告,他们通过监测发现该漏洞使恶意软件可以伪装成任何合法的应用程序,从而使黑客可以访问私人短信和照片,窃取受害者的登录凭据,跟踪位置或记录电话对话,甚至可以通过手机摄像头和麦克风进行监视。
研究人员将该漏洞命名为StrandHogg,这是北欧人的一种北欧海盗战术,袭击沿海地区掠夺并扣除押金。据统计目前至少已有500个利用此漏洞的恶意应用,其中包括最早在2017年观察到的BankBot银行木马的变种。
研究人员对此漏洞的原理深入研究后发现这是一种对“Activity劫持”的攻击方法。
0x01 StrandHogg攻击手法
该漏洞使恶意应用程序有可能在伪装成合法应用程序的同时请求权限。攻击者可以请求获得任何许可,包括SMS,照片,麦克风和GPS,从而允许他们阅读消息,查看照片,进行窃听和跟踪受害者的活动
简单来说,要么攻击者通过该漏洞,请求获取应用权限,要么攻击者利用类似“界面劫持”的方式,弹出钓鱼界面让你输入账户密码
0x02 StrandHogg攻击原理
实际上,该漏洞在2015年就已经被宾州州立大学进行了研究和报道,研究人员从理论上描述了该漏洞实现方法。谷歌当时否认了该漏洞的严重性,但Promon有确凿的证据表明黑客正在利用StrandHogg来获取对设备和应用程序的访问权限。
而关键在于利用该特性漏洞,可以根本不需要root即可钓鱼获取各种权限,甚至用户账户密码。
他利用Android的多任务系统中的一个弱点来实施强大的攻击,使恶意应用程序可以伪装成该设备上的任何其他应用程序。此漏洞利用基于一个称为“taskAffinity”的Android控件设置,该控件允许任何应用程序(包括恶意应用程序)*地采用其所需的多任务处理系统中的任何身份。
Android的多任务处理机制使得用户可以在不同的应用程序之间方便的切换,当前进程被切换到后台时,多任务机制会让进程进入暂停的状态,只会在内存中保存应用的运行状态,因此不会占用CPU的资源。
然而,Android的多任务处理机制以及Activity的设计自身却存在一些缺陷,“Activity劫持“大部分采用了界面覆盖或强行关闭目标进程并弹出虚假界面的方式,通常通过监听系统日志、枚举当前进程等方式来实现其攻击目标。
0x03 Activity劫持原因
Activity劫持是基于Activity所在任务及返回栈相关属性进行劫持的一种手段.通过一定的属性设计,可以实现Activity在不同任务之间的转移及覆盖等行为。
在进行安卓APP开发过程中,如果在启动一个Activity时,给他加入一个标志位FLAG_ACTIVITY_NEW_TASK,就能使他置于栈顶并立马呈现给用户。针对这一操作,假使这个Activity是用于盗号的伪装Activity呢?在Android系统当中,程序可以枚举当前运行的进程而不需要声明其他权限,这样子我们就可以写一个程序,启动一个后台的服务,这个服务不断地扫描当前运行的进程,当发现目标进程启动时,就启动一个伪装的Activity。如果这个Activity是登陆界面,那么就可以从中获取用户的账号密码。
简单的说就是APP正常的Activity界面被恶意攻击者替换上仿冒的恶意Activity界面进行攻击和非法用途。界面劫持攻击通常难被识别出来,其造成的后果不仅会给用户带来严重损失,更是移动应用开发者们的恶梦。举个例子来说,当用户打开安卓手机上的某一应用,进入到登陆页面,这时,恶意软件侦测到用户的这一动作,立即弹出一个与该应用界面相同的Activity,覆盖掉了合法的Activity,用户几乎无法察觉,该用户接下来输入用户名和密码的操作其实是在恶意软件的Activity上进行的,最终会发生什么就可想而知了。
0x04 Activity劫持攻击手段
- 监听系统Logocat日志,一旦监听到发生Activity界面切换行为,即进行攻击,覆盖上假冒Activity界面实施欺骗。开发者通常都知道,系统的Logcat日志会由ActivityManagerService打印出包含了界面信息的日志文件,恶意程序就是通过Logocat获取这些信息,从而监控客户端的启动、Activity界面的切换。
- 监听系统API,一旦恶意程序监听到相关界面的API组件调用,即可发起攻击。
- 逆向APK,恶意攻击者通过反编译和逆向分析APK,了解应用的业务逻辑之后针对性的进行Activity界面劫持攻击。
0x05 Activity劫持调度机制
android为了提高用户的用户体验,对于不同的应用程序之间的切换,基本上是无缝。他们切换的只是一个activity,让切换的到前台显示,另一个应用则被覆盖到后台,不可见。Activity的概念相当于一个与用户交互的界面。而Activity的调度是交由Android系统中的AmS管理的。AmS即ActivityManagerService(Activity管理服务),各个应用想启动或停止一个进程,都是先报告给AmS。 当AmS收到要启动或停止Activity的消息时,它先更新内部记录,再通知相应的进程运行或停止指定的Activity。当新的Activity启动,前一个Activity就会停止,这些Activity都保留在系统中的一个Activity历史栈中。每有一个Activity启动,它就压入历史栈顶,并在手机上显示。当用户按下back键时,顶部Activity弹出,恢复前一个Activity,栈顶指向当前的Activity。
0x06 Activity劫持实现
开发一个简单的APP应用来测试界面劫持,大体逻辑是程序启动时获取到本机上已安装的所有应用信息,然后人为添加想劫持的应用,程序在后台不断监听Activity栈顶元素判断应用信息是否与攻击者添加的应用信息一致,发现如果用户点击了被劫持的应用,则给伪造的页面添加一个标志位“FLAG_ACTIVITY_NEW_TASK”使其马上进入栈顶,替换掉本应该是用户点击正常加载的应用界面,从而实现界面劫持。
获取本机上已安装应用的package信息。并打印如下:
攻击者在下图所示位置,添加想劫持的应用包信息。但是如何知道包信息呢,答案很简单,因为攻击者想要增加劫持的成功率,他会选用一些用户体量大的应用,一些能被很多人下载的应用,而这些应用的包信息是公开的,这就解决了包信息的问题。
下图展示的代码,就是处理劫持攻击的逻辑代码。程序读取Activity栈顶的元素,判断他的包信息跟设定的包信息是否相符。相符的话立刻调用Camera_layout.xml(伪造页面),并添加一个标志位“FLAG_ACTIVITY_NEW_TASK”,将他立刻置于栈顶位置取代原先的正常页面,实现界面劫持。
劫持程序界面:
劫持成功界面:
0x07 Activity反劫持防护手段
目前,还没有什么专门针对 Activity 劫持的防护方法,因为,这种攻击是用户层面上的,目前还无法从代码层面上根除。但是,我们可以适当地在 APP 中给用户一些警示信息,提示用户其登陆界面以被覆盖。在网上查了很多解决方法如下:
- 针对用户:
Android手机均有一个HOME键(即小房子的那个图标),长按可以查看到近期任务。用户在要输入密码进行登录时,可以通过长按HOME键查看近期任务,比如说登录微信时长按发现近期任务出现了微信,那么我现在的这个登录界面就极有可能是一个恶意伪装的Activity,切换到另一个程序,再查看近期任务,就可以知道这个登录界面是来源于哪个程序了。 - 针对开发人员:
研发人员通常的做法是,在登录窗口或者用户隐私输入等关键Activity的onPause方法中检测最前端Activity应用是不是自身或者是系统应用,如果发现恶意风险,则给用户一些警示信息,提示用户其登陆界面以被覆盖,并给出覆盖正常Activity的类名。
在 Acitivity 的 onStop 方法中 调用封装的 AntiHijackingUtil 类(检测系统程序白名单)检测程序是否被系统程序覆盖。
在前面建立的正常Activity的登陆界面(也就是 MainActivity)中重写 onKeyDown 方法和 onPause 方法,判断程序进入后台是否是用户自身造成的(触摸返回键或 HOME 键)这样一来,当其被覆盖时,就能够弹出警示信息。