主要是内存布局好之后,通过 unlink 来修改指针
正常的 unlink 是当我们去 free 一个 chunk 的时候,如果这个 chunk 的前一个或后一个是 free 的状态,glibc 会把它从链表里面取出来,与现在要 free 的这个合并再放进去,取出来的这个过程就是 unlink
wiki 上面的一个示意图,Fd 是前置指针,Bk 是后置指针
ulink 有一个保护检查机制,他会检查这个 chunk 的前一个 chunk 的 bk 指针是不是指向这个 chunk(后一个也一样)我们需要绕过他的检查
how2heap 这个程序展示了怎样利用 free 改写全局指针 chunk0_ptr 达到任意内存写的目的,即 unsafe unlink
ulink 有一个保护检查机制,他会检查这个 chunk 的前一个 chunk 的 bk 指针是不是指向这个 chunk(后一个也一样)
先在 main 函数上设置一个断点,然后单步走一下,走到第 13 行(不包括)
我们来看一下,申请了两个堆之后的情况
上面说的那个检查 fd/bk 指针是通过 chunk 头部的相对地址来找的,我们可以用全局指针 chunk0_ptr 构造一个假的 chunk 来绕过
再单步走到第 20 行(不包括)
这两行代码做了个减法,使得从这个地方数起来正好可以数到我们伪造的哪一个 fake chunk
chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
上面那个图没对齐,用文本来解释一下
我们的 fake chunk 的 fd 指向 0x601058 然后 0x601058 的 bk 指向 0x601070
fake chunk 的 bk 指向 0x601060 然后 0x601060 的 fd 指向 0x601070,可以保证前后都指向我们伪造的这个 chunk,完美!
另外我们利用 chunk0 的溢出来修改 chunk1 的 prev_size 为 fake chunk 的大小,修改 PREV_INUSE 标志位为 0,将 fake chunk 伪造成一个 free chunk。
接下来释放掉 chunk1 因为 fake chunk 和 chunk1 是相邻的一个 free chunk,所以会将他两个合并,这就需要对 fake chunk 进行 unlink,进行如下操作
FD = P->fd
BK = P->bk
FD->bk = BK
BK->fd = FD
通过前面的赋值操作
P->fd = &P - 3 * size(int)
P->bk = &P - 2 * size(int)
也就是说:FD = &P - 3 * size(int),BK = &P - 2 * size(int)
FD->bk 按照偏移寻址,就是 FD+3*size(int) 也就等于 &P,FD->bk = P,同理 BK->fd = P
这样执行下来,最终实现的效果是 P = &P - 3 * size(int)
也就是说,chunk0_ptr 和 chunk0_ptr[3] 现在指向的是同一个地址
这个师傅注释很详细,帮了大忙,下面也是根据这个 exp 复现的
https://blog.csdn.net/weixin_42151611/article/details/97016767
完整 exp:
运行连个菜单都不给...
把名字改一下
create 功能,输入一个 size,然后申请 size 大小的堆块
会把申请的堆块的地址写到这里(并不是,是 s[1],因为先 ++ 了)
edit 功能,编辑已经创建好的堆块,但是没有对长度进行检查,所以存在堆溢出
wp 说没有 setbuf,会先申请 1024 的堆空间??
要先提前申请个 chunk 来防止他们干扰??
怎么就能防止干扰了??
其实只要先申请一个,让程序把两个缓冲区分配好了,别后面插在我们申请的两个之间就可以吧
黄色指的是提前申请的一个用来占空的
两个白色是缓冲区占用的,这样后面再申请就连起来了
这时候来改写第 2 个(从 1 开始计数)伪造一个 free 的 chunk(黄线分割了第 2 和第 3 个)
payload 如下:
这样填充完了就是这样的,在原本第 2 个 chunk 里面伪造了一个 free 的 chunk,大小是 0x20,然后把 fd 跟 bk 指针写为了 p64(head+16-0x18) 和 p64(head+16-0x10)。同时把下一个堆块的 prev_size 位写成了 0x30(前一个 chunk 加上开头的大小),以及 size 位的 prev_inuse 为 0
这样,对第 3 个进行 free 的时候会发生 unlink,head + 16 与 head +16 -0x18
那么最终的效果就是我们编辑第二个的时候就是编辑的 head + 16 - 0x18,也就是 0x602138
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!