unsorted bin attack作为一种久远的攻击方式常常作为其他攻击方式的辅助手段,比如修改global_max_fast为一个较大的值使得几乎所有大小的chunk都用fast bin的管理方式进行分配和释放,又或者修改__IO_list_all来伪造_IO_FILE进行攻击。在上述攻击的利用过程中我们实际上并不需要对unsorted bin的分配过程有太多的了解
//源码的第3470行-3597行 while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av)) //取链表尾部的chunk记作victim { bck = victim->bk; //size check //倒数第二个chunk记作bck //接下来对victim的size位进行检查 if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0) || __builtin_expect (victim->size > av->system_mem, 0)) malloc_printerr (check_action, "malloc(): memory corruption", chunk2mem (victim), av); size = chunksize (victim); //检查通过,计算victim得到的实际chunk的大小 /* If a small request, try to use last remainder if it is the only chunk in unsorted bin. This helps promote locality for runs of consecutive small requests. This is the only exception to best-fit, and applies only when there is no exact fit for a small chunk. */ //last remainder first if (in_smallbin_range (nb) && bck == unsorted_chunks (av) && victim == av->last_remainder && (unsignedlong) (size) > (unsignedlong) (nb + MINSIZE)) //假如说我们申请的malloc大小属于smallbin的范围,并且last_remainder是unsortedbin 的唯一一个chunk时,优先使用这个chunk { /* split and reattach remainder */ //假若满足条件则对其进行切割和解链操作 remainder_size = size - nb; remainder = chunk_at_offset (victim, nb); //cut and put the remained part back to unsorted list unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder; av->last_remainder = remainder; remainder->bk = remainder->fd = unsorted_chunks (av); if (!in_smallbin_range (remainder_size)) { remainder->fd_nextsize = NULL; remainder->bk_nextsize = NULL; }
check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); //return to user return p; } //如果说上述条件不满足,则将vivtim从链中取出之后放到合适的链中或返回给用户 //其中unsorted_chunks (av)->bk = bck; //bck->fd = unsorted_chunks (av); //unsorted bin attack产生的原因, //一旦我们绕过之前的检查到达这里, //在可以控制victim->bk即bck的情况下我们可以往bck->fd写入unsorted_chunks(av) //即*(bck+0x10)=unsorted(av)。 /* remove from unsorted list */ //unsorted bin attack unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
/* Take now instead of binning if exact fit */ //如果我们请求的nb同victim的大小恰好吻合,就直接返回这个块给用户。 if (size == nb) { set_inuse_bit_at_offset (victim, size); if (av != &main_arena) victim->size |= NON_MAIN_ARENA; check_malloced_chunk (av, victim, nb); void *p = chunk2mem (victim); alloc_perturb (p, bytes); return p; }
/* place chunk in bin */ //如果之前的条件都不满足,意味着目前的victim不能满足用户的需求, //需要根据其size放入small bin或large bin的链, //其中在后者实现中存在large bin attack, //由于同本文无关就不再进一步展开,最后是unlink将victim彻底解链。 if (in_smallbin_range (size)) { victim_index = smallbin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; } else { victim_index = largebin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd;
/* maintain large bins in sorted order */ if (fwd != bck) { /* Or with inuse bit to speed comparisons */ size |= PREV_INUSE; /* if smaller than smallest, bypass loop below */ assert ((bck->bk->size & NON_MAIN_ARENA) == 0); if ((unsignedlong) (size) < (unsignedlong) (bck->bk->size)) { fwd = bck; bck = bck->bk;
pwndbg> b +12 Breakpoint 1 at 0x400730: file demo.c, line 13. pwndbg> r Starting program: /root/CTF-PWN/Unsortedbin Attack/pwn unsorted bin attack 实现了把一个超级大的数(unsorted bin 的地址)写到一个地方 实际上这种攻击方法常常用来修改 global_max_fast 来为进一步的 fastbin attack 做准备