首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Angr AEG:堆溢出之Exploit自动生成

Angr AEG:堆溢出之Exploit自动生成

作者头像
FB客服
发布2019-03-08 15:14:41
1.5K0
发布2019-03-08 15:14:41
举报
文章被收录于专栏:FreeBufFreeBuf

本文主要介绍如何基于 Angr 进行漏洞挖掘,并自动生成 Exploit。对于 Exploit 的自动生成问题,也被称为 AEG(Automatic Exploit Generation),其中包含漏洞挖掘、Crash分析、约束条件构造、约束求解、Exploit 生成等环节,下文通过符号执行实现对二进制程序的自动化漏洞挖掘及利用,并展示完整的 AEG 过程。文中所分析的漏洞程序为 Insomni`Hack 2016 题目之一。下载地址,其中包含漏洞程序源码 demobin.c、编译后的可执行程序 demobin 以及 Angr 脚本 solver.py。

0x00 漏洞原理

1、源码分析

首先查看源码 demo_bin.c,存在一处堆溢出漏洞,关键点如下:

1) component_name[128] 大于 component->name[32];

2) initializacomponent( char *cmpnaem) 函数中,在赋值时未检查缓冲区大小;

3) 调用 do_something() 时,产生 Crash。

2、GDB 调试

分析过程序源码后,利用 GDB 动态调试 demobin,以触发 Crash。首先通过 r2 查看 initializacomponent( char *cmp_naem) 所对应的汇编代码。

分析后可知,结构体 component 大小为 36 字节,其中 component->name[32] 占用 32 字节,随后 4 字节为函数指针,因此构造 PoC 为 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB"。

利用 GDB 加载 demobin 并输入 PoC,在 initializacomponent( char *cmp_naem) 函数中,调用 malloc() 之后设置断点。查看此时 malloc() 所分配的内存情况。

继续调试,单步至 initializacomponent( char *cmpnaem) 函数返回,查看此时内存情况。可见 cmp 在堆上的地址为 “0x804b410”,而 cmp->do_something(1) 所对应的地址 “0x804b430” 此刻已被 “\x42\x42\x42\x42” 所覆盖,如下图所示。

当程序执行至 cmp->do_something(1) 时触发 Segmentation fault,此时 EIP 为 “\x42\x42\x42\x42”,表明程序的控制流已被劫持。

通过以上简要分析可知,demo_bin 中存在堆溢出漏洞,可导致控制流劫持。在此基础上,下文主要介绍如何通过 Angr 实现对该漏洞的自动化挖掘以及利用。

0x01 Angr AEG

完整的 AEG 过程,在逻辑上大致可分为以下几个环节:

1) 漏洞挖掘,Angr 主要采用带有前置约束及路径选择策略的符号执行; 2) 崩溃现场分析:EIP 状态、内存布局; 3) 约束条件构造; 4) 约束求解,Exploit 生成;

1、漏洞挖掘

在本例中,主要是针对控制流劫持漏洞的挖掘。利用符号执行检测控制流劫持,关键在于 EIP,若 EIP 完全被符号变量所覆盖,则代表着控制流可以被劫持,此时 Angr 会抛出 unconstrained 状态。

solve.py 中 65 ~ 84 行,通过搜索二进制程序的状态空间以实现漏洞挖掘。由于 demo_bin.c 中的漏洞逻辑较为简单,因此在挖掘过程中并未加入复杂的前置约束以缓解路径爆炸,也未采用额外的路径搜索策略,仅使用 SimulationManager 的 step() 方法,循环执行,直到出现 unconstrained 状态。

注意,在设置 SimulationManager() 时,save_unconstrained 必须设置为 True。

2、崩溃现场分析

脚本运行不久后,便会触发 unconstrained 状态,此时需要对崩溃现场进行分析,以判定 unconstrained 状态的可利用性。

1) EIP 可控性分析

solve.py 中使用 fullysymbolic() 方法检查 EIP 中符号变量的数量。其中 state.arch.bits 代表系统字长(The number of bits in a word),state.solver.symbolic() 用以判断输入数据是否为符号变量,该方法在 ./angr/stateplugins/solver.py 中实现:

当 EIP 完全被符号变量覆盖时,代表控制流已被劫持,此时堆及 EIP 状态如下:

在实际调试过程中,会出现多次 unconstrained 状态,但前若干次符号变量均未能完全覆盖 EIP,因此并不能利用。最终 EIP 被符号变量完全覆盖时,其内容如下:

2)内存布局分析

在触发控制流劫持后,需要分析当前状态下内存中符号变量的分布情况。solve.py 中的 findsymbolicbuffer() 实现相关功能,主要包括查找符号输入、追踪符号变量两个部分。

(1) 查找符号输入

Angr 在处理 scanf 的输入数据时,采用 streams 模式。默认情况下,stdin、stdout、stderr 均采用该模式。state.posix.stdin 为输入程序的全部符号变量,调试结果如下:

(2) 追踪符号变量

通过 state.solver.getvariables() 追踪内存中的符号变量。该函数位于 ./angr/stateplugins/solver.py 中,返回结果如下:

state.memory.addrsforname() 返回符号变量对应的地址,结果如下:

至此,已完成漏洞挖掘与崩溃现场的分析,后续需要结合 Exploit 的方式(ret2text、ret2syscall、ROP 等),构造完整的约束条件,并求解。

3、约束条件构造

对于 Exploit 自动生成问题来说,其关键是构造合适的约束条件,并利用 SMT(Satisfiability Modulo Theories) 约束求解器求解,若约束可解,则生成成功,否则生成失败。其中包括路径约束、EIP 约束、shellcode 约束等。

本例中,Exploit 方式采用 ret2text 且不考虑安全机制,因此仅需找到一片足以放置 shellcode 的连续空间即可。检查空间连续性的函数如下:

solve.py 中的 shellcode 大小为 22 字节,最终构造约束条件如下:

4、约束求解

通过 ep.satisfiable() 对约束条件 extraconstraints=(memory == scbvv,ep.regs.pc == buf_addr) 的可解性进行判断。最终判定为约束可解,并生成 Exploit:

0x02 小结

本文以简单的堆溢出为例,展示了如何利用 Angr 自动生成 Exploit。与此同时,也展示了 AEG 的完整过程。文中并未涉及复杂漏洞的自动利用及符号执行所面临的路径爆炸、路径选择、约束求解等问题。由于笔者接触 Angr 时间不久,文中难免存在理解不当之处,望各位大佬批评指正(Orz...)。

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FreeBuf 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0x00 漏洞原理
    • 1、源码分析
      • 2、GDB 调试
      • 0x01 Angr AEG
        • 1、漏洞挖掘
          • 3、约束条件构造
            • 4、约束求解
            • 0x02 小结
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档