首先我们看一下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
附近的地址就可以绕过该检查。