先把白夜学长这篇文章放这,关于ret2syscall的深入浅出,一看就能学会!
下载题目附件后拖入ida,看到vuln函数如下:
思路:
这次不用libc而是使用系统调用(syscall),那么我们就要自己构造系统调用链
其原理就是在Linux的glibc中,大部分系统调用已经被封装成普通的函数,如 read , write , open , execve等,同时也将 syscall 指令进行了封装,以64位Linux的glibc位例,read(0, buf, 0x10) 函数也可以是 syscall(0, 0, buf, 0x10)
read函数的调用号是0,所以这里第一个参数是0,那么我们根据64位的调用表得知execve函数的调用号为0x3b,那么我们这里syscall的调用号参数就要控制为0x3b,这个参数存在寄存器rax中,我们要控制的就是rax的值为0x3b
还是跟以前的ret类题目一样构造ROP链,要对目标文件找到几个/一个片段(gadget)其包括我们所需要的接收pop 寄存器以及syscall的调用
ROPgadget
找到这样一个片段,应该是白夜学长~~(偷懒)~~为了我做题方便直接把这些放一块了,我哭死
需要构造的链
我们需要构造如下一个链:
1 | 'a'*n #垃圾数据 |
需要解决的
目前最大的问题是两个,首先程序本身没有"/bin/sh"这个字符串,不能直接获得这样一个字符串的地址,找不到那么我们怎么办呢?当然是自己写啦!!
没错,仔细观察伪代码可以发现程序第二次输入的str位于BSS段:
那么我们是不是可以将第一次的/bin/sh地址指向bss段的开头,并在第二次输入时在该段输入"/bin/sh"并且在填充"\x00"使读取完/bin/sh就结束读取,这样/bin/sh的问题就解决了
还有一个问题是系统调用号的处理,我们需要控制rax,但怎么控制rax的值呢?
这里就有一个小技巧:read 和 write 函数返回值为输入或者输出的字符串的长度,而返回值存在 ax 寄存器中。可以利用这两个函数来控制系统调用需要的 rax 的值。通过gdb调试我们可以发现,第二次read函数接收的字符串长度会影响ax,而rax初始为0,我们ax有多大,rax就有多大,关于ax与rax的关系有一张图很直观地解释了
他们本身是同一个寄存器的不同部分,很好理解。这样一来我们只要控制第二次输入的长度就可以控制rax,怎么控制呢?当然是在/bin/sh后面填充33个"\x00"啦!,看似不起眼的第二步居然有如此关键的双重作用,不错不错!
exp
根据以上思路,有了以下exp:
1 | from pwn import * |
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !