ret2csu-for-BUUCTF-ciscn_2019_s_3
题目简介
BUUCTF原题,题目链接在这:BUUCTF原题:ciscn_2019_s_3
这道题的坑比较多,通过这题学到了很多细节上的东西,于是记录一下
漏洞点分析
首先拖进IDA观察,main函数就不多说了,直接跟进vuln函数
如图所示,看到read读取0x400字节,因此存在溢出
之后checksec检查,发现只开了NX
之后,查看gadget函数的反汇编,发现存在mov rax,3b的指令,如下图所示;而3b恰好是execve系统调用号
同时,函数表中没有发现任何明显可以泄露地址的函数(puts、write、printf等),所以不能ret2libc
综上,这道题的漏洞点在于通过溢出劫持执行流到ROP链,执行execve(“/bin/sh”,0,0)系统调用
漏洞点利用
首先寻找/bin/sh字符串的位置,shift+F12发现程序本身没有:
因此只能想办法将其布置在某个可写位置
首先想到布置在栈上,但是栈地址未知,需要能够泄露栈地址,这里观察到在vuln函数里存在一个write系统调用会输出0x30个字节,而buf只有16字节,因此该write操作会输出栈上的高地址处内容,有可能泄露栈上某个地址
具体泄露的是什么地址,需要通过调试确定,这里通过python脚本来确定,在0x400501即vuln函数调用read之前设置断点,并将泄露的地址写入文件保存,和buf地址相减计算偏移:
1 | |
具体的操作如下所示:
首先在调用read之前看到buf地址在0x7fff21e640d0,如下图:
之后继续执行程序,看到泄露地址=0x7fff21e64218,如下图:
综上,可以得到泄露地址距离buf地址有0x148字节
第二个问题是如何布置参数,通过ROPgadget工具,可以发现程序本身不存在控制rdx的可用碎片,至此利用思路似乎陷入僵局
但是,任何一个程序的__libc_csu_init函数里基本都会存在一些可以控制各个寄存器的代码段,如下图所示:
可以看到,在0x40059a地址开始,有一系列设置寄存器的指令,并且最后以ret结尾,而从0x400580地址开始,又存在我们想要的设置rdx等寄存器的指令
综上,可以先返回到0x40059a,将栈上布置好的值pop给r12~r15等寄存器;之后返回到0x400580地址处,再将需要的值mov给rdx、rsi等寄存器
这里再说一下payload构造的一些细节:
第一,r15寄存器没有作用(只能控制edi)所以直接置0即可
第二,关键的是r12、rbp、rbx寄存器,由于在第二阶段会call [r12+rbx8]
因此我们可以把rbx置0,r12设置成: 想要的返回地址所在的地址 注意,为什么这里r12要是二级指针,因为是call [r12]而不是call r12(做题时在这里卡了很久,没注意到有一次解引用……)
至于rbp,由于0x400591地址处存在一个比较和循环,所以需要把rbp设置成rbx+1,以便跳出循环,让程序顺利走到最后的ret指令
最后,在第二阶段,还需要填充一共78=56字节的脏数据,因为从0x400596到0x4005a2的指令会让rsp移动56字节
因此构造的payload如下:
1 | |
其中,reals为泄露的栈地址,这里我采用让call [r12]跳转到mov rax,59的指令处,并把该指令布置在/bin/sh字符串的上方
最后一步,确定buffer首地址距离vuln函数返回地址的偏移量
为什么这一步放到最后记录,因为这道题目有一个巨大的坑,如果只通过IDA来确定偏移量,如第一张图所示,offset应该=0x10+0x8=0x18
但是这是错的,这道题不能依赖IDA来确定offset,因为当仔细观察vuln函数的反汇编时会发现,结尾并没有熟悉的leave操作,而是直接ret,并不符合一般函数的退栈流程,因此不能假定返回地址在rbp的高一格位置
至于为什么会出现这种情况?个人怀疑这里是出题者故意设计的,因为我们需要一个syscall ; ret的碎片,所以出题者故意没有加leave指令
因此需要使用cyclic工具来计算偏移量,最后算出来offset=0x10,如下图所示:
综上,可以写出如下的利用脚本:
1 | |
但是至此还没结束,这也是这道题的最后一个坑
由于上述分析是在ubuntu22上进行的,因此当我在本地打通之后,无法打通远程
后来观察题目,发现服务器环境是ubuntu18,因此换了台ubuntu18的虚拟机,重新分析了一遍,发现是泄露地址距离buf的偏移发生了变化(上文算的0x148不对),如下图所示:
可以看到二者距离应该是0x7ffc426e0da8-0x7ffc426e0c90=0x118
其他地址并没有错误,因此将上述脚本中的binshStackAddr改为reals-0x118即可