Group of Software Security In Progress

GoSSIP @ LoCCS.Shanghai Jiao Tong University

Understanding and Defending the Binder Attack Surface in Android

论文下载

密歇根大学 Huan Feng and Kang G. Shin

  • 最近几年诸多CVE都是与binder相关,但都是以之为入口点,没有真正讨论过binder的安全。
  • 作者发现这种攻击的本质在于攻击者可以直接通过操控binder接口来给系统服务注入错误,而系统并没有对数据来源做到很好的鲁棒性。
  • 为了解答这个问题,作者调查了98个google的服务,以及72个三星的服务,以及137个造成崩溃的漏洞。发现数据的校验仅仅在binder的客户端的API上做了,在binder的服务端并没有。例如没有通过public API暴露的RPC参数,以及后续针对这些参数的(反)序列化都没有保护。证明binder的信任边界出错了,这主要由于Android提供了AIDL能够帮助开发者自动生成接口。
  • 作者开发了bindercracker,用来fuzz binder的漏洞,并能够7倍于单纯的黑盒测试效果。并提供了系统及的诊断工具用来binder攻击。

Fig

  • 攻击模型为 APP开发者可以任意构造binder客户端,来调用系统服务端的binder。

Fig

人工审查了binder的漏洞,结果为

Fig

  • 漏洞大多由于由于数据检查发生在调用Public API上,而对于直接对binder发送的数据没有做校验。
  • 包括攻击者可以
    1. 直接给没有通过public API暴露给开发者的RPC方法传参,
    2. 以及有些RPC虽然暴露给public API,但检查也在public API之前,直接调用这些RPC也能导致崩溃
    3. 利用序列化和反序列化过程中校验不严格,直接修改序列化过的数据,导致服务端反序列化的崩溃。

例如IAudioFlinger提供了RPC方法REGISTER_CLIENT,这个方法只会被系统中间层调用,并没有暴露给开发者,所以对于这个RPC的参数,系统服务就不会校验。如果直接通过对binder driver发送一个空参数,就能让这个服务崩溃。系统开发者直接认为RPC接口是外部无法访问的,这个假设是错误的。

这些错误都因为系统开发者认为的信任边界是错误的,他们认为客户端的public API是开发者唯一可以调用的。这种假设也是因为Android提供的AIDL会自动生成代码,帮助开发者完成binder通信,序列化等,事实上,开发者或者攻击者可以完全不需要使用AIDL,而自己手动调用binder和RPC。

Fuzz工具开发

  • 主要问题在于参数的复杂性,以及input可能来自别的binder的output。
  • bindercracker开发了两个组件:
    • 一个记录组件,作为系统中的一部分,收集binder通信的信息
    • 而fuzz组件作为用户层的APP,用来重放和改变记录下来的binder通信内容。

记录组件在binder通信的序列化过程中进行插桩,可以动态的监控到所有的参数类型和结构,并记录下依赖关系。然后fuzz组件通过对最外部的那次通信数据进行修改来fuzz。主要通过修改binder_transaction_data结构体中数据来进行Fuzz。首先需要找到binder的对应系统服务和具体的RPC方法的关系,这个可以通过解析代码和动态的方式找到对应关系。其次是控制一次binder通信中的数据。

Fig

基本思路就是通过记录下来的binder通信数据可以获取数据结构和必要的依赖信息,最后精确的找到真正需要fuzz的参数数据,保持其他的都不变,只改变一个参数值,这样来fuzz。观察binder服务端的反应,如果服务端接受了数据,并且没有catch到异常导致崩溃,则认为fuzz成功。

结果运行了30个APP,抓取到了超过一百万个binder通信数据,通过对每个RPC接口的binder数据采样,最后fuzz了78个系统服务的445个RPC方法,找到了89个漏洞。7倍于同样时间的单纯黑盒测试效果。此外通过简单配置,可以直接对基于binder机制更高一层的Intent做fuzz,并找到了超过20个intent通信的漏洞,主要在反序列化的阶段。

防御

  • 作者认为静态的方法可以类似android目前已有的lint工具,作用在RPC函数上,或者使用bindercracker来做动态的测试都能提高安全性。
  • 接着介绍了bindercracker找到的一系列案例的安全问题,例如可以导致崩溃,或者重启系统,或者一些提权漏洞等等。以及他们的修补情况。

Fig

最后作者尝试了在现有系统中加入动态实时的防御措施,首先尝试对类似的漏洞的入侵检测/防御。这种方法作者认为不可能实现,因为这个需要监控每个binder的参数信息,手机上性能和计算量不行,以及参数变化多端,和用户体验差。接着作者尝试对该漏洞的诊断系统,就是一旦漏洞发生,立马用可视化形式告知用户。由于一个系统服务如果照此crash,系统只会显示服务崩溃,难以找到谁发出这次通信导致的崩溃。作者利用bindercracker的记录功能,做了个可以告警的工具,供用户使用,以弥补现在系统的不足。

Fig

DSCRETE: Automatic Rendering of Forensic Information From Memory Images via Application Logic Reuse

论文下载

本文是一篇内存取证方面的文章,来自普渡大学dongyan xu老师的团队,发表于2014年的USENIX Security上,是当年两篇best student paper之一。

一作saltaformaggio已经连续几年在四大上发表了和内存取证相关的文章,近两年的文章和Android有关。

  • 本文描述了一种通过自动化重用程序代码,从内存镜像中恢复出属于该程序的可以被人理解的数据(图片、pdf、文档文件等)的技术-DESCRETE。
  • 和磁盘取证不同,内存取证最大的难点在于内存中的数据是碎片化的,同时并没有普适的连续的结构化信息(类比磁盘取证中各种文件的格式信息)可以利用。但是,在内存中存在着大量的有利用价值的数据,这些数据一般以无法直接被人理解的数据结构的形式保存于内存中,而不同的应用程序所定义的数据结构也是不尽相同,这就给自动化取证带来的极大的挑战。本文的主要目的就是解决如何对这些content of data structure fileds进行取证的问题。
  • 作者认为,对于这些应用程序内部维护的数据结构,一般在应用程序中都已经带有针对这些数据的“解释器”,这样的解释器负责将这些碎片化、抽象的数据结构组合成人能够直接理解的数据呈现形式(比如,一个图像处理软件在读入一个图片文件时,会将图片文件转化成该软件的一些内部的数据结构,然后通过系统的GUIAPI将这些内部数据结构绘制成能够显示在屏幕上的“图片”)。通过利用这些应用程序自带的“解释器”,就能够完成对内存数据的自动化“解释”,从而取证得到人可以理解的信息。

下图是DESCRETE的一次标准的取证流程:

Fig

  • 简单的说,DESCRETE的目的是寻找到一个测试函数P,P可以用来对内存镜像中的数据进行测试,判断输入的数据是否能够通过P来转换成人可以直接理解的信息。

首先,DESCRETE需要获得取证对象的创造程序的binary,DESCRETE会利用这个binary进行一些学习,从而制造出能够在内存镜像中扫描该应用程序内部数据结构的scanner。学习的第一步是运行该应用程序,确保在内存中有需要取证的数据结构的出现,以及完成一次对这些数据结构的解释输出(例如对于一个图像处理软件,需要先读入一些图片文件,然后将这些图片显示在屏幕上)。在这个过程中,DESCRETE会监控该应用程序对外部库接口以及系统API的调用,尤其是那些会将数据输出到磁盘或是其他设备上的接口。DESCRETE同时还会记录这些接口调用发生时栈和堆上的数据,供后续分析使用。在完成执行之后,descrete的使用者可以通过观察log下来的系统接口的输出,标记那些自己感兴趣的数据。之后使用传统的slicing技术,将所有和该数据生成过程有关的指令全部分离出来。

通过第一步,通过分析插装后的log记录,我们获得了很多个测试函数P的候选,下一步是确定测试函数P的截止点(closure point)。根据作者的定义,一个截止点是符合以下两个要求的一条指令:

  1. 截止点需要直接的对待取证数据结构进行操作。
  2. 在截止点之后的所有指令,对待取证数据结构的操作都基于该指令完成。符合以上两点的截止点能够确保我们在截止点出对待取证数据结构进行修改,就能够直接影响到最终输出的信息。这一步的筛选最终会产出多个截止点,根据作者的实验,截止点的个数一般在30以下,最多不超过102.

由于DESCRETE是一个全自动的取证工具,在过程中不应该有人的介入,所以接下来需要对第二步筛选出来的截止点进行自动化的测试,以此来选出真正能够使用的截止点。在这一步中,DESCRETE会使用不同于第一步的数据输入重新执行这个应用程序,当执行到一个候选截止点时,程序会fork出一个子进程,子进程初始化时,截止点所使用的数据指针会被替换,指针会被指向第一步提取出来的数据。然后子进程继续运行,当且仅当子进程顺利指令完毕并且输出和第一步相同的信息时,表示这个子进程对应的截止点是可用的,同时也意味着一个可用的P被发现了。

最后一步就是使用我们发现P去取证内存镜像,取证的过程和第三步类似。不同的是,在替换截止点数据时,使用的是待取证的内存镜像,对于镜像中的每一个字节,都会有一个子线程去验证。由于数据的特殊性,能够顺利执行完毕的子线程往往意味着成功完成了一次取证。当数据输出过程过于简单时,也会发生有很多子线程均完成执行的情况,这种时候需要人工介入对结果进行筛选。

作者使用了10款不同的真实的应用程序对DESCRETE进行了测试:

Fig

上面的表格显示了选取的10款应用程序的名字、调用的接口、取证人员关心的数据类型、调用接口时的数据大小、测试函数P候选占整个程序代码的比例、发现的截止点候选个数、能够顺利执行完毕的截止点个数、人工验证后正确的截止点个数。

Fig

上面的表格显示了在试验中,应用程序的名字、待取证的数据结构名称、数据大小、该数据结构的实例个数、DESCRETE输出结果的个数、True Positive、False Positive、False Negative。

Swords and Shields – a Study of Mobile Game Hacks and Existing Defenses

论文下载

分析mobile game hack的现状

Hacking Tools

General Hacking Tools

通用的hacking tool分两类:memory editing (GameKiller, GameCIH, and GameGuardian); local file editing (CheatDroid)

Specific Hacking Tools

还有一些为指定游戏设计的工具:例如Xmodgames,包含32个游戏的重打包版本,重打包的版本去除了原有的保护。

Analysis Techniques

Traffic Analysis

通过中间人,网络代理等来修改一些关键网络数据(金币,分数等)。难点如下:首先需要强制让APP的网络数据走分析者的代理。之后数据可能会加密。最后,网络数据可能还包括广告或数据统计的数据包,需要分析者区分。

Decompilers and Debugging Tools

反编译工具包括:dex2jar, ILSpy and JD-GUI。调试工具包括GDB,Android SSL Trustkiller等。

分析现有游戏的保护状况

  • 文章从四个方面来评估保护方法的好坏:安全,部署难度,网络流量消耗,运行效率。
  • 攻击场景:攻击者可以ROOT手机,攻击者分两类:业余选手,只会用现有工具。专业选手,可以深度分析。
  • 分析方法分四步:1)用现有工具改内存或本地文件 2)分析网络流量 3)静态分析 4)动态调试
  • 分析结果见table 1 和2。

Fig

  • 经分析,有如下几个主要防护手段:

Local Resource Protection

34%的游戏有如下保护手段:加密内存中的数据,检测内存修改行为,加密文件内数据。

Network Protections

26% HTTPS,加密网络数据,pinning,签名。还发现部分游戏网络数据不会通过代理。

Code Obfuscation and Hiding

24% 混淆

Compilation into Native Code

48% 用so

Client-Server Sync

25% 会一直同步服务器与本地的数据。

case study

Basic Memory Protection

地铁酷跑,将金币的数值与一个随机数异或,再存入内存,导致在内存中不容易定位到该数字。

Local File Protection

ZigZag,会将闯关数加密存在本地文件,因此无法直接在本地文件中搜索该数字。但是由于没保护内存中的数字,因此可以通过修改内存来修改闯关数。

Basic HTTPS

Rock Heroes用HTTPS,但是可以通过修改数据包欺骗服务器。同时作者发现这个游戏的排行榜有很多高分明显是假的。

HTTPS with Additional Protections

Game of War会做证书pinning,但是可以通过HOOK掉相关API来实现中间人。

Message Signing

Dragon City在native库中计算数据的SHA-256 HMAC作为签名。通过动态调试,在内存中发现key。最后修改数据包成功。

Communicating using Customized Protocol

Army of Toys用自定义协议,通过逆向分析,发现有双层加密。

Code Obfuscation

Kill Shot proguard混淆。

Code Hiding

Army of Toys会动态加载

Compilation into Native Code

Angry Birds会将加密函数放在SO中。作者找到了加密函数和密钥AES:StartEncryption from libAngryBirdsClassic.so.

Partial Client-Server Sync

Trivia Crack 会和服务器同步信息,但是本地还是有一些重要的计算,例如是否正确,金币是否足够等。

Full Client-Server Sync

Army of Toys时刻与服务器同步,且计算都在服务器,即使作者解密了自定义协议,还是无法hack成功。

建议

  • Local resource protection易部署,且没什么效率损耗。
  • Code obfuscation以及native code compilation依赖平台,如果开发平台支持的话也很简单,且会加速执行。
  • Traffic protection用HTTPS的话很简单,但是自定义一个好的协议就比较烦
  • Client-server sync最复杂。且效率低。

保护强度总结在table 3。

Fig

Curious Case of Rowhammer: Flipping Secret Exponent Bits Using Timing Analysis

论文下载

Sarani Bhattachary,Indian Institute of Technology,CHES’16

Combing Timing Analysis and Rowhammer

攻击模型

  • decryption oracle:RSA,对输入的密文解密,然后返回解密结果
  • Adversary:普通用户,已知明密文,可以和decryption oralce交互。目标是通过rowhammer让解密指数出错,因此需要知道secret在内存中的bank地址
  • spy:adversary引入的进程,监视解密过程,使得解密进程访问数据都是从内存中访问,并利用时间旁路确定secret所处的bank
  • k cores,k slices,c cache sets/slice, m way associative

Fig

确定evivtion set

  • Prime+Probe整体思想:由于cache组相连,攻击者可以占满一个cache set的所有组(Prime),当victim有cache进入这个set时,攻击者原有的cache被挤出,攻击者可以再次访问自己的数据看到时间差(Probe)。。

确定secret映射到的LLC slice

  • Prime+Probe可以确定secret所在的cacheset,攻击者可以找出m*k个映射到同一个set的地址,不断在这些地址上Prime+Probe,就可以把secret从缓存中逐出,保证decryption oracle每次都是从内存中取值

确定secret映射到的DRAM bank

  • row buffer collison的时间旁路(Drammer中也是利用这个来确定rowsize)
  • 当同时访问处于同一个bank中但在不同row的内存地址时,row buffer会清空,访问时间被比其他情况下的多 (两个进程的Collision只是理想中能发生的)

在bank中进行rowhammer

  • 在确定了secret所在的bank后,由于无法进一步获知secret所处的row,所以作者在其中进行随机的hammer,如果解密结果不对说明flip影响到了解密进程

Experimental Validation for Inducing Bit Flips On secret

  • 物理地址与cache slice的关系(RAID15)
  • 4核,12路组相连,4个cache slice,每个有2048个cache sets。
  • 攻击者mmap大块内存,通过pagemap得到物理地址,利用映射关系算出cache slice和cache set

Fig

Fig

Countermeasures and Discussion

  • hardware
  • software:ANVIL,统计cache miss
  • fault countermeasure: OpenSSL,计算两次,如果可以稳定的造出两次错误,这样的防护是无效的