基本 ROP
ROP (Return Oriented Programming),主要思想是在栈缓冲区溢出的基础上,利用程序中已有的小片段(gadgets) 来改变某些寄存器或者变量的值,从而控制程序的执行流程。
ROP 攻击一般需要满足如下条件
1.程序存在溢出,并且可以控制返回地址。
2.可以找到满足条件的 gadgets 以及相应 gadgets 的地址。
ret2text
原理:控制程序执行程序本身已有的的代码
需求:程序存在可以直接控制shell的代码,比如 system(“/bin/sh”) 或者 system(“sh”)
模板如下
from pwn import * |
ret2shellcode
原理:控制程序执行 shellcode 代码,shellcode 指的是用于完成某个功能的汇编代码,常见的功能主要 是获取目标系统的 shell。
需求:
1.需要对应的 binary 在运行时,需要找到一个可读可写可执行的区域写入并执行shellcode,这个 地方通常在bss段,可以使用gdb动态调试,使用vammp查看执行权限及所处位置
2.checksec时 NX disabled
NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。
shellcode格式:
- 64位文件 shellcode = asm(shellcraft.amd64.sh())
- 32位文件 shellcode = asm(shellcraft.sh())
模板如下
from pwn import * |
ret2syscall
原理:控制程序执行系统调用,获取 shell
需求:<32位程序>
1.系统调用号,即 eax 应该为 0xb
2.第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
3.第二个参数,即 ecx 应该为 0
4.第三个参数,即 edx 应该为 0
5./bin/sh或者sh字符串的地址
6.函数调用号int 0x80 的地址
构建方法:
<1>寄存器地址
- ROPgadget --binary 文件名 --only ‘pop|ret’ | grep ‘寄存器名’
<2>/bin/sh字符串地址
- ida中使用shift+f12,再用crtl+f查找字符串
2. ROPgadget --binary 文件名 --string ‘/bin/sh’
3. 加载本地elf文件之后 binsh =next(elf.search(b’/binsh’))
<3>int0x80 函数号地址
- ROPgadget --binary 文件名 --only ‘int’
<4>payload的构建
* payload = flat([cyclic(offset),寄存器pop|ret地址,寄存器内容,连续3个寄存器pop|ret地址,寄存器1内容,寄存器2内容,寄存器3内容,函数号地址])
from pwn import * |
ret2libc
原理:控制函数的执行 libc 中的函数,通常是返回至某个函数的 plt 处或者函数的具体位置 (即函数对应的 got 表项的内容)。一般情况下,我们会选择执行 system(“/bin/sh”),故而此时我们需要知道 system 函数的地址。
构建方法:
1.是否有system函数
if(1)
直接用ida查看sys函数的位置,记下即可,当然动态调试gdb也是可以的
if(0)
\1. 想办法泄露system的地址,一般选择在溢出点之前使用过的puts,read,write等函数
puts函数 |
2.根据泄露的地址确定基地址,由libc的加载的版本号确定
libc = ELF (“./libc版本号”) //确定libc的版本
libc_base = leak_addr - libc.sym[‘leak_func’] //确定libc的基地址
sys_addr = libc_base + libc.sym[‘system’] //通过偏移量找到system函数
bin_sh_addr = libc_base + libc.search(‘/bin/sh’).next() //在libc中找到/bin/sh字符串
3.是否有/bin/sh字符串或者sh字符串
if(1)
直接用ida查看/bin/sh或者sh字符串的地址,当然动态调试gdb也是可以的
if(0)
想办法构造一个字符串
\1. binsh = libc.search(‘/bin/sh’).next() //这种方法是通过加载libc
\2. binsh =next(elf.search(b’/binsh’)) //这种方法是通过加载elf文件
64位 exp模板
from pwn import* |
32位 exp模板
from pwn import* |
EOF