House of Corrosion, 无需泄露任何的地址即可getshell,适用于glibc2.27,利用条件是存在一个可以写至少10字节的UAF漏洞,存在1/16的爆破。首先释放一个NO_MAIN_ARENA被置为1的largebin,利用unsorted bin attack覆写global_max_fast,此时unsorted bin bk指针被覆写为了dumpe_main_arena_end的地址,在此地址上伪造一个large bin,size大小与释放的largebin相同。利用fatbin 的特性即文中提到的原语1,2,3覆写stderr结构体的成员变量和vtable指针,覆写_s._allocate_buffer函数指针为call eax的gadget,_IO_buf_end,_IO_buf_base之间的差值为one_gadget的地址。之后申请一个chunk触发unsorted bin的清空,伪造的chunk就会被插入到largebin链表中,在插入过程中触发NO_MAIN_ARENA的检查断言,进而刷新stderr,调用改写之后的vtable,进入IO_str_overflow,调用_s._allocate_buffer函数指针,也就是call eax,此时eax是_IO_buf_base,_IO_buf_end之间的差值, 也就是one_gadget, getshell。

House Of Corrosion

House Of Corrosion是是一种针对glibc 2.27\\\\2.29的堆利用技术,可以在不泄露地址的情况下完成getshell。其主要的原理是覆写global_max_fast,从而将堆地址写入fastbin[i]指定的位置。

利用的前提条件是存在一个UAF漏洞,可以造成WAF 10 bytes。并且需要随机爆破4 bits的地址(1/16的概率)。其利用流程如下

  1. 利用UAF构造unsorted bin attack爆破,覆写global_max_fast
  2. 结合堆风水,UAFfastbin attack覆写stderr
  3. 触发stderrgetshell

原语(Primitives)

原语1-覆写main_arena高地址的任意位置为堆地址

利用unsorted bin attackglobal_max_fast覆写为main_arena附近的地址之后,再次释放堆块就会进入fastbin[i]中,也就是将释放堆块的地址写入fastbin[i]的位置,其中目标地址与申请的堆块大小之间的关系是

chunk_size = (delta * 2) + 0x20

其中delta是第一个fastbin与目标地址之间的距离(以字节为单位)。需要注意的是在free的时候会存在一个检查

if (have_lock && old != NULL
    && __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
    malloc_printerr ("invalid fastbin entry (free)");

这里这个old是目标地址中存储的值。根据free的调用流程,发现__libc_free在调用_int_free函数时将have_lock置为了0,因此这里就不会存在这个检查,相关代码如下

void
    __libc_free (void *mem)
{
    //...
    _int_free (ar_ptr, p, 0);
}
static void
_int_free (mstate av, mchunkptr p, int have_lock){
    //...
}

此时我们可以将target address覆写为一个堆地址,该堆块属于fastbin

原语2-main_arena高地址任意写

在原语1中我们已经将target address覆写为了堆地址,那么此时只要我们利用UAF覆写堆块的fd指针为value,在将该堆块申请回来,根据fastbin的特性,target address中的内容就会被改写为value。如下所示

target->heap_address->NULL;
//UAF overwrite fd
target->heap_address->value;
//malloc heap
target->value;