Unsafe Unlink

1.unsorted bin

首先介绍unsorted bin,unsortedbin 是一个双向链表的结构,因此a中这两个指针分别是bk和fd,分别指向前一个和后一个chunk;free时,若该chunk没有紧邻top chunk,则不会与top chunk进行合并,它首先被链入unsorted bin中,被首次分配时,unsorted bin会扫描各chunk并根据大小链入不同bin中。

pCaRpX8.png

简介

Unsafe Unlink指的是早期unlink,没有大小检查、双向链表完整性检查,并且没有NX保护

当进行unlink时,会执行如下操作:

pCaRCnS.png

1
2
this->fd->bk = this->bk;
this->bk->fd = this->fd;

因此,如果我们能够伪造fd和bk的指向,就可以实现任意地址写入,而要进行unlink操作我们需要修改next_chunk的pre_inuse为0,这是free掉next_chunk会使这两个chunk进行合并。

条件

  1. 未开启NX保护。

  2. 程序存在堆溢出漏洞可以覆盖next_chunk的prev_size和size域或存在UAF漏洞。

  3. 可以泄露出libc地址和堆的基地址。

利用

  1. 在当前chunk中写入shellcode,这里的shellcode比较特殊,由于unlink时会覆盖掉一部分

​ shellcode代码,因此需要jmp和nop配合。

  1. 伪造当前chunk的fd = &__free_hook - 0x18,bk = 当前chunk的地址 + 0x20(shellcode地址)。

  2. 利用堆溢出或UAF伪造next chunk的prev_size为当前chunk大小,然后将next chunk的size域中

​ prev_inuse标志位置0。

  1. free(next_chunk),程序会误认为当前chunk已释放而执行unlink操作:
  • 首先,根据next_chunk的prev_size计算出当前chunk的地址。

  • 然后,根据fd找到前面的fake_chunk,在fake_fd + 0x18地址写入bk指针。

  • 然后,根据bk找到后面的fake_chunk,在fake_bk + 0x10地址写入fd指针。

完整构造如下:

1
2
3
4
5
6
7
8
9
a = malloc(0x88)
b = malloc(0x88)
edit(a,b'a'*0x88+p64(0x90))
fd = &__free_hook - 0x18
bk = &shellcode
shellcode = asm("jmp shellcode;"+ "nop;"*0x20+ shellcraft.execve("/bin/sh"))
edit(a, p64(fd) + p64(bk) + shellcode + p8(0)*(0x70-len(shellcode)) + p64(0x90)*2
free(b) //进行unlink将shellcode地址写入freehook
free() //调用freehook执行shellcode