首页
社区
课程
招聘
[翻译]ROPMEMU - 代码重用型攻击分析框架
发表于: 2016-8-6 16:13 13649

[翻译]ROPMEMU - 代码重用型攻击分析框架

2016-8-6 16:13
13649

原文链接 http://blog.talosintel.com/2016/06/ropmemu.html

ROPMEMU - 代码重用型攻击分析框架
Mariano Graziano / BDomne 译

0 概述
近年来,攻击手段变得越发的复杂,威胁层面的不断演进说明恶意者也在改变他们的策略以适应相关的防护方案。代码重用型攻击,如ROP(return-oriented programming),就是此类演变中的一个方向,由于目前对这一领域的研究还不够深入,因而给防护带来了较大的挑战。日前,Talos团队正式发布了针对复杂的代码重用型攻击的分析框架ROPMEMU,在本文中,我们将分析和讨论处理这些代码重用实例时的难点及其重要性,同时我们也会介绍框架中剖析此类攻击和简化指令的相关技术和组件。

代码重用并不是什么新的攻击方式,它自1997年第一例ret2libc攻击出现后就一直存在。也就是从那时起,恶意者开始转向代码重用型攻击,毕竟由于不断加强的软硬件防护措施,代码注入要想成功起作用也变得更加的困难。但改进后的防护方案必将导致恶意者开发出更复杂的方法来绕过它们,这些年,攻击者开始采用ROP模式来隐藏恶意功能以及阻碍分析。对于那些不熟悉ROP并且想要进一步了解的读者,我们建议你参考Shacham的文章

不幸的是,对于代码重用型攻击的研究,如ROP,在很大程度上被完全忽视了。通过公开的小部分样本我们就足以窥见此类攻击方式实际上是多么的复杂,而且恶意者将在今后继续利用这种攻击方式的趋势是很明显的。开发ROPMEMU的主要初衷之一就是由于目前防御的一方还普遍缺乏可用的工具来帮助剖析这些威胁。

提出的框架中采用了一系列不同的技术来探究ROP链,并通过特定形式重新拼接成等效的代码段,使其能够借助常用的逆向工具进行分析。具体来说,此框架基于内存取证(其输入为物理内存的dump结果),代码模拟(如实重建原始的ROP链),多路径执行(提取ROP链的payload),控制流程图(CFG)还原(重建原始控制流)以及多次的编译器优化(简化ROP链的最终指令)。此外,在本文中我们将通过一个持续的ROP型rootkit对ROPMEMU框架进行测试。

ROPMEMU是进行代码重用型攻击自动化分析的首次尝试,由于这是一个不断发展中的领域且ROPMEMU仍为研究的原型,因而其在操作通用输入以及处理所有可能实例时还存在一些功能上的不足。但是,我们相信通过接下来对此框架的继续研究与开发,能使其成为分析这类威胁的科学研究中一个真正有价值的工具。

ROPMEMU的相关成果已在第11届亚洲计算机与通信安全大会(ASIACCS)上发表,对应的论文可在此处下载。

1 关于ROP
内存取证的主要关注点在于查找物理内存被侵扰的依据,通常包含恶意程序创建或注入到内存中的各种巧妙设计。诸如psxview和malfind这类工具就是很好的例子,它们能够帮助识别dump块中存在的侵扰迹象。

多年来,攻击者一直通过代码注入劫持目标应用或操作系统的正常控制流,为了应对这种情况,安全人员开发了相应的工具来检测可能出现的此类威胁。典型的代码注入方案如下图所示:


正如图中所阐述的,我们的shellcode被放置在一块连续的内存空间中,程序将借助转移指令跳到此处(步骤1)。然而现今的操作系统都采用了特殊的保护机制来禁止shellcode在数据段上的执行,再加上其它的防护手段,代码注入就目前来看是越发的不可行了。出于这种原因,攻击者发明了新的技术来绕过现有的策略,对比经典的代码注入攻击,ROP攻击在具体形式上就显得大为不同:


可以看到,最主要的差别在于指令所处的内存空间不再相邻了。ROP是一项通过重用程序中的已有指令来执行任意代码的技术,每一部分指令序列(即代码片段)同时还负责引出下一部分指令的起始地址(通常使用ret指令由栈传递),最终借助拼接起来的许多代码片段就可以实现预定的计算操作。在上图所示的例子中,左边为拼接完成后攻击者所控制的指令指针,实际的代码片段由右边的各个方框表示,旁边的数字对应代码片段的执行次序,它们在内存中是不连续的,执行这些代码片段要求每次跳转到不同区域的地址空间(由橘黄色箭头标识)。在这种方式下,攻击者控制的数据段中只需包含对应的指针就可以了,最终得以绕过相关的防护策略。

代码重用型攻击,如ROP给出的这类攻击方式,无疑给安全分析带来了新的挑战。

2 ROP的分析
这些年,研究者们完全低估了ROP的复杂性,很少有人将研究的关注点放在识别内存中的ROP链上。虽然这是一个很吸引人的领域,但目前仍处于研究的初级阶段。在开发ROPMEMU的过程中我们意识到还有更多的工作需要去完成,也就是下列的主要难点:

难点1:冗余
大部分的ROP代码片段都会含有花指令,例如,用来增加EAX寄存器的代码片段在其执行到RET指令触发链中下一代码片段前可能还进行了无意义的出栈操作。此外,ROP链中包含的很大一部分代码为返回指令或其它的间接转移指令,它们的目的只是用来连接不同的代码片段,很少有例子能够说明为什么ROP代码会如此的冗长并且包含大量的无效指令,这使它分析起来变得更加困难。然而,这可能是待解决的问题中最容易的了,因为和编译器相关的资料中已经提出了许多转换技术来进行这些优化。

难点2:基于堆栈的指令流
ROP链和普通程序最明显的不同在于其指令的内存分布是不连续的,需借助间接转移指令将各个代码片段拼接起来。例如,一个普通程序可能只需包含50条指令的代码块就可以完成预定的计算,但对于ROP而言,这些指令可能分散在超过40块的代码片段中,彼此间通过RET指令进行连接。咋看之下,这个问题似乎没什么要解决的,由于ROP链上每块代码片段的地址都在内存中,你可能想当然的认为获取它们将是很容易的(待搜集完对应的代码块,就可以将整条链替换成一系列单独的指令)。然而,基于堆栈的指令操作可能会引入一些不易察觉的变化使得我们很难借助简单的静态分析进行识别,由于代码片段的地址存在于堆栈中,同时代码片段的指令还会与栈空间进行交互(获取参数或仅是执行冗余的指令),为了正确获取代码片段的地址,我们有必要模拟程序中的每条指令。

难点3:缺少立即数
ROP链和普通程序的另一个不同之处在于它一般由“通用的“代码片段(比如将任意数值存放到寄存器中)构成,其操作参数也存储在堆栈上。因此,很大部分赋值给寄存器的立即数和代码片段的地址一道分散在栈空间中。同样的,我们需要借助代码模拟来定位这些立即数并将它们转存到代码中的原本位置。

难点4:条件分支
在ROP链中,分支条件指的是栈指针的变化而非传统意义上指令指针的变化,这就意味着一次简单的条件跳转可能需要分散在多块代码片段中的多条不同指令共同完成(例如:根据要求条件设置标志寄存器,判断对应数值以及更改ESP寄存器)。为了将ROP链转换成可读性更高的代码,因而有必要基于语义来识别这些模式,进而将它们替换成单独的分支指令。

难点5:函数调用
在ROP链中一般通过简单跳转到函数入口的方式实现函数调用。然而,由于正常的代码片段也经常从库函数代码中选取,因此很难区分此函数调用是否来自另一块代码片段。此外,对于静态的代码链接,由于缺少函数导出信息将使逆向分析的处理变得更加繁琐和复杂。

难点6:动态生成的ROP链
普通程序的代码通常位于执行文件的只读区域,与之相反,在恶意程序中代码的动态修改则普遍存在(例如,由于加壳的原因),这严重限制了静态技术在分析恶意代码时的作用,并且很大程度上减慢了逆向处理的速度。由于ROP链位于堆栈而非只读内存空间中,所以借助一块代码片段跳转到另外的代码片段是相对容易的。动态意味着在同一时刻内存中不必存在完整的ROP链,一般是在程序的执行过程中逐步构建完成。

难点7:终止条件
在此研究中,我们假设分析过程能够定位到ROP链在内存上的起始点。但是,由于模拟器的分析需要借助代码的上下文,因此能有一个终止条件来决定何时代码片段已获取完成进而模拟器可以结束处理同样是很重要的。而实际情况是那些复杂的ROP链会在正常的代码片段中插入不同的函数调用(可能渐次进行其它函数调用),此外ROP链还可以在内存的其余部分动态生成另一条链,这无疑使得在一般情况下很难去解决该问题。例如,ROP型rootkit(重用内核代码中的已有指令)是什么时候终止的以及正常的内核任务又是什么时候恢复的?

对于最后的4个难点目前还没有相关的公开讨论,因为这些问题是近两年ROP链变得足够复杂后才有的。

3 ROPMEMU框架
分析ROP链中遇到的这些难点使得我们团队开始研究更好的分析技术及工具,最终促成了ROPMEMU的开发。ROPMEMU是GitHub上一个开源的工具,可用来帮助分析代码重用型攻击,关于如何安装此工具以及如何使用不同的插件和脚本的相关文档可在wiki页面中找到。需要注意的是此研究项目仍在继续开发中,因此目前只能算是ɑ版本,如果你发现了什么问题,还请提交问题单以便相关人员能够进行处理,同时,如果你想贡献代码,欢迎给我们发提交申请。

此框架由下图所示的5个主要分析阶段组成:


3.1 多路径模拟
此步骤将模拟执行ROP链中包含的指令,这是精确重建内存dump时刻对应ROP实例的唯一方法。其中所有可能的分支都会被考虑到,并且对于每一条执行路径将生成单独的JSON跟踪记录(由寄存器的数值来表示)。经过这样处理,我们可以解决上述的两大难点:基于堆栈的指令流以及动态生成的ROP链。执行记录中包含了CPU的上下文,此外,该框架还能获悉内存动态并拥有自身的影子堆栈。

所有的写操作将被拦截,且随后的读操作都从此处获取数据,关于栈空间的记录则保存在另一个JSON文件中。模拟器同时也被设计来识别大量的return-to-library函数并模拟它们的执行过程(解决上述关于函数调用的难点)。此外,它还借助启发式技术来检测ROP链的边界以及判断模拟过程的终止点。起初,我们实现了一个自定义的小型模拟器,它能够支持少部分要求的x86和x86_64指令,并且能够更新每条指令执行完成后CPU(寄存器和标志位)和内存的状态。然而,为了支持完整的指令集,我们最后还是采用了最新发布的Unicorn模拟器。对应的ropemu插件在Unicorn和Capstone的基础上实现了这部分功能,但目前此插件仅是一个POC,尚未经过大量的测试并且Unicorn模拟器也还存在一些公开的bug。

3.2 执行记录的分割
在这个阶段,系统将分析模拟器产生的所有执行记录,去掉重复部分并提取代码中的唯一块。此过程可分为两个子步骤,首先,每个执行记录在分支处进行切分,新产生的记录块保存在单独的JSON文件中,在此操作中,框架将通过元数据来描述不同记录块间的关系。下一步,分割组件通过比较单独的记录块来检测交叠的尾部指令(代码片段通常位于块的末尾)并将它们分离到独立文件中。此阶段得到的结果为一系列的JSON记录文件,即ROP链中真正的基本块。此过程是由Python脚本blocks实现的。

3.3 去链
本阶段中,系统将应用大量的汇编转换简化ROP记录块,通过移除代码片段间的连接部分可将内容上连续的代码片段重新组合成单一的基本块,此过程需要移除所有的RET、CALL以及无条件JMP指令。该步骤同时还负责将栈上的立即数分配到指定的寄存器中(解决上述基于堆栈的指令流与缺少立即数两个难点),这将简化对应的MOV指令并把POP指令转化为MOV,通过获取内存中的数值可完成这些操作。此阶段得到的结果为目标ROP结构上的二进制代码块,插件unchain实现了这些功能。

3.4 还原控制流程
此步骤将上一阶段生成的所有二进制代码块组合成一个单独的程序,即恢复ROP链中原本的控制流程。此过程由两个子步骤组成:

a.代码块首先组合成对应的流程图。记录块间的关联信息由执行记录分割阶段生成的元数据作为脚本输入进行具体表述。

b.而后流程图会被转换成实际的x86程序,此处将识别那些与分支条件相关的指令并把它们替换成更一般的基于EIP的条件跳转(处理关于条件分支的难点)。在我们的研究例子中,一次简单的条件跳转需要19块代码片段中的41条指令共同完成,我们的框架能够识别此类情形并将其转换成等效的汇编代码。例子中的19块代码片段最终被转换成两条汇编指令:其一为条件跳转(在我们的情况中可由JZ或JNZ表示),另一为无条件跳转(JMP)。

初始的这两步都是由Python脚本glue实现的。此外控制流程还原组件还负责检测和重建循环,ROP链中可同时包含有效的和无效的循环,这些都是在构建ROP链时按计划生成的。重建循环背后的相关逻辑可参见loops脚本。程序最终将保存成一个ELF文件(借助dust脚本),便于常见的逆向工具(如IDA pro)进行处理。

3.5 程序优化
最后,我们将应用已知的编译器优化方案进一步简化ELF中的汇编代码。此过程将移除代码片段中的无效指令并生成一个简洁的且优化过的payload版本(解决代码冗余问题),需要说明的是这些基本优化是分阶段实现的。

更多详细的分析,请参考此论文

4 评估
我们借助公开的最复杂ROP样本对ROPMEMU框架进行了评估,其中主要的关注点在于测试ROP链的提取、转换以及控制流程图的还原。

在第一组实验中,我们将测试ROPMEMU中的多路径模拟器能否准确提取copy链,以及两个动态生成的链(dispatcher链和payload链),结果表明ROPMEMU模拟器能够自动获取这3条完整的ROP链。其中,copy链最长,包含414275条指令,但仅由一个单独的基本块构成,,由于缺少控制逻辑使得此链类似于攻击利用中那些典型的payload,唯一不同的地方在于它是由180000多块代码片段组成的,主要作用就是生成动态代码并将它们复制到内存中。与之相反,dispatcher链和payload链包含的代码片段则较少,但它们都拥有更复杂的控制流程。具体来说,dispatcher链包括3个分支和7个代码块,为了还原完整代码,模拟器一共生成了7份不同的JSON记录。与此同时,payload链由34个代码块和26个分支组成,这意味着控制流程图将具有更复杂的逻辑。此外,payload链在不同执行路径下的总计17个函数调用中有9个是特殊的内核函数(find_get_pid,kstrtou16,kfree,__memcpy,printk,strncmp,strrchr,sys_getdents和sys_read - 最后两个函数被hook了)。

此实验证明了ropemu插件能够分析并dump复杂的ROP链,对于人工而言这几乎是不可能的。(需要指出的是由于Unicorn中的bug,目前ropemu插件在获取payload链的实现上可能存在一些问题。)我们相信这些结果能够说明现有的恶意程序分析框架在处理ROP型payload上的局限性。

概要结果如下表所示:


在第二组实验中,我们展示了分析ROP链时由其它处理阶段带来的影响。特别的,因为无法展现完整的代码,我们将借助payload大小来表示转换后的变化情况。概要结果如下:


正如第3列所示,去链阶段ROP链大小的变化是比较明显的,平均减少了39%。同时控制流程还原阶段会过滤掉实现条件声明的指令,并将ROP链从堆栈指针域转变到指令指针域,最后再对循环操作进行压缩处理。这些转换将copy链的指令数从大约414000条减少到了只有75条,而对于payload链的影响则相对较小,因其包含的多为有效的ROP循环。

对于第三组实验,我们将检验ROPMEMU还原ROP链中相应控制流程的能力。首先我们展示了dispatcher链通过关联所有记录块得到的控制流程图及其进一步的转换结果,在这个例子中,框架自动加入了尾结点。

左边流程图为未经转换的结果,右边流程图则用于说明具体的转换,我们通过识别加入了尾结点。

还原控制流程的第二步将处理对应的二进制代码块并生成ELF文件,各代码块的拼接则利用已知的元数据信息。为了验证此功能我们在IDA pro中打开得到的目标文件,在下图的左边,我们观察到ELF文件表示的copy链已经完全转换成了传统的基于EIP的程序,代码很简单,没有任何分支,主要功能由图中高亮部分的主循环表示。相对的,图的右边为dispatcher链在IDA pro中所示的结果,为了看起来明了些,图中每个节点的代码段都进行了折叠。


由于包含恶意的操作逻辑,payload链的控制流程图要更加的复杂,总计超过30个节点。从接下来的图片可以观察到此流程图中有两个主要的节点:sys_read和sys_getdents,此外图中还展示了相应的终止结点(Q和C)以及循环(从反向边可以很容易看出来)。即便控制流程图中含有一些多余的边(由于简化循环时引入的错误优化),下图所示的信息还是为payload的行为提供了一个快速但详细的概览。


5 不足
与其它二进制分析工具一样,ROPMEMU也有许多自身方面的局限性。具体来说,提出的方案中同时结合了内存取证和代码模拟这两项技术。前者要求在rootkit加载到内存后能够dump出物理内存中的数据,因此易于遭受反dump技术的对抗。此外,ROP的分析还依赖于模拟器的实现,而基于代码模拟的方案其主要局限就在于模拟器本身的精确性,换言之,此方法容易受到反模拟技术的影响,尤其是针对指令的未知副作用。

当前的实现还处于ɑ版本阶段,如下是我们已知的不足:

a.此框架目前的版本中完全支持的只有x86_64架构的系统,并且尚未经过大量的测试,因为就我们所知仅有此ROP型rootkit能复杂到足以说明ROPMEMU的特性。

b.作为模拟器部分最主要的插件,ropemu的当前版本是基于Unicorn编写的,因而会存在一些公开的bug。需要说明的是,论文是在最初自定义模拟器基础上写的,此后,为了利用Unicorn的特有功能我们又重写了ropemu插件。

6 结论
代码重用型攻击,特别是ROP,被广泛用于绕过操作系统的防护策略,而且正逐渐变得复杂起来。恶意开发者已经开始把ROP作为一种阻碍分析的手段,借此隐匿在这场从未停息的猫鼠游戏中。ROPMEMU则首次尝试了自动化分析完全由ROP实现的复杂代码,目前为止,我们已通过一个最复杂的样本,即持续的ROP型rootkit,对此框架进行了测试。

正是由于缺少深入分析越发复杂的ROP型payload的方法及工具才促使我们提出了此框架,虽然后续还有很多工作需要完成,但ROPMEMU作为一个POC毕竟迈出了第一步,我们希望整个安全圈子能够联合起来帮助分析这些类型的攻击。此外,我们的研究还阐述了安全人员在未来将面对的难点以及此类威胁所带来的潜在复杂性。

你可以在下述链接中找到此工具和相关文档:
http://www.talosintel.com/ropmemu/


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (8)
雪    币: 47147
活跃值: (20450)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
辛苦了。
『智能设备应用』 版块,近期会组织一些国外硬件安全的文章,有没有兴趣参与翻译?
2016-8-6 16:38
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
看不懂。。。
2016-8-6 17:16
0
雪    币: 1149
活跃值: (888)
能力值: ( LV13,RANK:260 )
在线值:
发帖
回帖
粉丝
4
每一点能落地都是一项了不起的东西
2016-8-6 19:29
0
雪    币: 4230
活跃值: (1435)
能力值: (RANK:270 )
在线值:
发帖
回帖
粉丝
5
这次离老大远了点
翻译的话可以尝试一下,顺带学些东西,智能设备接触的确实有点少:D
2016-8-6 21:50
0
雪    币: 6723
活跃值: (1199)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我也来尝试的参与一些
2016-8-8 22:40
0
雪    币: 6
活跃值: (1146)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错的资料,慢慢看
2016-8-9 12:57
0
雪    币: 3
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2016-8-13 19:08
0
雪    币: 397
活跃值: (387)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
10
感谢lz 翻译的很好译文,rop研究里面一个很特别的方向。
2016-9-15 10:19
0
游客
登录 | 注册 方可回帖
返回
//