unlink函数_PWN-浅析unlink

a5d24f5e7dffe1e6eaf5ac92a5332a04.png

my blog:http://www.pwn4fun.com/

About the unlink

unlink,在CTF中是比较常见的知识点。


What’s the unlink

unlink_chunk函数用于将空闲的chunk从所在的bin中取出( 把一个双向链表中的空闲块拿出来),可以使用下图描述。

66e7ffd9f0e092b54d3e7e2d1e0860d6.png

可能触发unlink的情形:

  • malloc_consolidate()函数将fastbin中的空闲chunk整理到unsorted_bin时
  • malloc()函数将unsorted中的空闲chunk整理到smallbin或者largebin中
  • malloc()函数获取堆空间时

下面是源码:

/* Take a chunk off a bin list. */ static void unlink_chunk (mstate av, mchunkptr p) { //检查chunk的size和next_chunk的prev_size是否一致 if (chunksize (p) != prev_size (next_chunk (p))) malloc_printerr (“corrupted size vs. prev_size”); mchunkptr fd = p->fd; mchunkptr bk = p->bk; //检查fd和bk(双向链表完整性) if (__builtin_expect (fd->bk != p || bk->fd != p, 0)) malloc_printerr (“corrupted double-linked list”); fd->bk = bk; bk->fd = fd; if (!in_smallbin_range (chunksize_nomask (p)) && p->fd_nextsize != NULL) { //检查largebin中next_size双向链表的完整性 if (p->fd_nextsize->bk_nextsize != p || p->bk_nextsize->fd_nextsize != p) malloc_printerr (“corrupted double-linked list (not small)”); if (fd->fd_nextsize == NULL) { if (p->fd_nextsize == p) fd->fd_nextsize = fd->bk_nextsize = fd; else { fd->fd_nextsize = p->fd_nextsize; fd->bk_nextsize = p->bk_nextsize; p->fd_nextsize->bk_nextsize = fd; p->bk_nextsize->fd_nextsize = fd; } } else { p->fd_nextsize->bk_nextsize = p->bk_nextsize; p->bk_nextsize->fd_nextsize = p->fd_nextsize; } } }

根据上面的源码,可以看到相应的检查。
首先是判断size是否相同,当前chunk的size以及next chunk的prev_size。if (chunksize (p) != prev_size (next_chunk (p))) malloc_printerr (“corrupted size vs. prev_size”);
其次是双向链表的完整性,检查fd、bk。if (__builtin_expect (fd->bk != p || bk->fd != p, 0))malloc_printerr (“corrupted double-linked list”);
也就是说,我们需要绕过两个check。
我自己的理解,unlink的检查是这样的,设在chunk0中伪造chunk,free(chunk1),根据prev_size位调节指针减去prev_size到fake_chunk的head部分,而是再根据fakechunk的size位继续调节指针+size,此时,按照正常情况应该到了nextchunk(chunk1)的prevsize位,因此我们在此伪造一个prev_size与fakechunk的size相同,即可绕过检查。当然,我认为,令size和prev_size相同,也是可以的。当然这样要求存在chunk overflow的情况。


How to use it

d85eda11e50aed9deebe5d508f9c8a6e.png

Example

Analysis

例题为:2014 HITCON stkof

首先IDA静态分析一下程序。

4cd3431c795d36bc84eef1f82b6c63a9.png

可以看到主要有三个功能:增、删、改。

首先看create:

8e64ecef8497d89542330180d1523848.png

有一个指针数组存放了chunk的地址,新建的chunk没有大小限制也没有数量限制。
值得注意的是,下标从1开始。
接下来是edit:

a4b43e2f0850dda775d805756dca92db.png


就是普通的修改,然后size自定义, 此处存在chunk overflow的情况。
最后是delete:

718f21b01fc9f7fd1d34bc4121d99537.png


UAF。
保护机制:

f247421b578c1319dca93948eb93de39.png


How to exploit
可以看到有堆块溢出以及UAF漏洞,可以新建两个chunk,在第一个chunk中伪造一个fake chunk绕过unlink检查进行unlink,最后修改GOT表leak libc以及get shell。
值得一提的是,因为程序没有进行setvbuf操作,所以输入和输出操作时,程序会申请缓冲区,有可能会影响我们的操作:

ca2be9cb10d057dfd4b2b66c37bb49c9.png


所以我们可以先去申请一个chunk申请缓冲区,以免影响操作。

626a55dca72a56104ba1fcee9cda297b.png

Start to exploit

9950b9cac298a346a325eb7781fd9d37.png


这样就ok了。
接下来伪造fake chunk并进行unlink。

84213c5acebec3034969b81c2f91c8ce.png


此时free了chunk3,注意溢出修改chunk3的head部分,要注意修改prev_inuse位,即0x90而非0x91,让系统相信我们伪造的fake chunk是free状态的。
这时,ptr = ptr – 0x18 = chunk[0] – 0x8
修改ptr中的指针指向GOT表。

1ccf9f2141d309de37cc28bfa3543f5c.png

34febe8c4051bbecf38167921cf17166.png


然后修改GOT表的内容,因为数组指针下标从1开始(如下图)

9141095f9e20039e0557d8f3992f89a2.png


但是我们修改ptr的时候并不会绕过下标0。

5b4705e9b6fc9fcab20862f58a2df574.png

aa026cb8a62ebb136a09749d3d89e23a.png


leak successfully。

43feadc4b38d86411db371803ee2ca17.png


接下来就是常规get shell。

850b7e5f5c9aef62dd0949b3655f1e51.png

Reference:CTF-WIKI

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值