原创作者:FreeBuf特约作者MarcusAurelius
一、漏洞简介:
Hacking team今年爆出了针对android4.0.x-4.3.x android浏览器的漏洞攻击利用代码。该漏洞攻击代码,通过连续利用多个浏览器与内核漏洞,完成通过Javascript向虚拟内存写数据,执行代码,提升至root权限,并最终达到向目标手机中植入恶意程序的目的。
此攻击流程共分5个阶段,本人之前的前两篇文章(一、二),已对Stage0,Stage1进行了分析,本文主要分析Stage2的工作。
在上一篇文章最后,攻击者首先通过Stage0和Stage1的两个漏洞联合进行地址泄露操作,获得了一个Javascript分配的4M 数组(后文中称其为页块)的基地址。然后,通过Stage1的漏洞,获得了一个可以向全地址空间进行4字节写操作的可控写指针。最后,通过XSL提供的generate-id操作所获取的xml元素id,可以反算出该xml元素对象所在的大概地址范围(精度60 Bytes)。使用之前的全地址范围写指针操作,使得我们可以完全控制由generate-id生成的id值所对应的xml元素对象。
本文将要分析的Stage2过程,主要是通过Stage1最后获得的可控xml元素中的字段指针信息,泄漏并定位webkit动态链接库的起始地址,并为Stage3将要进行的通过ROP关闭内存可执行保护操作做准备。
0.概述
Stage2的操作流程:
(1)泄漏webkit动态链接库加载的地址。Stage2通过对节点类型为XML_TEXT_NODE类型的节点中的name字段的指针值进行读取,通过后面一系列操作的操作,达到泄漏webkit动态链接库加载地址的目的。可泄漏webkit动态链接库加载地址信息的操作是: 由于name字段指针通常指向的字符串是webkit模块中的字符串常量,因此当攻击者获取了此常量的地址时,就可以通过逐个向前扫描内存页的页首位置中是否有“ELF”字符串,由此判断出webkit的加载地址。从而达到了对webkit动态链接库地址泄漏的目的,由此绕过了地址随机化。
(2)获取对整个内存空间的读写能力。攻击者将Stage1阶段所利用的漏洞封装成xsltobj对象,通过xsltobj对象可以对内存进行读写删除操作(删除操作以xmlNode对象为单位进行删除)。
(3)优化对整个内存空间的读写能力。由于每次xsltobj对象进行内存读写,都需要重新加载xsl文件。因此,攻击者在此阶段使用Stage1漏洞产生的xsltobj对象,对内存进行适当的读写,创建了一个DataView对象,以更方便的进行全内存读写。该阶段中,攻击者需在4M可控页块中,申请一个可控的ArrayBuffer数组,通过修改ArrayBuffer数组的管理结构。然后将修改后的ArrayBuffer数组包装进一个DataView对象,这样利用DataView中的更多样的方法,可以更方便的对内存进行读写操作。通过xsltobj创建一个DataView对象:攻击者通过xsltobj对象,可以free页块中的一段连续内存,之后向内存中填充大量ArrayBuffer对象,并在页块中查找刚刚free的内存中是否有ArrayBuffer的管理结构,如果存在,则通过页块修改ArrayBuffer的管理结构,将其中的起始地址设为0×0,长度设为0xffffffff,在之后通过ArrayBuffer对象创建DataView对象时,DataView会将ArrayBuffer中的起始地址和长度直接复制到自身,由此攻击者就可以获得一个可读写全内存的DataView对象。
(4)获取一个可控的TextNode节点,通过修改TextNode对象的函数指针,达到控制流劫持的目的。并且,攻击者可以通过TextNode中的indexOf函数在动态链接库中查找特定的指令。
1.泄露webkit地址操作
当xmlNode节点的类型是XML_TEXT_NODE类型时,节点的name字段会指向一个值为“text”字符串的地址。如下图。
图1 XML_TEXT_NODE类型的name字段指向
当xmlNode节点的类型为XML_TEXT_NODE时,其name字段会指向一个“text”字符串,由于此字符串为webkit的一个静态常量,所以字符串存储于webkit的动态链接库中,因此xmlNode节点的name字段的指针指向一个webkit中的固定位置。攻击者可以使用“text”字符串所在的地址,通过逐个向前扫描内存页的页首位置中是否有“ELF”字符串,判断出webkit的加载地址。
2. 封装一个可对任意内存写的xsltobj对象
通过与Stage1所使用的漏洞相似的原理,攻击者可创建一个xsltobj对象。通过此对象可以对内存地址任意可读可写可删除(将目标地址区域作为非法的xmlNode对象删除),相较于Stage1的内存可写可删除,xsltobj对读写删除操作进行了封装,更好的实现了代码重用。下面我们来简述一下xsltobj对象的创建过程。
(1)通过向页块中填充数据,修改Stage1中获得的xml元素中的字段。
图2 向内存中填充的信息
图2为向内存中填充的信息,通过使用Stage1中的漏洞,这些填充信息可以修改Stage1中所使用的nsuri节点中的任意字段。
(2)通过修改nsuri节点的数据,可以完全的控制nsuri节点中各字段的信息,从而使我们可以用nsuri节点对内存地址进行读、写、删除操作。
图3 内存中填充信息的图形化显示
如图3显示,程序会通过4个DTD类型,对nsuri节点的type,children,name三个字段进行修改,使这三个字段完全可控。
图4 四个DTD节点的next指针指向的位置
图4中的4个DTD节点的next字段所指向的数据,通过这四个next指针,可以修改nsuri节点的类型为0×1(在Stage1阶段通过漏洞改为0×12),将nsuri的children字段指针和name字段指针改为两个指向完全可控位置的指针。
(3)再次调用Stage1阶段所使用的漏洞执行所填充数据的操作后,攻击者就可以通过简单的修改children中的信息,来执行对全内存的读、写、删除操作,无需重新读取xml文件,每次使用时只需重新加载xsl文件。
(4)最后攻击者将此操作封装到一个xsltobj对象中,方便进行读写删除操作。
图5 向内存中填入数据与内存删除
通过循环向内存中填入一组不可识别类型(0x900d)的xmlNode节点,然后调用上一步中生成的xsltobj对象,从起始地址开始对对象进行顺序删除,由于删除的对象是以链表的形式链接的,程序会将整个0×1000的内存区域删除(以xmlNode对象为单位)。并将删除的节点加入存储被free的内存的链表中,使这些内存地址可以被重新申请。而此时,此0×1000的内存区域实际上还可以通过页块来访问和修改。
图6 循环申请ArrayBuffer判断是否在页块中
当攻击者成功通过图5的操作,将其可控的页块中的0×1000的内存区域free之后,会循环调用ArrayBuffer申请长度为0xbad的内存空间,此时所申请的ArrayBuffer对象的管理结构很有可能申请到之前free的0×1000的内存区域中。攻击者通过循环读取0×1000区域中的每个4字节,判断其是否为0xbad(在通过ArrayBuffer申请内存时申请的长度),如果判断成功,之后的4字节内存存储的数据就为ArrayBuffer对象的起始位置。攻击者只需如图6第二个红框中,将ArrayBuffer对象的长度设置为全内存,起始地址设置为0地址,就可在之后创建BufferMemoryObject对象时,其内部调用的DataView构造函数就可以创建一个可以控制全内存的DataView对象(由于DataView的构造函数在执行过程中,会将ArrayBuffer对象的起始地址和长度字段直接复制到新建的DataView中,所以当ArrayBuffer对象中的指针信息指向全内存区域时,新建的DataView对象同样可以控制全内存区域)。由此获得的DataView对象被封装到memobj对象中,方便之后的内存读写。
4. 构造一个完全可控的可用来查找动态链接库中操作的对象
图7 向内存中填入数据与内存删除
此步操作与图5中的操作类似,这里不再详细阐述。
图8 循环申请TextNode判断是否在页块中
当攻击者成功通过图7的操作,将其可控的页块中的0xff0的内存区域free之后,会循环调用document.createTextNode函数创建TextNode节点,此时所创建的TextNode节点很有可能申请到之前free的0xff0的内存区域中。之后,攻击者会检查之前被free的空间,看其是否存在TextNode节点,如果存在,则将此信息存入图8的第三个红框中,传递给Stage3使用。
通过获取TextNode元素,可以达到两个目的:
(1)在Stage3中,可以将libc动态链接库的起始地址和长度存入此元素中(由于此元素存储在可控内存中,可以修改其指向字符串的位置与字符串长度等字段),然后就可以通过简单的Javascript中的indexOf函数,方便的查找到动态链接库中存在的特定汇编指令,为后文的ROP提供便利。
(2)由于TextNode对象在内存中是以类的对象的形式出现的(由于此元素存储在可控内存中),攻击者可以任意修改对象中函数指针,通过修改函数指针,即可完成ROP操作(此漏洞详细信息在Stage3分析中介绍)。
攻击者通过此阶段的一系列操作,获得了webkit的地址信息(Stage3 ROP指令查找的基础),memobj对象(对内存中的任意地址进行读写,xsltobj对象的功能完全由功能更强便捷的memobj对象所取代),可控的TextNode节点(获取所需汇编指令和控制流劫持)信息并连同上一阶段获得的页基址信息和page信息(完全可控的内存信息),传得给了Stage3,供后续使用。
*本文来自FreeBuf特约作者MarcusAurelius投稿,属FreeBuf黑客与极客(Freebuf.COM)独家发布,未经允许禁止转载。