首页
社区
课程
招聘
[原创]Large bin attack--LCTF2017-2ez4u--writeup
发表于: 2017-12-12 21:22 9316

[原创]Large bin attack--LCTF2017-2ez4u--writeup

2017-12-12 21:22
9316

技巧性很强的一道题,当时自己写的思路和官方的不一样,后面看着官方的wp看了半天才把思路看懂。

这道题很关键的一个点在于伪造large bin chunk,并将该chunk分配出来,从而实现空间复用,所以先解释下large bin分配的过程,源代码如下:

有关堆的管理与结构不多说,需要强调下的是,large bin数组里的不再是存储大小一样chunk,而是可以存储等差数列变化的chunk块。large bin chunk结构体中的fd_nextsize和bk_nextsize俩个字段是有意义的,large bins中空闲chunk是按照大小排序的,但同一个大小的chunk可能有多个,增加这俩个字段可以加快遍历空闲chunk,fd_nextsize指向下一个比当前chunk大小大的第一个空闲块,bk_nextsize指向前一个比当前chunk大小小的第一个空闲chunk。

总结下large bin chunk分配的过程,查询对应的large bin链表,不为空的话,反向遍历,chunk size链表直到找到第一个大于等于所需chunk大小的chunk退出循环。找到合适的chunk之后,使用unlink将该块分配出来,并设置好相应的结构。

还需要看下unlink的代码,之前做的相关题目都是small bin的unlink,对于large bin之前也都没注意,从代码中可以看到,就是多了fd_nextsize和bk_nextsize俩个位置的检查,原理和fd和bk的检查一致。

题目是经典的菜单题,有创建、编辑、删除、打印四个功能。
漏洞是UAF漏洞,即在删除堆块后并没有将存储指针的全局变量清空,还能够重复的编辑,如何使用这一点拿到shell就是这道题的考点。

题目的第一个难点在于泄露地址,程序本身还开启了PIE,由于打印的时候,打印的位置是从分配堆块的0x18的位置开始打印的,而正常堆块的fd与bk俩个指针在前0x10字节,想要通过常规的利用这俩个字段泄露地址好像有点难度,此时就想要了前面提到过的fd_nextsize和bk_nextsize这俩个字段。所以就想办法通过large bin来实现攻击。
首先泄露堆地址,构造俩个large bin chunk,大小在同一个bins中,将其释放后,此时俩个chunk会被释放到unsorted bin中,再申请一个大小大于这俩个chunk的块,此时这俩个chunk会被放到相应的large bin中,同时fd_nextsize与bk_nextsize会被赋值,再利用UAF打印即可得到堆块地址。

在泄露堆地址后,接下来需要泄露libc地址,根据官方的wp,使用的方法是伪造large bin chunk,我觉得神奇的地方在于不需要将伪造的堆块释放,而是修改之前被释放堆块的bk_nextsize字段即可,对应到源代码中代码即victim = victim->bk_nextsize,这一点使用UAF即可做到,但想要将该堆块申请出来,还需要绕过unlink的限制,这也可以通过UAF实现。在可以将伪造的堆块申请出来之后,我们可以在伪造的堆块中包含有正常的small bin,这样就可以达到泄露出libc地址以及修改内存的目的。

可以利用刚刚伪造的堆块包含fastbin,接下来只需要覆盖fastbin的fd指针,就可以构造合适的chunk,使得将main_arena的top指针覆盖为free_hook的上面一些的地址。
这一点对于我来说是个新姿势,学到了。具体来说,首先使用修改fastbin fd的方式,将main_arena的fastbin数组的一个指针修改为0x60,这样就获得了在申请fastbin时需要绕过检查的size位,接着将另一个数组的相应fd指向为main_arena合适的位置,即可将top指针上放的指针当作chunk申请出来,从而实现将top指针修改为__free_hook上方的位置,再接着就是多申请几次,将hook指针覆盖为system函数地址即可。

exploit如下,是官方的wp,加了一些注释:


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (5)
雪    币: 295
活跃值: (64)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
先膜一发
2017-12-12 21:27
0
雪    币: 699
活跃值: (444)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
3

fd_nextsize应该指向的是下一个比当前chunk 小的第一个空闲块吧?

largebins
0x3c0: 0x804b000 —▸ 0x804bf80 —▸ 0x804b7f0 ◂— 0xf7fbf680
0x804b000 PREV_INUSE {
  prev_size = 0, 
  size = 1017, 
  fd = 0x804bf80, 
  bk = 0xf7fbf680 <main_arena+608>, 
  fd_nextsize = 0x804bf80, 
  bk_nextsize = 0x804b7f0
}
0x804bf80 PREV_INUSE {
  prev_size = 0, 
  size = 985, 
  fd = 0x804b7f0, 
  bk = 0x804b000, 
  fd_nextsize = 0x804b7f0, 
  bk_nextsize = 0x804b000
}
0x804b7f0 PREV_INUSE {
  prev_size = 0, 
  size = 969, 
  fd = 0xf7fbf680 <main_arena+608>, 
  bk = 0x804bf80, 
  fd_nextsize = 0x804b000, 
  bk_nextsize = 0x804bf80
}

2018-3-21 12:49
0
雪    币: 699
活跃值: (444)
能力值: ( LV9,RANK:240 )
在线值:
发帖
回帖
粉丝
4
看您的wp有些地方不懂,方便的话能讲一下么~
LIBC  =  u64(io.recv(6)+'\x00\x00')-0x3c4be8
log.info("libc  base  0x%016x"  %  LIBC)
这个-0x3c4be8是怎么算出来的呢
2018-3-25 23:19
0
雪    币: 1184
活跃值: (174)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
5
sakura零 看您的wp有些地方不懂,方便的话能讲一下么~ LIBC = u64(io.recv(6)+'\x00\x00')-0x3c4be8 log.info("libc base 0x%016x ...
这是main  arena的某个地址,应该是smallbin数组的地方吧,我忘记了,直接减去偏移就可以了,vmmap查看libc基址,然后看泄露出来的地址,相减就得到这个偏移
2018-3-27 22:51
0
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
楼上说的对,fd_nextsize指向的是下一个比当前chunk  小的第一个空闲块
2018-4-3 15:58
0
游客
登录 | 注册 方可回帖
返回
//