堆中global_max_fast相干应用 | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

堆中global_max_fast相干应用

申博_新闻事件 申博 129次浏览 未收录 0个评论

媒介

事变的原由还要从*ctf 2019提及,heap_master里能用unsorted bin attack完成一次恣意地点写,一最先想到的是写stdout来完成地点泄漏 ,然则如许要写两次才能完成,花了很大的阅历找别的一次写,依然没有找到,很无望。

预先看wp看到是用一次写完成对变量global_max_fast的掩盖,从而完成后续的应用,对mallocfree中触及global_max_fast举行了肯定的剖析,并连系在网上找到的相干的题目举行了响应的实践。

在最先之前向人人引荐下我写的一个框架pwn_debug,写它的本意是轻易人人的调试,重要的特性有:

  1. 支撑带符号调试glibc,剧本中支撑装置debug版的glibc(x64和x86都支撑),以完成调试的时刻可以或许看到glibc源码。
  2. 支撑分歧版本的glibc调试。如在ubuntu16上调试libc-2.29。
  3. 下断点轻易,不论顺序是不是开启PIE。
  4. 运用轻易,与pwntools兼容起来很简单(我以为)。

源码剖析

此次的源码是基于libc-2.23的,后续的版本到场了tcache,该机制相对来讲对照简单与自力,以是照样基于2.23举行响应的剖析,在64位体系上举行。
global_max_fast这个全局变量的作用是用来标记fastbin的巨细的阈值,小于这个值的堆块会被认为是fastbin,运用fastbin的响应机制举行治理。看下它的界说:

#define set_max_fast(s) \
  global_max_fast = (((s) == 0)                           \
                     ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
#define get_max_fast() global_max_fast

set_max_fast初始化函数最先是在malloc_init_state挪用的,可以或许看到这个宏界说的作用是设置global_max_fast默认值,默认值是0x80。

然后看malloc中关于fastbin的处置惩罚,fastbin处置惩罚很简单,就是找到对应的fastbin的单链表,并从中掏出堆块,若是size搜检经由历程就将该堆块返回:

if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
    {
      idx = fastbin_index (nb);
      mfastbinptr *fb = &fastbin (av, idx);  ## 找到对应的单链表
      mchunkptr pp = *fb;
      do
        {
          victim = pp;
          if (victim == NULL)
            break;
        }
      while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
             != victim);
      if (victim != 0)
        {
          if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))  ## 搜检size
            {
              errstr = "malloc(): memory corruption (fast)";
            errout:
              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
              return NULL;
            }
          check_remalloced_chunk (av, victim, nb);
          void *p = chunk2mem (victim);
          alloc_perturb (p, bytes);
          return p;  #返回
        }
    }

检察free中的fastbin相干的处置惩罚源码:

if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())

    ...
    ## 对size举行基础的搜检
    if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
    || __builtin_expect (chunksize (chunk_at_offset (p, size))
                 >= av->system_mem, 0))
      {
    ...
    ## 对next chunk的size举行搜检
    if (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ
            || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
          }))
      {
        errstr = "free(): invalid next size (fast)";
        goto errout;
      }
    ...

    ## 猎取对应的fastbin index
    unsigned int idx = fastbin_index(size);
    fb = &fastbin (av, idx);

    ...

    do
      {
    /* Check that the top of the bin is not the record we are going to add
       (i.e., double free).  */
    if (__builtin_expect (old == p, 0))
      {
        errstr = "double free or corruption (fasttop)";
        goto errout;
      }
      ...
    p->fd = old2 = old;
      }

关于fastbin的free历程重要包罗以下:

  1. 对开释的堆块的size举行基础的搜检。
  2. 对开释堆块的下一个堆块的size举行基础的搜检。
  3. 猎取开释堆块所对应的fastbin链表对应的索引。
  4. 搜检是不是是double free。
  5. 开释进单链表。

fastbin的单链表治理是对照简单的,与global_max_fast相干且须要注重的代码则是fastbin 所对应的index猎取和index所对应的指针猎取的代码,即fastbin_index宏和fastbin宏,对应代码以下:

#define fastbin_index(sz) \
  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)

#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])

可以或许看到这两个宏仅仅是应用偏移来定位数组的指针,然则arena所对应的malloc_state中fastbins数组相干的界说为:

mfastbinptr fastbinsY[NFASTBINS]

#define NFASTBINS  (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)

到这里题目就对照显着了,若是可以或许改写global_max_fast为一个较大的值,然后开释一个较大的堆块时,由于fastbins数组空间是有限的,其相对偏移将会今后掩盖,若是开释堆块的size可控,便可完成往fastbins数组(main_arena)后的恣意地点写入所堆块的地点。

即应用global_max_fast举行相干的进击

应用场景

关于global_max_fast的应用起主要处理的事变是怎样掩盖global_max_fast。实用的场景应是存在恣意地点写的破绽,然则写入的地点倒是不可控的(也是一个对照大的值),由于若是写入的值也是可控的话就不须要运用这个要领就可以处理了,最典范的应该是unsorted bin attack,可完成往恣意地点写入main_arena中的地点。

前置前提我想也许多是须要泄漏一个libc的地点,不然的话能够会像heap_master中一样须要爆破4bit的地点。

完成恣意地点写的体式格局是:经由历程地点与fastbin数组的偏移盘算出所需free的堆块的size,然后开释响应的堆块,便可完成往该地点写入堆块的地点以进一步应用。

盘算偏移的代码可以或许以下:

fastbin_ptr=libc_base+libc.symbols['main_arena']+8
idx=(target_addr-fastbin_ptr)/8
size=idx*0x10+0x20

此时要处理的事变是往那里写以到达完成应用的目的。能够有许多的处所,理论上来讲只如果main_arena组织体背面的是函数指针或是组织体指针的地点都可以或许,现在很轻易可以或许预想到的是:

  • _IO_list_all
  • stdout
  • stdin
  • stderr
  • __free_hook

复写前面四个就是运用IO_file进击那一套要领,捏造组织体来完成恣意读恣意写或许捏造vtable来完成house of orange进击。

复写__free_hook的话则须要一次uaf来修正开释进去的fd改成system或许one gadget,再将堆块请求出来,从而完成将__free_hook改写成system或许one gadget

实践

在网上找了一下,应用历程当中触及到global_max_fast的题目加上*ctf的heap_master,总共有4题:

  • BCTF 2018的baby_arena
  • 0CTF 2016的zerostorage
  • 胖哈勃杯pwn500-house of lemon
  • *CTF 2019的heap_master

个中胖哈勃杯pwn500-house of lemon,在网上找了半天没找到题目,问出题的0x9a82师傅求题目,师傅说年代太久远了,找不到了,以是终究题目数目是三题。

baby_arena

题目的意义对照简单,供应了三个功用分别是:Create OrderDelete Orderlogin的功用。

破绽也很显着,存在两个破绽:一个是在create的时刻碰到换行符就return了,没有到场\x00字节,致使可以或许泄漏地点;另一个是login中存在一个栈溢出破绽,不克不及掩盖返回地点,然则可以或许掩盖user指针,致使可以或许完成恣意地点写的破绽,然则该破绽写的内容是不可控的,只能写adminclientele字符串。

CVE-2019-2725 二次反序列化jndi注入分析

鉴于漏洞危害较大,作者将文章删除,麻烦管理删除一下,谢谢了。

怎样应用?

起首运用第一个破绽泄漏处libc的地点,依据libc的地点盘算获得global_max_fast_IO_list_all的等地点。

然后应用恣意地点写的破绽将global_max_fast从0x80掩盖为0x6E696D6461(admin),依据偏移开释一个堆块至_IO_list_all,将该堆块请求出来捏造好IO_file组织,从新free至_IO_list_all,接下来要做的就是触发FSOP,由于请求的size都会被认为是fastbin,因而想要触发毛病很简单,随便请求一个巨细的堆块就会触发io flush,从而getshell。

zerostorage

这题应该是对照典范的unsoted bin attack题,ctf wiki和brieflyx大佬的博客的writeup都有写。

值得一提的是writeup是基于老版本的内核,应用泄漏出的libc地点经由历程偏移可以或许获得顺序基址,现在主流的版本彷佛都不可以或许了,想了良久,找到一个只须要libc地点就可以胜利应用的要领,后续也会别的写一个细致的历程发出来。

此题最重要的一个破绽就是uaf,在merge的时刻from idto id没有举行搜检,两者可以或许雷同,致使了一个uaf破绽的构成,从而可以或许完成泄漏libc地点、堆地点和举行unsorted bin attack

在获得泄漏出的地点后,应用unsorted bin attackglobal_max_fast掩盖成main_arena上的地点。接下来开释的堆块都会被当做fastbin往main_arena背面的地点上复写了。

然则往那里写,前面_IO_list_all__free_hook这些目的的偏移所对应的size都是大于0x1000的,而题目的size是限定在0x1000之内的,使得请求出来的堆块size没法到达目的,以是没办法后续举行应用。

现有的writeup是老版本的内核中可经由历程libc基址获得顺序基址,在顺序bss段里组织捏造的fastbin从而完成泄漏随机的异或key然后完成恣意写。

没有顺序基址怎样操纵呢,关键因素末了找到merge的时刻没有对merge出来的size举行搜检,由于堆块最大可为0x1000,因而最大可以或许merge出来0x2000巨细的堆块,可以或许知足需求,复写到_IO_list_all,从而可经由历程捏造io file,像baby_arena一样的应用体式格局,终究拿到shell。由于篇幅的限定,细节就不说了,会在今后的文章给出。

heap_master

heap_master的官方解是用large bin attack,经由剖析,也可以或许运用unsorted bin attackglobal_max_fast连系起来来完成get shell。

这题起首mmap出来0x10000巨细的内存,给了addeditdelete三个选项,add函数是经由历程malloc请求出来一个堆块,然则editdelete都是关于mmap出来的堆块操纵,一个很新鲜的题。

剖析下来,破绽存在的处所是可以或许在大的内存块中捏造堆块开释进去main_arena里,同时依然可以或许edit,可以或许说是一个变相的uaf。

没有泄漏,也不克不及掌握malloc出来的堆块,怎样应用呢?谜底在于unsorted bin attackglobal_max_fast

详细来讲,起首捏造堆块开释到unsorted bin内里,然后再edit 堆块的bk的后俩字节为global_max_fast-0x10的地点,举行unsorted bin attack以完成将global_max_fast掩盖为main_arena中的地点,由于后两字节的低12字节是肯定的,因而只须要爆破4 bit就可以够了,照样很快的。

global_max_fast复写后,我们就具有了恣意地点写堆块地点的才能,往那里写,写哪个堆块地点进去呢?

现在主要处理的题目依然是怎样泄漏地点,此时就想到了修正stdout组织体内里的内容来完成恣意地点泄漏,道理在文章里形貌的对照清晰了,要想完成地点泄漏,须要修正stdout file组织体完成以下前提:

  • _IO_write_base指向想要泄漏的处所。
  • _IO_write_ptr指向泄漏完毕的地点。
  • _IO_read_end即是_IO_write_base以绕过限定。

此时恣意地点写的目的就肯定了,就是上面三个字段的地点,依据偏移将上面三个字段设置为堆地点,个中_IO_write_base_IO_read_end指向之前开释进unsorted bin里包罗libc地点的堆块的地点,_IO_write_ptr指向它完毕的地点,完成今后,再次挪用printf函数的时刻libc地点就会泄漏出来了。

泄漏完成今后就好做了,由于开释堆块的size是可以或许随便捏造的,因而我们可以或许将目的定位__free_hook(size为0x3920),怎样向该hook指针填入system地点呢,道理是应用uaf,详细的操纵是先开释一个堆块到__free_hook中,此时__free_hook包罗的是堆的地点,然后edit谁人堆块,将它的fd改写成system地点,然后再将堆块请求出来,链表操纵完成今后system地点的值就会填入到__free_hook里了,再开释一个堆块便可获得shell。

house of lemon

很可惜没有找到题目,哪位师傅若是有的话可以或许联络我一下,我也想看看。题目的设想与解法0x9a82师傅在它的博客里写的很清晰了,有须要的可以或许进修进修。

小结

文章重要形貌了有关堆应用中global_max_fast相干的道理和题目的剖析,觉得这类要领相干的一些场景包罗:

  • 能够可以或许获得libc地点。
  • 可以或许掌握free堆块的size。
  • 能往恣意地点写然则却无法掌握写的内容。

以此来完成往main_arena背面的恣意地点写堆块地点的结果,以完成后续的应用,相干的破绽应用体式格局包罗unsorted bin attack和house of orange(IO file)等。

一切题目的链接和剧本在我的github内里,exp的编写用了pwn_debug,因而再次向人人引荐下这个框架。


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明堆中global_max_fast相干应用
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址