记录黑客技术中优秀的内容, 传播黑客文化,分享黑客技术精华

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

2015-11-05 11:25

原创作者:FreeBuf特约作者:MarcusAurelius

一、漏洞简介:

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

此攻击流程共分5个阶段,本人的之前的文章,已对Stage0Stage1Stage2进行了分析,本文主要分析Stage3的工作。

在上一篇文章最后,通过Stage0、Stage1和Stage2,攻击者已经获得了webkit的地址信息(Stage3 ROP指令的来源),memobj对象(对内存中的任意地址进行读写),可控的TextNode节点(获取所需汇编指令和执行特定ROP操作)信息,页基址信息和page信息。

本文将要分析的Stage3过程,通过修改TextNode节点对象中的函数指针信息,执行ROP操作,最终达到关闭dep的目的。

二、Stage3利用过程:

0.概述

Stage3的利用过程主要分因为以下五步:

a.通过Stage2泄漏出的webkit中的地址信息,搜索出webkit的加载地址。
b.通过webkit泄漏出libc的加载地址。
c.从libc中查找ROP中所需的指令。
d.将指令地址组成栈信息。
e.修改Stage2中获取的TextNode节点的函数指针,再通过特定的javascript语句触发所需操作。

1.查找webkit加载地址

通过Stage2,攻击者获取了webkit中“text”字符串的地址信息。

                图1 通过动态链接库内地址获取动态链接库加载地址

如图1所示,攻击者所用的方法是循环查找Stage2传入的“text”字符串所在位置之前的页的页首中是否存在“ELF”字符串,来判定动态链接库的加载地址。

2.通过webkit泄漏出libc的加载地址

                图2 通过webkit泄漏libc加载地址

如图2所示,攻击者在获取了webkit的加载地址之后,获取了其中fopen的起始地址,在通过fopen的地址,用与获取webkit加载地址相同的方法获取了libc的加载地址。

3.从libc中获取ROP所需的指令

                图3 获取ROP所需指令

如图3所示,当攻击者需要获得特定指令时,攻击者只需把所需的二进制指令传入findstring函数。此函数会通过在Stage2中获得的TextNode对象,将其指相应的指针指向当前动态链接库的起始地址和动态链接库长度,之后执行indexOf函数时,函数会将动态链接库当作字符串来进行查找,当查找到所需操作时,会将操作的地址返回,以供之后的ROP使用。

4.将指令地址组成栈

                图4 ROP栈

如图4所示,攻击者可以在一个完全可控的内存中(之前通过javascript申请的数组)存贮此信息,再通过调用特定指令将此信息换入栈中,从而控制程序的执行流。

5. 修改TextNode节点的函数指针,并通过javascript使得TextNode对象调用此函数,从而劫持控制流

(1)修改TextNode对象的函数指针表:

                图5 修改TextNode对象的函数表1

如图5所示,在第一个红框中,攻击者首先将TextNode节点的函数指针表保存。在第二个红框中,攻击者将其控制的函数指针表写入相应位置。在第三个红框中,攻击者触发被修改指针位置的函数,进行了控制流劫持。在第四个红框中,攻击者将TextNode节点的函数指针表还原,使TextNode恢复正常功能。

  

                                          图6 修改TextNode对象的函数表2

如图6所示,攻击者将函数指针表地址改为一个已被完全控制的内存区域地址,之后在通过Javascript对node节点进行赋值(node.obj.nodeValue=”x”),此时浏览器会调用TextNode对象的WebCore::CharacterData::setNodeValue函数,修改TextNode对象中所存的值。而此时,存储WebCore::CharacterData::setNodeValue函数指针的位置已经被修改,由此完成了指令流劫持的第一步。

(2)调用WebCore::CharacterData::setNodeValue函数

WebCore::CharacterData::setNodeValue函数会被WebCore::NodeInternal::nodeValueAttrSetter函数调用:

                图7 WebCore::NodeInternal::nodeValueAttrSetter函数的汇编代码

如图7所示,r4为TextNode对象的指针,r1为TextNode对象的函数表地址,r5为实际被调用的WebCore::CharacterData::setNodeValue函数(在函数表+92的位置)。此时,我们发现r1、r2寄存器存储的是栈顶指针加8和栈顶指针加4的位置,再之后的shellcode执行时栈指针的数据会被使用。

                图8 函数指针表+92处的指针指向

(3)ROP过程

fakevtable和伪造栈信息作为ROP过程中被用到的两个重要数据,我们先来对这两个数据进行简单的介绍。

                图9 fakevtable存储内容

如图9所示,fakevtable:fakevtable+4=第二组指令地址(图9中的最后一行完成此操作) fakevtable+8=伪造栈地址 fakevtable+12=第二组指令地址 fakevtable+92=第一组指令地址。

栈信息上文中已经给出,这不再复述。

                图10 第一组汇编指令

如图10所示,词组汇编指令首先将TextNode对象的函数指针表地址取出,存入R7,由于此地址已被攻击者篡改,攻击者此时再将R7+4位置的函数指针取出(此时的R7+4指向fakevtable+4=第二组指令地址),作为第二组汇编指令取出。

                图11 第二组汇编指令

第二组汇编指令会被执行两次。如图11所示,第一次执行时,此时的R7指向fakevtable,程序会将fakevtable当作栈使用。之后pop.w会讲栈中的数据存入R4,R5,R7,LR寄存器中,此时就会将R7置为伪造栈地址,LR置为此函数的入口地址本身。当第二次执行此指令时,会将R7中的地址再次放入SP中,此时R7中存储的是伪造的栈地址,攻击者以成功的将伪造栈换入栈中。再次通过pop.w指令,将伪造栈中的数据存入R4,R5,R7,LR寄存器中,此时R4指向一个攻击者可控的内存区域(此区域会被用来存储原始栈信息)。LR指向第三组汇编指令。

                图12 第三组汇编指令

如图12所示,第三组汇编指令的主要功能是将原始的站信息存入攻击者可控的地址中(R4+4)。在之前的分析中已经知道,R1中存储栈顶指针加8的地址,在此步操作中会将其存入可控地址的内存空间。之后通过pop地址到PC中,执行第四组汇编指令。

                图13 第四组汇编指令

如图13所示,第四组汇编指令的主要功能是将栈中的页基址信息(page.base)存入R0中,作为修改页可执行保护的起始页。

                图14 第五组汇编指令

如图14所示,第五组汇编指令的功能是将栈中数据填入R1-R5和PC中,通过第四组指令中设置的R0和此阶段设置的R1-R5,攻击者达到了向mprotect函数(mprotect为攻击者从libc中找到的关闭内存可执行保护的函数指针)中写入参数的操作。并成功调用此函数,关闭了整个页块的可执行保护。最后mprotect函数会通过栈中的最后两个元素,返回到攻击者写的shellcode中执行。

(4)shellcode执行

本程序所利用的shellcode可以分成三部分来分析:

判断shellcode的执行状态
正常执行函数调用
第一次执行ROP后防止程序崩溃操作(将栈指针返回)

a.判断shellcode的执行状态:

                图15 判断shellcode的执行状态指令

如图15所示,此部分功能是首先获取dword_124位置中存储的对象值,dword_124中存储着如下对象:

                图16 dword_124中存储的对象

如图16所示,此对象的用来完成函数调用的操作,fn存储函数指针,forking表示是动态链接库中的函数或攻击者自定义的函数,r1、r2、r3、r4表示传入参数,r0表示返回值。图14中的操作实际为将fn(所需调用功能的函数指针)存入R5中,并判断R5是否为零,如果不为0 ,说明有函数需要调用,shellcode将进入正常的函数调用步骤。否则就进入修复栈操作。

b.正常执行函数调用:

                图17正常执行函数调用

如图17所示,函数调用部分的主要功能就是将图16中的各个参数存入寄存器,并调用R5中存储的函数指针。最后将R0中的返回值存入structfn+0x1c的位置。由此就完成了函数调用的过程。

c.第一次执行ROP后防止程序崩溃操作(将栈指针返回):

                图18 栈指针修复代码

如图18所示,当图14中的R5为0时,代表并无函数须调用,shellcode是在ROP后被执行,需要对栈进行还原操作。上图中的第一个红框中的操作是将第三组汇编指令执行时存入内存中的栈指针信息取出。由于此栈指针信息原本存储就是SP+8的位置,栈信息在之后的ROP过程中又进一步遭到破坏。所以需要对栈指针进行调整。

图18中第二个红框中的操作是循环对栈指针减4,并读取栈中的数据,判断其是否属于webkit动态链接库的地址范围。之后如图18中第三个红框所示,shellcode读取栈栈指针加0×28的位置,判断其是否属于v8动态链接库的地址范围。如果判断都成功,就将SP指针调整到相应位置后退出shellcode,进入Stage4。如果判断不成功,无法恢复栈,程序将崩溃。

三、结语

通过Stage3的操作,攻击者成功的使用ROP,关闭了内存写保护,可以在内存中执行攻击者所写入的操作,达到了任意代码执行的目的。

*本文来自FreeBuf特约作者MarcusAurelius投稿,属FreeBuf黑客与极客(Freebuf.COM)独家发布,未经允许禁止转载。

知识来源: www.freebuf.com/vuls/83950.html

阅读:79364 | 评论:0 | 标签:漏洞 终端安全 Android Hacking team 浏览器

想收藏或者和大家分享这篇好文章→复制链接地址

“Hacking Team安卓浏览器攻击过程中的漏洞分析 Stage3”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

公告

关注公众号hackdig,学习最新黑客技术

推广

工具

标签云