白泽带你读论文丨Counterfeit Object-oriented Programming*

  • A+
所属分类:安全开发

Counterfeit Object-oriented Programming: On the Difficulty of Preventing Code Reuse Attacks in C++ Applications
论文链接:https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7163058
本文由德国達姆施塔特高級安全研究中心的Ahmad-Reza Sadeghi教授等人和波鸿鲁尔大学的研究者合作发表,收录于国际安全顶级会议S&P 2015。
1     主要内容
自代码重用攻击(code-reuse attack)出现,到2015年为止,这项攻击技术已经发展得较为成熟,各种各样的攻击变种以及防御机制不断涌现,相互博弈。其中以Return-oriented programming(ROP)为典型代表,并出现了与之类似的JOP和COP等攻击手段。这些代码重用攻击均存在五大特征:
(1)程序代码分支会跳转到非原始目标或非地址占用的代码位置。
(2)与原程序执行流程不相符的return指令调用。
(3)攻击者会大量利用间接分支跳转。
(4)攻击者会改变堆栈指针(可能为暂时的)。
(5)攻击者会注入或者操控现有程序中的代码指针。
针对以上五点,现有大部分防御机制从源码或二进制代码级别进行相应的恶意行为检测,其检测思路大致可分为四类:
(1)     Memory Safety,较为通用的内存保护技术,主要针对控制流劫持进行的防御。比较依赖对源码的分析,实用性低。
(2)     Control-flow integrity,对程序控制流完整性进行分析检测的技术。
(3)     Code shuffling, rewriting, hiding,对代码片段进行保护隐藏等,防止被重用。
(4)     Heuristics,利用启发式学习的方式,动态检测程序执行流程中的恶意行为。
但是本文借助C++中的多态和继承特性,通过修改对象中的虚表函数指针,指向程序中的其他虚表,从而利用这些虚表中的虚函数来构建代码重用攻击,避免出现与传统攻击类似的这五大行为特征,绕过了现有大部分的防御机制,特别是基于二进制代码进行检测防御的技术。同时,本文也为基于源码进行分析检测的防御技术指出了防御过程中应当考虑的重要因素。
2     COOP Attack攻击原理
白泽带你读论文丨Counterfeit Object-oriented Programming*
上图为COOP攻击中的程序流体现。在获取内存布局和控制流劫持方面,与传统的代码重用基本一致,COOP可以通过缓冲区溢出或Use-after-free漏洞,劫持一个虚函数调用,将程序流引导到一个被称为Main Loop Gadget(ML-G)的代码片段入口。攻击中所利用到的gadget均为程序中存在的虚函数,为此,攻击者需要将ML-G中的调用对象替换为自己修改后的伪对象(Counterfeit Object),于是便能通过这些伪对象去调用到攻击者想要调用的虚函数。攻击流程可以分为以下三部分:
(1)     注入伪对象,利用ML-G搭建好虚函数的调用顺序。
(2)     利用虚函数进行恶意行为的计算以及恶意的写行为。
(3)     最终调用系统敏感的API,实现恶意行为。
白泽带你读论文丨Counterfeit Object-oriented Programming*
COOP所利用到的Gadget为上图所示的10类,最为关键的就是ML-G、ARITH-G和W-G,分别用来进行程序流的组织,以及恶意数据计算和内存写入行为。
白泽带你读论文丨Counterfeit Object-oriented Programming*
具体来说,COOP攻击所需要用到的ML-G如上图所示,该虚函数会在对象指针的容器(如C类型的array或者vector)上进行迭代,并在每个对象上进行虚函数调用。
传统ROP需要在栈上伪造数据,重新组织栈布局的,而COOP利用ML-G,能够在继承了原有控制流和数据流的情况下,实现恶意的利用。且攻击者只需要注入伪对象(此例中为Student对象),修改伪对象中的虚表指针即可。最后被修改的内存布局,如下图所示。
白泽带你读论文丨Counterfeit Object-oriented Programming*
接下来,为了完成恶意的计算,需要利用ARITH-G和W-G完成动态计算以及写入的操作。如下图所示,通过在内存中将Exam与SimpleString对象部分字段重叠(即score和char* buffer),攻击者便能通过执行ARITH-G计算出待写入的内存地址,并结合W-G完成将特定值写入的操作了。
白泽带你读论文丨Counterfeit Object-oriented Programming*白泽带你读论文丨Counterfeit Object-oriented Programming*
       在上述过程中,可以看到strncpy()函数需要利用到虚函数set的一个函数参数。为了完成各个虚函数调用中的参数传递问题,作者具体分析了x86和x64两个架构上函数参数传递的流程,分别设计了可行的方案:
(1)  针对Windows x86的函数参数传递。在x86中,函数的参数通过栈来进行传递,对此利用ML-ARG-G便能向指定的栈地址写入待传的参数值。
(2) 针对Windows x64的函数参数传递。在x64中,函数前四个参数是通过寄存器进行传值,对于此可以利用LOAD-R64-G来将计算后的值存入会被用来进行参数传递的寄存器中。而对于更多参数传递的情况下,后续的参数可以利用x86中的方法,向对应的栈地址写入参数。
以上便是COOP攻击中完整的虚函数利用方式,最后为了调用敏感的系统API,作者设立了三种可行的调用方案:
(1)利用调用了敏感WinAPI函数的虚函数。
(2)通过import table或export table,将WinAPI当成虚函数进行调用。
(3)利用调用了C类型的函数,修改函数指针指向要调用的WinAPI函数。
可以注意的是,对于COOP来说,程序分支以及循环的控制都是通过ML-G中循环容器的大小来实现的,通过修改这些值,就可以完善分支和循环的控制,从而达到图灵完备。
3     COOP攻击实现
对于寻找可以利用的虚函数,作者采用了符号化执行的方式,利用IDA反编译程序,构建程序流程,基于Metasm工具对所有虚函数进行分类,进一步筛选其功能。在解决伪对象重叠地址计算上,利用了z3求解器来求解对象特定filed的偏移量,使之能够在内存中重叠。
最终,作者分别针对64位、32位的IE,以及GCC编译后的64位Firefox浏览器编写了利用POC。作者仅对这几个程序的运行空间注入了平均20个左右的伪对象,且利用不超过11个不一样的虚函数,便能完成整个攻击。
4     讨论
作者对COOP在现有防御机制下的表现进行了评估。研究发现,基于二进制代码所做的防御技术,除了Memory Safety类型的工作,其他全都无法很好的防御COOP攻击。而基于源码做的防御技术,有部分没能考虑到C++中继承上的关系,导致COOP也能成功绕过。
作者讨论了COOP攻击方法在其他体系架构(如RISC)下的可行性,说明只需要利用x86和x64中的参数传递方法,即可迁移到其他架构中。并且对于C#这样也具有部分C++特性的编程语言,也存在可以迁移的可能。
最后,本文给出的防御建议则是需要更多的考虑到程序中这样的语义信息。例如对虚表指针进行校验,监控程序的数据流,或者是对C++对象结构也进行随机化。同样的,采取一些通用的防御检测手段,从源头上防止代码重用攻击也是可行的方式。
 
5     评价
COOP攻击借助了C++数据结构中继承与多态的特性,对虚函数的调用进行了偷梁换柱式的利用,构建了新式的代码重用攻击,并且避免产生前人所提出的攻击中具备的五大显著特征。虽然COOP攻击的对象限于C++语言,但是在代码重用的攻击和防御两方面技术涌现的当下,是一个具有深义的工作,推动了防御机制,特别是基于二进制代码所做的防御,向更加成熟的方向发展。

文 章 |  sher1ock
排 版 |  Amber
白泽带你读论文丨Counterfeit Object-oriented Programming*


什么?你还没有关注白泽?
了解更多更新鲜的安全攻防信息、想要深入认识白泽战队、联系或者加入我们
欢迎扫描下方二维码关注公众号“白泽战队”,我们在这里等你来!

白泽带你读论文丨Counterfeit Object-oriented Programming*

公众号:白泽战队


一个有情怀的安全团队

知乎、简书搜索:复旦白泽战队
也能找到我们哦~
白泽带你读论文丨Counterfeit Object-oriented Programming*
戳“阅读原文”即可查看论文原文哦~

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: