转载

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

本文原创作者:MarcusAurelius

一、漏洞简介

Hacking team今年爆出了针对android4.0.x-4.3.x android浏览器的漏洞攻击利用代码。该漏洞攻击代码,通过连续利用多个浏览器与内核漏洞,完成通过javascript向虚拟内存写数据,执行代码,提升至root权限,并最终达到向目标手机中植入恶意程序的目的。

此攻击流程共分5个阶段,本人的上一篇文章《 Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage0 》,已对stage0进行了分析,本文主要分析stage1的工作。

在上一篇文章最后,通过stage0,攻击者已经获得了页块信息(一个4M大小的Javascript数组,后文简称页块)并且泄露出一个指向页块内部的特定字符串(“http://www/w3.org/1999/XSL/Transform”)的线性地址,由于页块是通过javascript申请的4MB空间,而通过stage0所泄漏出的线性地址,无法被判断其在4M页块中偏移。而stage1的工作就是确定所泄露出的线性地址所在的内存页,在页块中的具体偏移。进而推算出4MB的页块在内存中的准确地址。这样就绕过了堆内存地址随机化等保护措施。

二、漏洞详细信息

0.概述

Stage1利用的0Day漏洞原理如下:

stage1存在两个漏洞。

漏洞1属于由于不合理的id生成方式导致的地址泄漏。

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图1 generate-id实现代码

generate-id函数的主要功能是为目标对象生成一个id值,可实际在函数执行过程中,生成id的方法如图1红框中所示,将对象的地址值除以对象长度(60)。因此可以通过生成的id乘60的方法,泄露出目标对象的地址信息(地址范围在特定的60byte中),这就达到了地址泄漏的目的。

漏洞2属于未对对象类型进行正确性检查,就直接错误地进行强制类型转换,错误地将一个xmlNs类型的指针当作一个xmlNode类型的指针使用,并导致xmlNs中的一个完全可控的字符串指针(prefix)被当作xmlNode指针(children)所使用。由于字符串转换成xmlNode节点后,节点的类型是未识别类型,因此导致字符串会被当作非法节点从双向链表中移除,在将字符串从链表中摘除的操作中,存在操作cur->prev->next=cur->next操作,导致任意地址写漏洞。攻击者可以通过控制字符串制造任意的xmlNode对象(被cur指向)。

修改prev指针(cur+28位置),再修改next指针(cur+24位置),这样就可以达到向任意的[prev]+24的位置写入任意值(next的值)。漏洞利用的思路是:首先,通过JS将stage0所申请的页中的数据清空。然后,将字符串中+28位置的地址修改为一个在与stage0所泄漏出的虚拟地址相同页的任意一个虚拟地址,+24的位置修改为一个特定值,然后使用漏洞即可向虚拟内存页中的特定地址中写入特定值,然后循环查找页块中的每一个虚拟内存页中的特定地址,当其中的值为特定值时,即可判断出stage0中所泄露出的地址所在的页在页块中的位置。之后通过计算偏移,就可以计算出页块的起始地址。

hacking team在实际使用时对代码还进行了漏洞利用稳定性的优化处理,漏洞利用稳定性的优化处理在三中分析。

下图简单的介绍了程序进入stage1时的情况。

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图2 stage1输入参数的关系

图2分析了当执行到stage1时程序的状态。图2中的页块(红框范围)代表由javascript所申请的4MB的页,而蓝框中的页代表虚拟内存空间的4KB的页。由stage0泄漏出的指针,指向由javascript所申请的页块中的一个虚拟内存页,正如我们所看到的,通过stage0无法知道泄漏出的指针具体指向哪一个虚拟地址内存页,也无法推算出页块的基地址。而stage1主要达到的效果就是通过stage1的漏洞确定图2中的n的实际值。并通过此值通过计算偏移的方法计算出页块的基地址。

1.触发崩溃的数据结构和利用代码

由于此漏洞是在xsl执行过程中所引发的漏洞,所以此漏洞利用代码有xml部分、xsl部分和填充的内存数据部分:

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1   

图3 漏洞触发代码 xml部分

图3为触发漏洞所需的xml代码,其主要功能是将引发错误时被强制类型转换的字符串信息写入xmlNs对象中。其中字符串信息(ns)信息会被存入图5中的xmlNs节点中的prefix指针中,nsname会被存入href中。   

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图4  漏洞出发代码 xsl部分

图4为触发漏洞所需的xsl代码,我们所须关注的重点是红框画出的部分,其大致含义是,找出节点中的namespace节点,并获取第二个namespace节点(第一个节点为一个合法的xmlNs节点;第二个namespace节点为图3中所创建的包含字符串信息的节点)。

程序在运行过程中会为namespace(xmlNode)节点创建一个副本,然后将副本namespace节点中的next字段设置为图3中的nsuri节点,通过存储此节点来确定副本的归属。之后,对副本namespace节点进行apply-templates操作(此操作为强制类型转换操作)。

在apply-templates函数执行时,其传入参数为一个经过之前的条件检索出的节点,也就是说,被传入的节点为一个xmlNs节点。由于程序每做类型检查,此节点会被当作一个xmlNode节点进行操作。之后函数会循环遍历xmlNs的所有子节点,对节点类型为“未识别”的节点和类型为“DTD类型”的节点进行去链和删除操作,再循环对其他合法节点进行后续处理。由于xmlNs节点是通过字符串构造的,因此在去链操作中会触发任意地址写漏洞。

2.漏洞成因:

程序出现漏洞的根本原因是由于,在xsl执行到apply-templates时,会将传入的节点强制类型转换成xmlNode节点进行操作,而在使用时不进行任何节点类型的检查。

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图5 xmlNode对象和xmlNs对象

如图5所示,当xmlNs被转换成为xmlNode对象时,红框中的字符串指针(prefix)会被当作xmlNode节点指针使用。也就是说,攻击者所构造的字符串在apply-templates的执行过程中,会被当作xmlNode使用。

当apply-templates执行时, 函数会遍历所有子节点,当发现字符串节点的类型不可识别时,会将字符串节点去链删除。

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图6 清除未识别元素的去链操作

图6是摘除字符串节点时对字符串节点进行去链操作的流程,其中会被攻击者利用的操作为:ztX节点的指针会被存储到字符串节点(转换为xmlNode节点)可控制的内存中(如图6),所以可将ztX节点的地址(ztX节点的地址是被字符串所指向的指针,是stage0泄漏出的地址)写入当前页中的任意地址,在hacking team实际的攻击过程中此地址为虚拟内存页起始地址+0×88。此后程序只要循环读取每页的0×88中的信息,看其是否为stage0泄漏出来的地址,就可以确定指针是否指向此页,并由此推算出整个页块的基地址。

三、漏洞利用稳定性的优化处理

在图4中的xsl代码中,不仅有触发漏洞的代码,同时还有一组代码,而这组代进行了漏洞利用稳定性的优化操作。

由于在漏洞利用阶段,apply-tamplates会将字符串认定为未识别的类型,因此会对字符串指针指向的位置进行清除操作,由于字符串指针在清除时,并没有修改xmlNs节点的prefix指针,导致prefix指针指向了一个被free的内存块。而在后续操作中,程序会循环调用xmlXPathNodeSetFreeNs函数,对所有的namespace节点进行删除操作。

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图7 xmlXPathNodeSetFreeNs函数的操作流程

从图7中我们能发现,当ns的next字段所指向的xmlNs节点(此时实际指向了一个xmlNode类型的节点)不为空且节点类型不为XML_NAMESPAC_DECL时,会对ns进行free操作。由于ns->prefix所指向的字符串,在之前的apply-templates中已经被删除,所以此时再进行free会引发可被android操作系统捕获的崩溃。

为了避免此崩溃发生,攻击者采用了将next所指向的xmlNs节点的类型修改为XML_NAMESPACE_DECL的方法,使ns节点不被free。

之前已经说明过,ns->next会指向图3中的nsuri节点,所以用户需要对nsuri节点的类型字段进行修改,当将类型改为0×12(XML_NAMESPAC_DECL所代表的数字)时,namespace节点就会绕过删除操作,从而避免崩溃。此过程分为以下步骤。

1. 获取nsuri节点的地址信息:

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图8 通过generate-id获取内存地址信息

攻击者可以通过generate-id()函数获取nsuri节点的一个id值。而这个id值的生成方式是由nsuri节点的内存地址除xmlNode类型的长度(60)获得。

2. 循环填充15个内存区域:

Javascript会循环填充15次如图9中的节点信息,并在每次循环中将documentarea的值循环递减4,由于documentarea是由生成的id乘以60再加上60得来的,通过对其循环递减4,可以使documentarea覆盖整个60个地址长度的内存,其中必有一个指针指向了图3中nsuri所在的位置。

3. 泄漏nsuri节点的准确地址:

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图9  此时内存中填入的信息

在图3中,执行红框上面关于ELZ的比较时,会对图9中第一个红框中的地址进行比较,判断其是否是一个确实属于图2中的nsuri节点的数据(判断节点的上下文信息是否指向nsuri+4),只有当图9的第一个红框中的documentarea= nsuri+4时,才会进入第二次apply-templates,由于在15次填充中,必会出现匹配成功的情况,进入到第二次apply-templates,这时apply-templates中执行节点的数据所携带的documentarea地址,正是指向nsuri+4的位置。这就达到了泄漏nsuri地址的目的。

4. 再次进行apply-templates操作:

Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage1

图10 去除DTD节点的操作

在第二次执行apply-templates会进行与第一次类似的操作,此时会删除DTD类型的节点。而在对DTDOverwrite节点进行去链操作时,函数会将documentarea-24(图9第三个红框中)当作xmlNode类型进行操作(此时修改documentarea-24的next指针就指向nsuri节点的类型字段),此时会将nsuri节点的类型字段赋值为node12节点的地址,而此地址的末尾是0×12。

之后对DTDClear节点进行去链时,会将documentarea-23(图9第二个红框中)当作xmlNode类型进行操作,此时会将nsuri节点的类型字段赋值的前几位清空,使得类型值变为0×12(XML_NAMESPAC_DECL所代表的数字)。这时在运行到图7所示的xmlXPathNodeSetFreeNs函数时,由于cur->next->type=0×12,所以不会对ns节点进行删除操作,从而避免了崩溃。

本文由:3020337181@qq.com和3352444864@qq.com合作完成

*作者:MarcusAurelius,本文属FreeBuf原创奖励计划文章,未经许可禁止转载

正文到此结束
Loading...