CVE-2019-11932分析
android-gif-drawable是谷歌开源的一个安卓端gif解析库,可以用来渲染gif,被许多app所应用,如what’s app等知名软件。在android-gif-drawable的v 1.2.17以及之前的版本中存在一个double free的漏洞,该漏洞存在于decoding.c中DDGifSlurp函数中。

如图,newRasterSize的计算是当前这一帧的width*height,但是没有检查结果是否为0,realloc的特性我们知道,当size为0时,ptr会被free。因此,我们伪造两个大小为0的帧,即可使得info->rasterBits被double free。

info->rasterBits存储着的是Gif帧的压缩数据,因此,我们可以通过伪造帧数据,来控制被double free后造成的UAF的堆里的内容。而在安卓上,double free是不会报错崩溃的。

一个比较好的利用手法就是double free一个与GifInfo结构体大小一样的堆,然后让GifInfo这个结构体占据double free后的这个堆,接下来,利用帧数据来覆盖GifInfo这个结构体,劫持rewindFunction这个函数指针,从而在DDGifSlurp函数结尾,通过info-> rewindFunction的调用,来控制程序的流程。

gif2ascii出题

为了模拟安安卓上的情况,libc版本选择为2.27,这样double free不会报错。该程序提供4个功能,upload用于加载gif,select用于选择一个帧,add watermark用于添加水印,convert用于将当前选中的帧转化为ascii。
其中,watermark水印功能存在地址泄露漏洞,可以将栈上一些数据拷贝到变量里,然后在convert功能里打印ascii时,可以一起打印出来,通过此功能,我们可以泄露出libc、堆、栈等地址。

首先随便上传一张正常的gif,利用watermark功能泄露出libc地址和堆地址等。

可以看到有地址被泄露出来了。

本题,我们的GifInfo结构体大小为0x98,因此,我们需要伪造帧的width*height为0x98为0x90,这里,我们另width和height都为0xC,然后将伪造的数据放进去,通过giflib的编码函数,将数据进行编码,我们的第一帧就构造完成。



接下来是构造两个大小为0的帧,如图,我们另Width为0即可,然后构造好尾部。这样,一个可利用的gif就构造完成,接下来就是来触发了。

通过convert解析gif,制造一个0xA0的堆double free。然后通过再次上传该gif并解析,这样第一帧的内容就会被解码到GifInfo结构体内,从而覆盖GifInfo结构体。


本题的另一个难点在于开启了沙箱,使得程序只能做ROP来读flag,因此,需要利用setcontext进行栈迁移,但是很难控制0xA0和0xA8处的内容,因此,我们找到一条有用的gadget帮我们调整rdi。

