首先我们看一下glibc 2.30中的源代码
if (in_smallbin_range (nb))
{
idx = smallbin_index (nb);
bin = bin_at (av, idx);
if ((victim = last (bin)) != bin)
{
bck = victim->bk;
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): smallbin double linked list corrupted");
set_inuse_bit_at_offset (victim, nb);
bin->bk = bck;
bck->fd = bin;
if (av != &main_arena)
set_non_main_arena (victim);
check_malloced_chunk (av, victim, nb);
#if USE_TCACHE
/* While we're here, if we see other chunks of the same size,
stash them in the tcache. */
size_t tc_idx = csize2tidx (nb);
if (tcache && tc_idx < mp_.tcache_bins)
{
mchunkptr tc_victim;
/* While bin not empty and tcache not full, copy chunks over. */
while (tcache->counts[tc_idx] < mp_.tcache_count
&& (tc_victim = last (bin)) != bin)
{
if (tc_victim != 0)
{
bck = tc_victim->bk;
set_inuse_bit_at_offset (tc_victim, nb);
if (av != &main_arena)
set_non_main_arena (tc_victim);
bin->bk = bck;
bck->fd = bin;
tcache_put (tc_victim, tc_idx);
}
}
}
#endif
void *p = chunk2mem (victim);
alloc_perturb (p, bytes);
return p;
}
}
从源代码中我们可以看出,如果我们控制了一块small bin的bk指针,就可以向任意的位置写入一个main_arena附近的地址,在small bin中加入指定的堆块,进而在内存中分配一个指定的chunk。当前前提是我们需要绕过下面的检查
bck = victim->bk;
if (__glibc_unlikely (bck->fd != victim))
这其中bck就是我们伪造的bk指针,因此我们只要在指定的位置写入一个堆内存地址(victim的地址),就可以绕过该检查。
从上面的代码中我们可以看到,在small bin分配之后,如果small bin链表中仍然存在堆块,并且对应的tcache list不为空的话,就会将small bin链表中所有的堆块放入到tcache中。当然要发生这种分配的方式必须可以越过tcache分配堆块,因为malloc在tcache中存在堆块的时候会首先在tcache中返回堆块,calloc则不经过tcache。
注意此时加入tcache的部分没有进行安全检查。那么之后攻击方式与House of Lore Attack相同。但是这里需要注意的是tcache将所有的small bin加入tcache的特性
tcache中有一个空位,small bin中需要一个chunk。可以在指定地址(bk+0x10)中写入main_arena附近的地址,而且不用再指定地址+0x10处写入可写内存的地址
tcache中有两个空位,small bin中需要两个chunk。可以在指定地址中写入main_arena附近的地址,分配指定位置的chunk。但是需要构造下面的chunk链

small bin中有两个chunk,我们需要将第一个chunk的bk指针覆写为fake_chunk-0x10,fake_chunk即我们想要分配到的内存地址。之后需要将fake_chunk+0x10的位置写入一个具有可写权限的内存地址,因为将会在此地址处写入main_arena附近的地址。那么之后申请一次0x90大小的堆块,就会将fake_chunk放入到tcache中,用malloc申请就可以得到该chunk。
该题目利用Tcache Stashing Unlink向指定位置写入了main_arena附近的地址,绕过程序的检查,从而向特定地址写入rop链,利用程序原有的函数调用执行rop。
改题目利用Tcache Stashing Unlink,堆溢出,分配mmap_address处的内存,进行函数布局,利用程序原有的函数调用执行system
程序提供了四种功能add,delete,change,show,在删除的时候存在UAF漏洞。程序只提供特定大小的堆块分配0x10,0xf0,0x400,0x300。当用户输入是666的时候会提供一个栈溢出的函数,该函数的调用需要满足条件

我们可以通过Tcache Stashing Unlink来讲mmap_address+0x800更改为main_arena附近的地址就可以绕过该检查。