Linux Rootkit:内核 5.7+ 的新方法

Linux Rootkit:内核 5.7+ 的新方法

文章目录

  • [Linux Rootkit:内核 5.7+ 的新方法](https://xcellerator.github.io/posts/linux_rootkits_11/)
  • 这是怎么回事?
  • ProcFS 更改
  • Kallsyms 问题
  • 系统调用名称问题
  • 就这样……

这是怎么回事?

早在 2020 年 2 月, LKML上就有一些关于kallsyms_lookup_name()从内核取消导出的骚动。造成这种情况的主要原因是,不道德的模块开发人员通常会简单地添加MODULE_LICENSE('GPL')到他们的代码中(而没有实际许可他们的模块)。然后,通过使用kallsyms_lookup_name(),他们可以随心所欲地使用任何其他导出的内核函数。内核开发人员不喜欢这样,因为它使树外模块能够调用非导出函数。

显然,这对我们来说是一个问题!特别是,ftrace_helper.h用于kallsyms_lookup_name()获取我们想要挂钩的函数的地址。事实上,从内核版本 5.7 开始,我们不能再使用这个函数了(diff)。

除了这一更改之外,5.6 版本的发布还对 procfs 系统进行了一些其他更改。虽然这些修复相对较小,但为了在ftrace_helper.h更新的内核上工作,还有更多的工作要做。

值得注意的是,截至撰写本文时,可用于 Ubuntu 20.04 的最新内核是5.4.0-60-generic,因此如果您使用 LTS,这些更改实际上不会影响您。但能够走在时代前沿真是太好了!

ProcFS 更改

让我们先处理一下更改proc_create()。这是一个非常简单的修复,但说明了一种在不破坏现有支持的情况下处理此类更改的好方法。查看v5.5.19中的声明,我们看到:

struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops);

复制

我们在《Privileged Container Escapes with Kernel Modules》escape.c中使用了该声明。然而,从 5.6 版本开始,现在看起来像这样:proc_create()

struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops);

复制

请注意,最后一个参数已从file_operations结构体更改为proc_ops结构体?我们需要在代码中考虑这一变化。我们关心的这些结构体之间有两个主要区别:

  • 不再有.owner字段proc_ops
  • IO 处理程序的.read/字段现在分别称为/.write``.proc_read``.proc_write

那么,处理这些变化的最佳方法是什么?使用预处理器!特别是,<linux/version.h>为我们提供了LINUX_VERSION_CODEKERNEL_VERSION宏。这些让我们非常简单地实现这些更改:

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
// proc_ops version
static const struct proc_ops proc_file_fops_escape = {.proc_write = escape_write,
};static const struct proc_ops proc_file_fops_output = {.proc_write = output_write,.proc_read = output_read,
};
#else
// file_operations version
static const struct file_operations proc_file_fops_escape = {.owner = THIS_MODULE,.write = escape_write,
};static const struct file_operations proc_file_fops_output = {.owner = THIS_MODULE,.write = output_write,.read = output_read,
};
#endif

复制

至此,第一个问题就解决了!docker escape 现在可以编译并按5.10.6-arch1-1预期工作。相同的代码仍然可以5.4.0-60-generic在 Ubuntu 20.04 上编译。

此修复已合并到存储库中。您可以在此处查看上面提到的更改。

Kallsyms 问题

现在,我们遇到一个稍微困难一点的问题。如果没有kallsyms_lookup_name(),我们无法轻松地将符号名称解析为内存地址,这意味着我们无法使用 ftrace 挂钩函数(回想一下,我们使用 ftrace 来注册当等于$rip我们想要挂钩的函数的内存地址时触发的回调) )。

我最初的想法是寻找一个不同的内核函数(仍然导出的),它可以用来无意中解析符号名称。我决定与sprint_symbol()执行相反的操作kallsyms_lookup_name(),即给定一个内存地址,它返回该地址处的函数名称。

使用这个,我决定从基地址向上循环地址,sprint_symbol()每次调用并strncmp()ing 直到找到我想要的函数。虽然有点不雅观,但效果却出奇的好。它看起来像这样:

/** kaddr is an unsigned long which holds the memory address being looped over* fname_lookup is a kernel buffer which stores the name of the function at kaddr* fname is a kernel buffer storing the function we're searching for*//** Trick to get the kernel base address* sprint_symbol() is less than 0x100000 bytes from the base address, so* we can just AND-out the last 3 bytes from it's address to obtain the address* of startup_64 (the kernel load address)*/
kaddr = (unsigned long) &sprint_symbol;
kaddr = &= 0xffffffffff000000;/* During testing, all the interesting functions were found below this limit */
for ( i = 0x0 ; i < 0x100000 ; i++ )
{sprint_symbol(fname_lookup, kaddr);if (strncmp(fname_lookup, fname, strlen(fname)) == 0){/* Match! Clean up and exit */kfree(fname_lookup);return kaddr;}/* Kernel function addresses are all aligned, so we skip 0x10 bytes */kaddr += 0x10;
}
kfree(fname_lookup);

复制

如果我最终没有使用这种技术,为什么我还要费心告诉你呢?有两个原因;首先是为了说明剥猫皮的方法总是不止一种。其次是因为我上面使用的技巧来获取内核基地址。我面临的问题是如何知道从哪里开始暴力破解。加载内核的地址被称为startup_64(您可以在 中找到它/proc/kallsyms),但是内核地址空间布局随机化意味着该地址将在每次启动时发生变化。然而,即使我们不能使用,我们仍然可以通过使用运算符来获取任何导出的kallsyms_lookup_name()内核函数的地址。&

sprint_symbol如果您检查系统上的和的地址startup_64,您会发现只有最后 3 个字节不同。这是因为距内核开头sprint_symbol不到字节。0x100000这种差异在重新启动之间不会改变。因此,我们只需删除最后三个字节即可获得基地址!尽管它已经在上面的代码片段中,但我会再次将其放在这里,因为我认为它非常酷:

/* Get the address of sprint_symbol() */
kaddr = (unsigned long) &sprint_symbol;/* Set the last 3 bytes of the address to 0x00 */
kaddr &= 0xffffffffff000000;

复制

当我致力于完善这项技术时,@f0lg0在 GitHub 上提出了一个问题,提出了这个问题,并提出了一种使用 kprobes 的很酷的技术。

Kprobe系统允许您动态地将断点插入正在运行的内核中。我们将使用它来完成kallsyms_lookup_name()查找自身的工作!

经过一番反复讨论后,他们想出了一个非常巧妙的解决方案。他们在该评论中的代码很好地说明了主要思想。我们只需声明一个kprobe结构体,并将.symbol_name字段预设为kallsyms_lookup_name。一旦注册了kprobe,我们就可以取消引用该.addr字段来获取内存地址!

为了有效且整齐地实施这项技术,我希望所有的更改都在ftrace_helper.honly 中。这里的技巧是使用<linux/version.h>上面提到的宏来检查内核版本,然后在kallsyms_lookup_name()像平常一样使用之前手动解析。

最初,我们只是包含<linux/kprobes.h>并声明该kprobe结构:(请参阅此处):

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {.symbol_name "kallsyms_lookup_name"
};
#endif

复制

就位后,在尝试使用之前kallsyms_lookup_name(),我们只需添加以下代码片段。需要做的就是注册 kprobe,将.addr字段分配给一个名为的符号kallsyms_lookup_name(在适当地转换它之后),然后在完成后取消注册 kprobe(请参阅此处)。

#ifdef KPROBE_LOOKUP/* typedef for kallsyms_lookup_name() so we can easily cast kp.addr */typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);kallsyms_lookup_name_t kallsyms_lookup_name;/* register the kprobe */register_kprobe(&kp);/* assign kallsyms_lookup_name symbol to kp.addr */kallsyms_lookup_name (kallsyms_lookup_name_t) kp.addr;/* done with the kprobe, so unregister it */uregister_kprobe(&kp);
#endif

复制

当然,如果我们不是在内核 5.7+ 上进行编译,那么这些都不会触发,并且kallsyms_lookup_name()将由内核头解析(就像之前的情况一样)。这样,我们就不必对现有代码进行任何更改ftrace_helper.h- 并且 5.7 之前的内核版本不受影响!

系统调用名称问题

最后,还有另一个小补丁修复了一直困扰我的问题。ftrace_helper.h尽管共享相同的名称,但存储库中实际上有两个略有不同的文件。原因是我使用宏来添加__x64_到系统调用名称,但问题是没有一种简单的方法(据我所知)仅添加__x64_到以sys_. ftrace_helper.h为了解决这个问题,我只是在没有挂接系统调用时删除了相应的宏。

这是非常不优雅的,所以我决定完全删除宏,并简单地手动添加__x64_到任何rootkit.c挂钩系统调用的 s 中。缺点是不再自动支持 32 位内核(您必须__x64_HOOK()宏中删除rootkit.c并重新编译),但现在 32 位并没有太多问题(我实际上没有测试过任何内容) 32 位,所以我什至不知道哪些模块已损坏以及哪些模块可以工作!)。

就这样……

现在,存储库中的 Rootkit 技术可与最新内核配合使用!再次感谢@f0lg0他们使用 kprobes 来解析的想法kallsyms_lookup_name()- 绝对比暴力破解地址更简洁。

直到下一次…

阅读其他帖子


←Janus:BGGP 2021 的多语言二进制文件Fancy Bear 是一名伐木工人,没关系 - 深入了解 Drovorub 的内核组件→

哈维菲利普斯 2020 - 伦敦, 英国:: panr制作的主题

该网站是闹鬼网络的一部分

Drovorub 的内核组件→](https://xcellerator.github.io/posts/linux_rootkits_10/)

哈维菲利普斯 2020 - 伦敦, 英国:: panr制作的主题

该网站是闹鬼网络的一部分

<<< 随机 >>>

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

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

相关文章

如何把vue项目打包成桌面程序 electron-builder

引入 我们想要把我们写的vue项目,打包成桌面程序&#xff0c;我们需要使用electron-builder这个库 如何使用 首先添加打包工具 vue add electron-builder 选择最新版本 下载完毕 我们可以看到我们的package.json中多了几行 electron:build&#xff1a;打包我们的可执行程序 e…

vue实现二维数组表格渲染

在Vue中渲染二维数组表格可以采用嵌套的<template>和v-for指令。 写法一 <template> <table> <thead> <tr> <th v-for"(header, index) in headers" :key"index">{{ header }}</th> </tr> </t…

在 iOS 上安装自定企业级应用

了解如何安装您的组织创建的自定应用并为其建立信任。 本文适用于学校、企业或其他组织的系统管理员。 您的组织可以使用 Apple Developer Enterprise Program 创建和分发企业专用的 iOS 应用&#xff0c;以供内部使用。您必须先针对这些应用建立信任后&#xff0c;才能将其打…

服装品牌如何利用数字化工具提升商品管理效率

随着科技的快速发展&#xff0c;数字化工具在商品管理中的应用越来越广泛。数字化工具不仅可以提高商品管理的效率&#xff0c;还可以帮助企业更好地满足客户需求&#xff0c;提升市场竞争力。本文将探讨如何利用数字化工具提升商品管理效率。 一、建立数字化管理系统 数字化…

备战蓝桥杯---搜索(应用基础1)

话不多说&#xff0c;直接看题&#xff1a; 显然&#xff0c;我们直接用深搜&#xff0c;我们可以先把空位用结构体存&#xff0c;然后打表存小方块&#xff0c;再用数组存行列。 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace std; int a[12][12];…

【leetcode】1512. 好数对的数目(简单)题解学习

题目描述&#xff1a; 给你一个整数数组 nums 。 如果一组数字 (i,j) 满足 nums[i] nums[j] 且 i < j &#xff0c;就可以认为这是一组 好数对 。 返回好数对的数目。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1,1,3] 输出&#xff1a;4 解释&#xff1a;有 4 …

OSG程序如何适配在无显卡的Ubuntu系统中

最近&#xff0c;嵌入式机器需要搞一个使用OSG开发的程序&#xff0c;但是发现弄上去后&#xff0c;各种问题&#xff0c;非常头疼&#xff0c;所以我花费了很多时间去查阅资料&#xff0c;终于解决了这个问题&#xff0c;因此写一下博客&#xff0c;记录下这个问题&#xff0c…

linux中的gdb调试

gdb是在程序运行的结果与预期不符合时&#xff0c;可以使用gdb进行调试 注意&#xff1a;使用gdb调试时要在编译上加-g参数 gcc -g -c hello.c 启动gdb调试&#xff1a; gdb file 对gdb进行调试 设置运行参数&#xff1a; set args 可指定运行参数 show args 可以查…

React实例之完善布局菜单(二)

我们继续未完的课程。 我们已经设计完所有theme的有关逻辑和代码了。接下来就是菜单部分&#xff0c;首先&#xff0c;菜单分为菜单头和菜单列表&#xff0c;还有收缩模式和缩略模式。为配置能用化的考虑&#xff0c;我们在菜单配置方面采用了 Json 数组。而菜单本身的数据状态…

uniapp基于Android的环境保护环保商城系统生活垃圾分类 小程序_rsj68

本环境保护生活App是为了提高用户查阅信息的效率和管理人员管理信息的工作效率&#xff0c;可以快速存储大量数据&#xff0c;还有信息检索功能&#xff0c;这大大的满足了用户和管理员这两者的需求。操作简单易懂&#xff0c;合理分析各个模块的功能&#xff0c;尽可能优化界面…

WPF布局面板

StackPanel StackPanel 是一种常用的布局控件,可以支持水平或垂直排列,但不会换行。当子元素添加到 StackPanel 中时,它们将按照添加的顺序依次排列。默认情况下,StackPanel 的排列方向是垂直的,即子元素将从上到下依次排列。可以使用 Orientation 属性更改排列方向。可以…

Apache POI与easyExcel:Excel文件导入导出的技术深度分析

在处理Excel文件时&#xff0c;Java开发者经常会面临多种选择&#xff0c;其中Apache POI和easyExcel是两个非常受欢迎的选择。这两个库都提供了强大的Excel文件处理功能&#xff0c;但在性能、内存使用、API设计以及扩展性方面有所不同。本文将深入分析Apache POI和easyExcel在…

开发中小程序遇到的问题总结

1. backdrop-filter样式的作用 backdrop-filter 是CSS中的一个属性&#xff0c;用于为元素的背景区域添加图形效果&#xff0c;如模糊或者颜色偏移。这个属性的使用需要满足一定的条件&#xff0c;即元素本身或者其背景至少部分必须是透明的&#xff0c;这样才能让附加的效果显…

Unity 通过配置文件生成代码

文章目录 示例1&#xff1a;基于ScriptableObject的配置生成类示例2&#xff1a;预制体路径列表生成加载代码示例3&#xff1a;动画剪辑生成动画控制器片段示例4&#xff1a;Excel配置表生成序列化类示例5&#xff1a;UI元素及其事件绑定生成代码 在Unity编辑器模式下&#xff…

【BBF系列协议】TR181-2 TR369的设备数据模型

针对CWMP端点和USP代理的TR-181设备数据模型 执行摘要 TR-181问题2定义了设备数据模型的版本2(设备:2)。设备:2数据模型适用于所有类型的TR-069或USP启用的设备,包括终端设备、住宅网关和其他网络基础设施设备。 本技术报告中定义的设备:2数据模型由一组数据对象组成,…

电商实战练习部署

基于阿里云ECS服务器实战部署 1 单架构部署方案 1.1 部署流程 传统方案 基于docker 2 持续集成&持续部署方案 随着软件开发复杂度的不断提高&#xff0c;团队开发成员间如何更好地协同工作以确保软件 开发的质量已经慢慢成为开发过程中不可回避的问题。互联网软件的开发…

护眼台灯有aaa级吗为什么?一文揭晓护眼台灯照度等级分类

尽管台灯是一个很成熟的行业&#xff0c;但却时不时也会冒出一些新的概念和名词。比如近些年的”AAA级”台灯&#xff0c;很频繁地出现在我们视野中。给人感觉似乎带”AAA级”的台灯&#xff0c;要比其他的强上一头。那到底是真是假呢&#xff1f; 一、护眼台灯有AAA级吗&…

字节跳动推出MagicVideo-V2超高清文生视频模型

&#x1f989; AI新闻 &#x1f680; 字节跳动推出MagicVideo-V2超高清文生视频模型 摘要&#xff1a;MagicVideo-V2是由字节跳动的研究人员开发的一种超高清文生视频模型。该模型在视频的高清度、润滑度、连贯性、文本语义还原等方面表现出色&#xff0c;比目前主流的文生视…

leetcode 1.两数之和(C++)DAY1(待补充哈希表法)

文章目录 1.题目描述示例提示 2.解答思路3.实现代码结果4.总结 1.题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&…

ffmpeg操作实战001:视频+音频文件融合

一、功能需求 把视频文件video.mp4 和音频文件audio.wav融合在一起&#xff0c;输出视频文件output.mp4 二、操作指令 ffmpeg -i video.mp4 -i audio.wav -c:v copy -map 0:v:0 -map 1:a:0 output.mp4 三、参数说明 ffmpeg: 这是用于执行FFmpeg命令行工具的命令。-i video…