android上的漏洞挖掘方式和Fuzz

https://www.blackhat.com/docs/asia-16/materials/asia-16-He-Hey-Your-Parcel-Looks-Bad-Fuzzing-And-Exploiting-Parcelization-Vulnerabilities-In-Android-wp.pdf
感觉翻译的有点怪异,凑乎的看哇。

Binder简介

Binder是andorid ipc通信的核心, 几乎所有的内部进程通信通过并且利用Binder机制交互,像是正常的非受信任应用或是低特权进程,孤立进程到高特权进程。例如:mediaserver,systemserver 和其他 vender-notification service。Binder有很多有用的特性例如:death-notification mechanism,unique token identity,descriptor transmission。为了执行效率,很多Binder服务是被c语言完成的,因此攻击就需要内存崩溃的bugs。

认证并组织Binder攻击的方面

认证攻击C++ 代码层的方面

开源的binder部分严格的遵循了面向对象的编码原则。代理和委派设计出的接口用来隐藏实际的执行细节,比如Binder传输和曝光。仅仅逻辑效果呈献给用户和开发者。开发者和端用户需要的仅仅是实现特定方法相同接口定义。我们就拿crypto服务在mediaserver作为一个例子。

RefBase

RefBase是一个强大的基类,是吸纳了refcount机制的。在很多没有清晰资源声明需求的时候,就可以减少可能的内存泄漏的bugs和双重释放漏洞。很多类是从RefBase继承出来的。RefBase同样适合释放通知机制相关的。这类里最重要的函数就要算是incString和decStrong。当其子类被引用或者是解引用的时候,以上两个函数就会被响应的调用。

IBinder

IBinder定义的接口例如: transact/ pingBinder, isBinderAlive,getInterfaceDescriptor,这些都会被子类共享。但是他们没有具体的实现滋生方法。

BBinder

BBinder是所有服务方法的基类。在正擦汗那个循环服务下,边界会在基于BnInterface的onTransact函数实现,这些通常是巨大分支没开箱接受数据。

BpBinder

BpBinder持有在客户端的远程服务句柄,并且是所有的客户端实现方法的基类。正常情况下,客户端需要实现onTransact函数。它包含了一些函数的实现方法,例如pingBinder 和isBinderAlive。

BpRefBase

封装了BpBinder实例,通过getter函数实现远程调用。

IInterface

自定义的服务必须继承IInterface。它使用了IMPELENT_META_INTERFACE 和 IMPLEMNET_META_INTERFACE在函数asinterface ,用来建立IBinder和商业逻辑类。
实例如下:

android上的漏洞挖掘方式和Fuzz

android上的漏洞挖掘方式和Fuzz

identifying attack surface

客户端的代理名字一般=都是以Bp开头哦的,例如BpCrypto。通常利用者会考虑,只有在BnXXX的bugs才能导致实际的提权漏洞,但是也不总是。读者必须了解到所谓的服务端实际上属于正常的用户应用,这是的客户端是生存在私有的进程例如:mediaserver。这个例子就是反向链接并且总是被用户的回调看到。我们经看到一个学习段的例子。
通过这个例子,我们枚举出所有的接口,并使用正则匹配暴露出特定的服务。更复杂准确的识别可以被字节代码级的LLVM编译器或ctags或GCC前端实现,但是将会在以后的工作中提及。

再次用Crypt service framework 在mediaserver作为例子。

Business logic interface

ICrypto 是从IInerface扩展出来的虚类,并且包含纯虚函数事件接口逻辑的定义,定义在、frameworks/av/include/media/ICrypto.h。所有的客户端和服务端实现必须从这个类扩展。
android上的漏洞挖掘方式和Fuzz

服务端的实现

Crypto 定义在 frameworks/av/medai/libmediaplayerservice/Crupto.cpp持有服务断时间逻辑的接口实现。这一部分的运行在私有的进程mediaserver中。明显这里是我们查找丰富的内存崩溃的bugs的地方。
android上的漏洞挖掘方式和Fuzz

服务端委派实现

BnCrypt 是服务端委派的实现,宽展自BnInterface,他是响应句柄和打开接收数据的封装类,之后传递合适的函数到Crypto函数类,当然返回值也是被封装并发送到调用者的。这部分的代码同样运雄在mediaserver。函数onTranscat清晰的揭示了这里是个完美的地方,用来寻找受限权限提升bugs。
android上的漏洞挖掘方式和Fuzz

客户端委派实现

BpCrypto是扩展自BnInterface的客户端封装。这部分代码运行于客户进程。这里的崩溃不会导致似有权限的提升缺陷。

android上的漏洞挖掘方式和Fuzz

通过调用API建立更新数据

由于以上复杂的封装,末端用户在调用Crypto API的时候就会非常方便。这里的引用位于 framework/base/media/jini/android_media_MediaCrypto.cpp

首先我们需要获取远程Crypto服务的引用。Crypto服务也就是所谓的中间服务,但他不会直接通过ServiceManager暴露出来。它实际上是被IMediaPlayerService暴露出来的,然后需要通过ServiceManager进行查询。而查询的服务本事是被Binder handle 0绑定的。并作为暴露一级服务的索引。
android上的漏洞挖掘方式和Fuzz

返回句柄ICrypto是一个扩展字BpInterface的BpCrypto句柄。一直持有远程binder的引用。进入mediaserver进程之后的更新数据会通过从BnCrypto到Crypto,之后就会到达实际的事件实现。

java源码的认证攻击面

java方法的Binder服务实现会有更多的错误倾向,因为一个叫做AIDL的工具被用来做客户端和服务端封装类,同事C++手写的代理类通常都是容易引进缺陷的。逻辑崩溃(权限泄露,拒绝服务,类型拒绝)一样存在。JavaBinder 服务的类名有一点不同,即使他们的名字相同。举几个PowerMangerService作为例子:

-PowerManagerService.Stub 作为服务端的封装
-PowerManagerService.Stb.Proxy 作为客户端封装
-IPowerManager作为标准的时间逻辑接口收集
-PowerManagerService 本身是服务端时间逻辑实现

通过监听以上接口,检测是否接口使用enforcePermission或者相似的调用进行守护。我们就可以找到权限泄露的缺陷所在。这类错误通常被在第三方的ROM向量中找到。正如我们在十月份找到的酷派和QIku上的Binder接口强制读写的系统私有权限一样。

在闭源二进制文件中识别攻击面

一些供货商可以添加自己的服务在本地android 系统服务上,当然是没有源码跟踪的。幸运的是符号并没有被删除,所以识别过程几乎是一样的,除非研究者需要咨询IDA而不是读朴实的源代码。我们已经找到一些内存崩溃漏洞位于华为手机的鼻渊binder服务系统服务上,细节无法公布因为还没有被修复。

数据打包和解包

基本的数据更新单元是包。Parcel.cpp定义和是吸纳了大部分的POJO读写数据类型。

打包行为在C++层和Java层是略有不同的。在C++层,基本的读写函数是read/writeInplace和read、writeAligned。基于以上两个函数,越复杂的数据传输原型被声明成16/8 readString, readBlob,等等。

在C++层,每当分配和释放一个特定类型的对象类,没有类信息会被加入到数据流中,接收端会在它希望的时候终端数据,根本没有办法检测。没有任何规定这些数据是如何被操作的。所以你需要通过在C++层的复杂数据类型,你需要写的分配的或者是没有分配的函数使用原始的数据。这些都会增加我们在案例中引入的异常。例如,考虑一下这些函数:
android上的漏洞挖掘方式和Fuzz
服务端会直接中断流。
然而,我们的说明会有一点不同位于Java层。例如Parcel.java。在Java层,可以传递更多数据类型,例如基本java数据类型java.lang.String, java.lang.BigInteger, 即使这些类没有实现分配函数自身。
查看Parcel.java 我们可以找到这个答案。此外i爱基本点额数据类型也是定义在Parcel.cpp中的, 这里有个很重要的函数叫做 read/writeValue.

android上的漏洞挖掘方式和Fuzz
我们能够看懂啊类型信息伴随着字节数据流被提供,类类型将会被字符串类型决定。然后ObjectInputStream被用来反序列化和构建类句柄。这些特性导致一些漏洞例如,CVE-2014-9711,他就是没有检查被提供 的类是否被序列化,还有CVE-2015-3825,这个是因为指针区域位于native层可以被恶意攻讦使用导致的,导致类任意读写。我们会在接下来讨论更多的案例。

Fuzzing 策略和建议

架构

我们设计我们的模糊测试器作为客户服务结构工具。就像我们上面说的,鉴于Google良好的代码编写习惯,客户代理类通常是被Bp前缀来命名的。为了成功的fuzz某个数据路径的传递过程,我们需要收集:

  • 更新数据的代码,通常被定义无符号整型1成为枚举结构。
  • 更新参数和命令,这些可以被以readxxx和writexxx的函数命名
  • 获取远程服务的方式。

服务端将会提前解析和手机C++源码文件,产生json文件并且保存它。客户端运行在模拟器,真机接受参数命令,用以更新数据,传递参数类型和命令和远程服务。客户端将会产生基于以上原则得fuzzing参数,并且发送给私有权限的服务器。服务检测mediaserver的PID通过Android debug Brigde代理。如果PID改变,那就表明溢出异常发生,日志生成,可以手动分析了。

android上的漏洞挖掘方式和Fuzz

如果在Java层的fuzzing即使就会有不同。在java层,我们的模糊测试侧重于模拟被writeValue产生的序列化字节流,并通过改变信息字符串字节位于数据流中的头不信息实现目的。这个原则有效的识别出一些漏洞,但是由于java天然的内存安全特性,这些异常仅仅是一些拒绝服务的漏洞例如OOM, 被看门狗中断杀死,等等。

结合ASAN

通过开启某项构建好的选项,我们可以把ASAN结合在整个Android系统上。我们成功的测试了这一特性在NEexus和ARM模拟器中,但是在X86模拟器中和其他型号的手机上测试失败了。这种超出预期的表现是极低的,我们可以有效的增加模糊测试的有效性。

以下命令可以开启ASAN。
make -j42
make USE_CALNG_PALTFORM_BUILD:=true ANDITIZE_TARGET= ADDRESS - j42
fastboot flash userdata && fastboot flashall

结合AFL

每当包数据更新数据其实是字节流数据,如果我们在其中加入模拟这些数据(AFL)在其中将会是一大进步。然而,这里没有独立接口位可以使用输入文件和Socket于私有进程权限构建Binder事务,也有一些问题,导致我们不能顺利构建AFl在系统文件库中。我们还在进一步研究中。

研究案例

CVE-2015-6612分析

CVE-2015-6612是一个私有权限提升的漏洞,位于libmedia.这个漏洞被官方在2015年修复。这个典型的堆溢出定位在Crypto服务框架,我们将给出细节分析在本小节。

正如接下来代码所示,一个可利用的Crypto server提供的服务就是解密。
android上的漏洞挖掘方式和Fuzz
android上的漏洞挖掘方式和Fuzz
totalsize 是通过客户端的包中取出来的,这个我们是可以控制的。此外,subSample的内容也是可以通过包完全控制在我们的手中的。注意到,每当secure没有被设置的时候,totalSize的内存大小会被分配,返回的指针dstPtr会被传递到decrypt函数。
这里是代码最终到达的地方。
android上的漏洞挖掘方式和Fuzz

细心区分这个模式,memcpy最终会被调用。这里,dstPtr指针,totalSize大小内存的,就会被我们控制。期间,subSample.mNumBytesOfClearData同样是可控的,这会导致典型的堆溢出。利用特定的堆布局操作,源代码将会完全受控域我们,这样一个溢出就可以被我们用来构建执行在mediaserver近进程中。

CVE-2015-6622分析

一个整型溢出存在于MotionEvent::readParcel,位于系统服务进程。恶意承诺书能够导致向量大小的溢出,导致信息泄露或者OOB访问。

android上的漏洞挖掘方式和Fuzz

CVE-2015-6620(24123723)AMessage越界访问

我们前面提到过,AMessage是会被接受到的数据解包的。一下代码证明,如果攻击者输如一个无效的mNumber,越界访问将会持续发生,因为msg->mltems是一个被修改过的数组kMaxNumberItem=64.这个异常在Nexus被十二月份的公报中修复。
android上的漏洞挖掘方式和Fuzz

这里触发漏洞会有点意思。我们需要找到一个用来从用户输入解包AMessage的私有进程接口。IStreamListener->issueCommand 是一个接受用户输入的回调,在mediaserver传递, 并且调用 AMessage::fromParcel。
为了得到ISrteamListen对象,我们需要构建一个BnStreamSopurce对象,并且传递到MediaPlayer->setDataSource。当特定的媒体文件运行的时候,BnStreamSource对象的setListen回调方法会被调用,然后IStreamListener句柄被传递回客户端。我们可以调用位于Binder代理的issueComand方法,恶意数据将会被装备私有权限进程,以此触发漏洞。这是个位于客户进程得BnXXX类,当BpXXX类位于服务进程空间。

攻击还原CVE-2015-6620(24445127)mediaCodecInfo 越界(越权)访问

漏洞

CVE-2015-6620实际包含了两个缺陷,但谷歌只给了一个CVE。另一个漏洞(24445127)包含了一个似有权限提升漏洞,位于libstagefright。这个漏洞在官方十二月份2015的更新中修复了。相关服务称作IMediaCodeList有一个被命名为GET_CODE_INFO选择规则,这里是他细节实现。这个漏洞比较有意思,因为我们可以撬动信息泄露和代码执行的相关功能。下面实现的共计过程基于Nexues 5设备,运行在Andoid 5.1.1 LMY48I,通过这个缺陷影响的是早于Androiid6.0版的系统。

android上的漏洞挖掘方式和Fuzz

这里mCodeInfos是一个包含sp的向量。这里函数itemAt是缺少边界检查,因此我们得到了通过定义value超过数组容量的越界读操作。
开始的时候数组附近的堆布局就像是这样,我们可以看到它在160区域。
android上的漏洞挖掘方式和Fuzz

攻击过程

正如上面提到的,这个漏洞考虑的越界dword值当作了强指针类型,应该指向nagMedidaCodecInfo Object。我们需要在攻击实现前了解一下对象内部结构。
android上的漏洞挖掘方式和Fuzz
以上是MediaCodecInfo的定义,通过我们利用调试器和反编译器的进一步研究,我们获得了对象的结构:
android上的漏洞挖掘方式和Fuzz
这里的mName有一个AString的类型,包含了字符串的基类和它的响应尺寸。mQuirks和mCpas是两个数组成员

PC控制

到此,我们有了堆MediaCodeInfo的清晰了解,我们可以回到我们的攻击过程中了。oob读取强指针,并且下面的构造过程被调用的时候实现:

android上的漏洞挖掘方式和Fuzz

这里refs->mBase->onFirstRef();给我们提供了控制pc寄存器的机会。确切的讲,我们可以建造一个恶意指针到内存,并受到我们的完全控制,我们设计需要的mBase和最终虚函数onFirstRef。这些完成后,我们就可以实现代码执行。如此意味着在我们构造的伪造MeiaCodeInfo对象中,令refs=[addr+4]我们需要一下条件:
[refs]==INIT_STROING_VALUE
[[[refs+8]]+8]是需要的pc寄存器地址

如下反汇编:
android上的漏洞挖掘方式和Fuzz
正想一下快照显示:
android上的漏洞挖掘方式和Fuzz

越权读

接着,我们需要泄露一些地址,因为meida_server上有一些保护机制阻止我们的ROP。事实上,这个漏洞还可以被用来泄露内存地址。但首先我们需要快速的退出函数,避免函数指针被调用而导致的异常。实现这样的功能需要把c设置成与INITIAL_STRONG_VALUE不相等(0x10000000)。
服务端最终会协会请求的结构到客户端。下面的代码将会被执行:
android上的漏洞挖掘方式和Fuzz
一旦我们能够具体指定mData(+0x80)和mSize(+0xc)位于伪造的MediaCodecInfo,强制的内存读取就可以实现。当然我们还需要设置mQuirks(+0x20)和mCaps(+0x34)的值为0,这样可以确保不会在中途崩溃。每当我们强制读取的时候,我们可以迭代浏览潜在的.text page 来获取额外的模块信息。这种访问是有效的,因为32为设备的ASRL脆弱型,期间mediaserver将会自动的恢复如果内存读失败,所有基地址模块保持不变。
一下代码裁剪自堆喷射过程中构建的信息泄露:
android上的漏洞挖掘方式和Fuzz
这里的快照成功的证明了text段的回收过程,利用的是返回的AString Binder事务。
android上的漏洞挖掘方式和Fuzz

翻译的好痛苦。有错误再改吧。