前言
通过一道PWN题目学习ROP。
随着 NX 保护 (No-eXecute 不可执行) 的开启,以往直接向栈或者堆上直接注入代码的方式难以继续发挥效果。攻击者们也提出来相应的方法来绕过保护,目前主要的是 ROP (Return Oriented Programming),其主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段 (gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。所谓 gadgets 就是以 ret 结尾的指令序列,通过这些指令序列,我们可以修改某些地址的内容,方便控制程序的执行流程。
ROPgadget工具可以帮助你寻找合适的gadgets,在编写你的ROP exp
的时候有很大作用。ROPgadget支持x86, x64, ARM, ARM64, PowerPC, SPARC和MIPS架构下的ELF/PE/Mach-O文件格式。
这里我们需要构造的gadget如下
1 | mov eax,0xb |
0x00
checksec查看开启了哪些保护机制
1 | % checksec ret2syscall |
通过查看架构得之主要的寄存器有eax ebp ebx ecx..
程序执行如下,输出前两句后接受输入,然后退出
1 | [root@VM-16-14-centos rop]# ./ret2syscall |
反编译查看,从gets函数得之存在溢出漏洞
pwndbg
查看寄存器位置,发现eax寄存器位置为0xffffd29c
,ebp
寄存器的位置为0xffffd308
,如果我们想要覆盖掉ebp
寄存器的位置,则需要填充的字节为0xffffd308-0xffffd29c
字节再加上ebp
所占的4个字节,因为架构是32位的。即需要填充112字节。
0x01
接着我们通过ROPgadget
工具寻找gadget
首先寻找eax的pop|ret
地址,选择0x080bb196
地址最合适
1 | % ROPgadget --binary ret2syscall --only "pop|ret" | grep eax |
接着寻找ebx的pop|ret
地址,有很多,哪一个最适合呢,发现0x0806eb90
最合适,因为它也有ecx
和edx
寄存器。
1 | % ROPgadget --binary ret2syscall --only "pop|ret" | grep ebx |
最后我们寻找int
,地址为0x08049421
1 | % ROPgadget --binary ret2syscall --only "int" |
因为ebp寄存器中需要写入/bin/sh
,因此我们还需要在程序中找到/bin/sh
的地址
在ghidra
中全局搜索发现地址为0x80be408
或者通过python编写脚本获取
1 | from pwn import * |
0x02
编写exp
1 | from pwn import * |
0x03
本地执行exp
获取shell
1 | [root@VM-16-14-centos rop]# python3 exp.py |