2014年NDSS会议上有这样一篇文章,《Screenmilker:How to Milk Your Android Ccreen For Secrets》,即怎样从你的Android手机屏幕获取你的隐私,该文章展示了一种与传统攻击方式不同的方法来窃取用户隐私,比较有意思。
Android的安全机制设计主要基于Linux的权限模型,出于安全需要,普通用户和开发人员无法直接访问系统资源,且无法自由读写其他应用内部的资源,然而对于普通用户和开发人员而言,某些需要的功能就无法实现,比如说屏幕截图功能或者手机备份功能。而要想实现这类功能,一共有两种途径:一种是root手机,但这种方法极大地破坏了Android的安全机制,使得很多恶意app或攻击都能趁虚而入;另一种则是利用adb。
熟悉Android的人应该对adb都比较熟悉,它实际上是Android的调试桥,可以让用户或开发人员用这个命令行工具与自己的手机交互,而adb的权限比一般的手机应用程序要高,利用adb工具我们可以安装或卸载手机中的软件,可以备份或者还原手机中的数据,可以让屏幕截图等。
而在Android系统中,并未对一般的app提供屏幕截屏的API接口或相应的权限。那么如果一个应用需要实现手机截图的功能,应该怎么办呢(由于天朝的特殊第三方市场环境,我们暂时只考虑外国正规app市场中截屏app的实现)?答案是利用adb代理。adb代理实际上是一个由开发人员开发的原生可执行程序,它与adb具有相同的功能和权限,要实现屏幕截屏功能的app利用adb代理来访问Android的系统资源,包括FrameBuffer里的数据,而从FrameBuffer中可以得到屏幕截图,具体流程示意图如下:
而用户安装方法也很简单,下载app的同时会得到一个adb代理的程序,用户通过电脑将该程序利用adb安装到手机中即可。
问题就在这里,在截屏app与手机中的adb代理程序通讯时是通过socket通信的,且通常并未进行身份验证,那么如果手机中存在恶意app,它同样可以通过相同的端口号来与adb代理程序通讯。也就是说,如果恶意app知道截屏app与adb代理通信的端口号,那么恶意app就能在用户不知情的情况下访问手机的截屏。
一种新的隐私泄露方式诞生了,然而怎样利用这个漏洞更加隐秘地得到更多用户隐私信息呢?我们知道手机截图往往占有比较大的存储空间,特别是如果攻击者还必须把截图上传到服务器,更加困难的是如果不知道上传的图片是否有利用价值则需要一次性发送许多图片,然后在服务端判断哪些图片有利用价值。这样一来恶意app将消耗大量的内存和上网流量,很容易被用户发现。另一方面,如果在手机中再注入图像识别的程序,同样要消耗大量的cpu的使用时间,也很容易被用户发现。于是作者想出了以下即隐秘又有效的攻击方式。
1.首先建立常用的截屏app的数据库,一个app对应一个socket端口号。恶意程序在手机中首先利用PackageManager来列出系统中的所有程序,来判断该手机是否安装有截屏app,并根据包名来判断手机中adb代理的端口号。
2.探测要攻击的app是否在运行中,此处要攻击的app主要指通讯录或者银行app或带有支付功能的app,这样就能窃取用户的联系人信息或用户银行账号密码等十分重要的隐私数据,探测方法主要是读取/proc/[PID]/stat字段的信息,通过cpu的运行时间变化来判断目标app是否在运行中。
3.判断要攻击的app正处在哪个activity,由于一个app中的大部分activity的标题栏都不一样,因此可以将activity的标题栏作为标识,此时就得用到截屏功能,即截屏后只读取标题栏的像素值,对其进行hash,将hash出来的值与事先得到的hash表(恶意app中存有一个受攻击的app各个页面标题栏的hash值)进行对比,来判断此时app处于哪个界面。若是支付界面或登录界面,就进行下个攻击动作。
4.接下来每秒钟探测5次手机键盘的敲击状态,此处的探测比较巧妙,即利用截屏来判断用户正在敲击哪一个健,如下图所示:
由于每敲击一个键,比如a,a就会变为蓝色(作者的默认键盘),并且a字母的上方会出现一大块蓝色的a方块,因此攻击者只用读取四条红线区域中的像素值,然后根据读取像素值得hash值来判断用户点击的是哪一个健,同样读取↑健的像素值可以判断此时用户打的是大写字母还是数字。而一秒钟五次的读取速度超过了绝大部分人的打字速度,因此基本可以不遗漏地读取到用户所有的敲击键盘的动作。
5.根据作者敲击键盘的字母或数字序列来判断用户的用户名或者密码,从而获取到用户隐私。
本文只是阐述了截屏app的漏洞以及一种可行的攻击方式,当然,用户所使用的手机与键盘颜色可能存在不同,因此hash表也不一样,将这种攻击方式运用到实际中有一些困难。