zctf-2017-pwn-sandbox

才接触二进制不久,第一次写博客,萌新一只,zctf被表哥们虐得体无完肤,只能坐等writeup,最近参考flappypig的writeup研究sandbox这道题目,用了三天,记录一下。

ps:基础太渣,可能有理解错误的地方,大佬莫笑,麻烦大佬在评论中指出。。。

接下来进入正题

这道题有两个二进制文件:sandbox和vul。用sandbox运行vul程序,其中vul程序存在栈溢出。

vul为64位,开启了NX。

一个非常暴力的栈溢出,能溢出16字节,真正的难度在于理解sandbox程序到底进行了什么保护(以及写exp)。

接下来看sandbox程序,直接ida F5(程序删去了调试信息,为了便于理解,所以自行加上了名字)

 

程序先是调用了一个初始化函数,然后fork了一个子线程,分别执行两个函数,接下来看initial函数。

。。。。。。这个函数有点长,而且我有点懒,所以不放图了,后面会放上我的i64文件,直接用ida打开就行,我已经给几乎所以变量改名了,所以应该不难理解。

这个函数先是读取了vul文件,将它保存到内存中,读取ELF头,获得了一些信息。(当时对着表查了半天。。。)

此函数关键在于申请了一大块堆内存,并在给了每个plt重定位项32个字节的空间,存放着指向plt函数名的指针,got表中此函数的地址,plt表中此函数的地址,然后预留了8字节的空间,这8字节具体用处一会会说。(关于got和plt详见动态链接)

接下来是主线程函数,这个函数调用了ptrace函数,所以得对ptrace有所了解。(所以我又学了半天ptrace。。。)

这里先是调用wait函数,当wait函数的参数stat_loc的低8位字节等于0x7f并且低8至16位字节为0x05时(后面会检查这个,不是就跳出while)执行while循环,也就是wait参数为1407时,执行while循环,至于为什么,我也不知道,有大神知道求留言告知。

这里将vul寄存器里的内容保存到内存中。

然后进行了一大堆检查,我没管它们,默认都过了。(好不负责任。。。)

这里当执行到入口的时候,执行if里边的指令。

我认为if里面就是这个sandbox的核心功能了。

vul对某函数进行延迟绑定时,当执行到 jmp linker 这条指令时,从栈上读取该函数的id,并检查当初在initial中申请地址的相应位置的24字节偏移处(就是当初预留出来的8字节)是否为零,如果为零,则正常执行延迟绑定,并在从c库中返回时执行后面的一个else(这个if...else...用来判断vul的指令指针是在.text中还是在c库中)指令,将该函数在c库中的真实地址保存到预留的8字节处,并执行一个函数将got表重置到没有进行延迟绑定时的默认状态。这样当vul从c库返回后再执行这个函数时,sandbox程序直接让vul执行当初预留的地址处的函数。这样做可以使got表一直为未绑定的状态,所以无法从got表获取c库函数的真实地址。

应对方法就是用return to dl-resolve攻击,这里给出两个学习链接Return-to-dl-resolveROP之return to dl-resolve

exp看的flappypig的writeup,也不难理解。通过readelf等命令从头文件中获取必要信息,然后构造fake_relro和fake_sym。

我当初遇到了几个坑,记录一下。

 

  • 第一个坑是不知道为什么要泄露0x600ef0这里面的内容。

这个地址属于.dynamic段。

根据偏移找出这个地址对应DEBUG的value,虽然现在看起来是0,但是这个值会在运行时被改写成指向r_debug结构体的指针。

link_map_addr = l64(io.read(8)) + 0x28 

上面读取r_debug的地址,并加上0x28(应该是r_debug的大小),这个便是link_map的地址。

 

  • 第二个坑是不知道下面的代码到底意义何在。
write_16byte(io, link_map_addr+0x1c8, '\x00'*0x10)

后来看到了ROP之return to dl-resolve这篇文章才知道是为了跳过dl-runtime.c中的一个检查。

 

子线程函数没什么好说的,就是调用了个ptrace函数告诉主线程我可以被跟踪调试,然后execl vul。

 

i64文件

 

总结:复习了一下ELF文件的结构,并了解了ptrace这个东西,总之太菜,还是得多学习一个。

 

参考:

【CTF攻略】第三届XCTF——郑州站ZCTF第一名战队Writeup

ROP之return to dl-resolve

Executable and Linkable Format

Program Header

Dynamic Section

通过DT_DEBUG来获得各个库的基址

 

转载于:https://www.cnblogs.com/1oner/p/6539678.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值