暑假集训——Hitcon_Trainning——lab11_bamboobox——堆unlink

UNLINK

思路

其实是艰辛的心路历程

这道题是昨天晚上这个时间就想到的思路 [虽然是道基础题但是是难得的一道没看别人exp就想到怎么写的题,当时觉得自己已经登顶了(bushi] 毕竟是一道套路题的确套路了我【微笑.jpg】

change_note这个函数里面没有检查输入长度,堆溢出。堆的几个漏洞里面,堆溢出我只会unlink,所以就顺着这个思路一直往下写了。

UNLINK

  1. 概念
  • 合并

    当一个chunk不属于fastbin的范围时,就会触发向前合并或向后合并。

    前提是合并的chunk不在使用当中。

    合并之后就会被放进unsortedbin中。

    之后还需要判断这个合并之后的总chunk的大小是否大于FASTBIN_CONSOLIDATION_THRESHOLD, 大于就会触发fastbins的合并操作,合并之后仍旧放入unsortedbin,直至fastbins为空。

  • UNLINK触发情形

    本质就是将一个bin中的某个结点拿出来,在分配内存和由free()带来的合并操作都会触发。

    当free(a)时,a物理相邻的前一个chunk——b, 被判断 是空闲的,那么b就会从原有bin中断开,和a合并。

  • 发生了什么

    暑假集训——Hitcon_Trainning——lab11_bamboobox——堆unlink_第1张图片
    其实就是一个简单的双向链表删除某个结点,数据结构讲过很多遍的。
    p是一个指向需要unlink的chunk的整个chunk的起始位置

    FD = *(p->fd)
    BK = *(p->bk)
    *(FD->bk) = BK
    *(BK->fd) = FD
    //p->fd == p + SZ_WORD * 2
    // 其他同理
    

    SZ_WORD是程序的一个字长我忘却了各大源码里用的啥,瞎编的名字…

    这个堆溢出在没有很久很久以前没有检查机制的时候是可以很简单地实现地址任意写的。只要

    FD = target_addr - SZ_WORD * 3
    BK = shellcode
    

    unlink之后就会有

    *target_addr = shellcode
    

    但是那也是很早很早的事情了。如今开了防御措施,会检查FD->bk和BK->fd是否等于p。

    但是也不是不能利用了,我们先要找到一个指针ptr==p。

    fd = ptr - SZ_WORD * 3
    bk = ptr - SZ_WORD * 2
    

    unlink的时候就可以绕过检查机制

    FD->bk == ptr - SZ_WORD * 3 + SZ_WORD * 3 == ptr
    BK->fd == ptr - SZ_WORD * 2 + SZ_WORD * 2 == ptr
    

    会得到

    FD->bk =  ptr - SZ_WORD * 2
    BK->fd = ptr - SZ_WORD * 3
    

    也就是

    *ptr = ptr -  SZ_WORD * 3
    

    ptr最终指向的是ptr前面一点的地方,往ptr里面写payload就能够覆盖ptr本身。然后再次往ptr里面写payload,就能实现地址任意写了。

    在覆盖chunk_1的presize时,指的是构造的fake_chunk_0包括size和presize的大小。覆盖size的时候,原来这个地方是什么,就只要把最后一位从1变为0就好,不要改他的大小。不然会提示
    在这里插入图片描述

    但是我不知道为什么。按理来说,应该没得关系,难道是因为AMP里面的p位标识是0?可是double free不也可以吗,而且也不会报和size有关的错叭?

    这个整个chunk的起始位置和presize、size就是今天的一个我的大坑之一。

    nodelist的地址指向的是非空闲chunk数据开始的地方,而检查的时候,是检查这个地址是不是指向这个chunk的presize。

    我一开始想的是用chunk_0溢出伪造chunk_1空闲的假象,然后free(chunk_0)。也就是向后合并。

    我错在直接在chunk_1的原来的presize的地方开始构造,但是nodelist[1]不指向这里,也没有一个可以利用的指向这里的指针,所以通不过防御机制。

    而且就算我从nodelist[1]这个地方开始构造,因为没有改到chunk_0的size域,导致ptmalloc找chunk_1的时候找到的还是chunk_1的presize的地方。

    所以这个题是只能向前合并的[我jio得]。

    size 和 presize就纯粹是脑子没转过弯来以及知识盲区。

    哇塞真的好菜啊TAT

    unlink可以看一个大佬写的关于unlink的分析 超详细超厉害der!

惊天巨坑!

昨天一晚上今天一上午,我都在想,为什么,我的exp让一个chunk在free之后,只是把相关数据清零,但是这个chunk并没有被放进任何一个bins。

然后我找了别人的exp跑了一下,卡死了。

我直接用gdb调试二进制文件,发现不是exp的原因,free()这个函数就很玄学,他不按说好的来啊根本就!!

我环境是glibc2.27, 师傅让我在2.23里面跑一下。
发现是没问题的。

含恨在2.23里面调试,但是2.23不行啊,生成容器的时候默认的安全机制开太大了gdb根本没法用。师傅说的解决方法我没有理解,于是又看了一下午docker怎么用 *[露出菜鸟的疲惫微笑]* 。我以为就是在run一个新的容器就好,没想到这个最简单的镜像里啥都没有。这里不得不说感谢师傅帮忙装好了python和gdb和一些别的环境,我一下子真的弄不来[头秃]。最后灵光一闪懂了大佬说的那个解决方法,用现有容器commit一个镜像再run一个容器。【菜是真的菜】

那么2.27到底是个什么机制我也没有搜到。

这个题还有另外一个解决方法! 明天再说!耶!

你可能感兴趣的:(堆,hitcontrainning,unlink)