Skip to content

fastbin_reverse_into_tcache

复制本地路径 | 在线编辑

建议直接看 tcache_stashing_unlink 记录文章,建议从头看到尾,不要贪图块。尤其是最后面的引申,把这两个攻击完全串起来了。

这里还是简单稍微介绍一下:

  1. 申请 N 块内存,释放七次,塞满 tcahe;然后释放七次,全都放进了 fastbin
  2. 把 fastbin 最后一个块,里面的 fd 指针修改成目标地址 target_addr
  3. 申请七次块,目的是清空 tcahe,这样只有 fastbin 中有数据了
  4. 申请一次,malloc 会从 fastbin 中找到块,此时会触发 stash 机制,把剩下的块放入到 tcache 中
  5. 由于第 2 步中,最后一个块的 fd 被修改成了 target_addr,所以 target_addr 也被放入了 tcahe,最终 malloc 一次就得到了目标地址的块

要求:可以复写某个 freed chunk 的 fd 内容
效果:任意地址块控制

而且因为这样思考和延申,我还发现了 how2heap 中 fastbin_reverse_into_tcahe.c 的错误,之前这个文件的注释认为第 1 步中不一定要释放七次块到 fastbin 中,但其实是必须的。

当时的提交 Issue(英文):https://github.com/shellphish/how2heap/issues/222

当时 Issue 的本地草稿

fastbin_reverse_into_tcahe 中,注释宣称如果目标控制地址的内容为 0,那么可以指释放一个 fastbin:

    char* victim = ptrs[7];
    printf("The next pointer that we free is the chunk that we're going to corrupt: %p\n"
           "It doesn't matter if we corrupt it now or later. Because the tcache is\n"
           "already full, it will go in the fastbin.\n\n", victim);
    free(victim);

    printf("Next we need to free between 1 and 6 more pointers. These will also go\n"
           "in the fastbin. If the stack address that we want to overwrite is not zero\n"
           "then we need to free exactly 6 more pointers, otherwise the attack will\n"
           "cause a segmentation fault. But if the value on the stack is zero then\n"
           "a single free is sufficient.\n\n");

    // Fill the fastbin.
    // for (i = 8; i < 14; i++) free(ptrs[i]);

    // 如果按照注释,我们只释放一个
    free(ptrs[8]);

此时堆空间为:

[fastbin] -> victim -> target_addr(it's fd is zero)

注释这样写应该是认为 fd 为 0,此时 stash 会终止。

但由于 safe-linking,把 target_addr 放入到 tcache 时,会解析 target_addr→next 为一个非法地址 REVEAL_PTR(0),而不是 0,因此会检测失败:

/* 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.  */
    while (tcache->counts[tc_idx] < mp_.tcache_count && (tc_victim = *fb) != NULL)
    {
        if (__glibc_unlikely (misaligned_chunk (tc_victim)))
            malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");

        if (SINGLE_THREAD_P)
            // 如果 tc_victim->fd,但 *fd 并不是 0,最终导致上一条语句的检测失败
            *fb = REVEAL_PTR (tc_victim->fd);
        else
        {
            REMOVE_FB (fb, pp, tc_victim);
            if (__glibc_unlikely (tc_victim == NULL))
            break;
        }
        tcache_put (tc_victim, tc_idx);
    }
}

Comments