众所周知,Linux操作系统天生自带一个虚拟分区/proc,该分区下保存硬件信息、内核运行参数、系统状态信息等等,进程运行时的一些信息自然也就存在这个分区下。
虚拟分区/PROC
系统里运行的每一个进程都会在/proc分区下新建一个以自己pid命名的目录,并将本进程的参数存到该目录下。在该目录下可以通过修改cgroup文件,残暴的将进程绑定在某个CPU上,也可以通过修改cpuset文件来优化进程在NUMA架构系统上的运行效率,还可以通过修改oom_adj文件与系统OOM机制sayGoodbye。而ps、top这类查看进程的命令恰恰也就是在/proc分区下收集信息。通俗点讲就是如果让ps、top命令“失明”,就能达到我们隐藏进程的目的了。
初次尝试
网上关于Linux隐藏进程的方式有很多,比如:
1)强行将进程pid变为0,这种方法存在破绽因此不予考虑。
2)系统启动时会依据/etc/fstab文件内容来挂载分区,在proc分区挂载参数中加入hidepid=2参数后,登陆系统的用户只能查看到当前用户启动的进程的信息。也就是说tomcat用户只能看到属于自己的进程信息。这种方法也存在弊端,罐中的黑客只能看到有限的进程信息,可能就会产生会怀疑。如果再存在tomcat提权漏洞,那罐子的身份就会瞬间露馅。所以这种方式也不合适,那么如何才能将我们的问题解决在系统最底层呢
“肝”起来
对于Linux系统来说有着得天独厚的优势,我们可以从内核解决一切问题。可是小编的C语言实在让人捉急,还好我生活在伟大的中国,高手藏于民间啊!!!瞬间得到了广大吃瓜群众的响应,一位妹纸的思路很新颖,在内核中新增两个信号,当进程向内核发出hide信号时,内核将不会为该进程在/proc目录下生成对应的目录,从而也就从底层铲除了进程的信息,即使黑客获得了root权限也无法通过常规手段察觉到蛛丝马迹。除此之外,新增的unhide信号作用恰好与hide信号相反。通过查阅官方文档发现,Demo中使用的内核版本为2.6.15。在include/asm-i386/unistd.h文件中定义新信号294和295。
系统在接收到我们新定义的294和295两个信号之后需要调用对应的函数来做出相应的动作。在kernel/sys.c中我们实现294和295信号调用的函数。如下图说明,sys_hide和sys_unhide两个函数主要功能是修改进程hide变量的值。
踩雷
新内核编译完成后小编本以为可以愉快的玩耍了,结果新内核根本无法启动。通过各种修改启动参数发现,内核报错“kerneltooold”,尴尬了。再次求助妹纸,原来gcc调用的libc不是完全向下兼容的,我们可以通过
来查看当前libc能够编译的最低版本的内核,如下图所示libc-2.5.so可以编译最低到2.6.9版本的内核,如果编译内核版本低于2.6.9的话就会报错导致内核无法启动。
So,我们的libc版本不能太高,又因为Demo中修改的是i386架构的内核源码,所以小编选择的实验环境为CentOS5.11(32bit)。至此,我们就可以成功安装并启动2.6.15版本内核了,然而事情并没有结束。系统供外部进程使用的信号仅有64个。
所以一般情况下我们的进程只能发出这64种信号,我们想要发出294和295号信号就必须借助于与系统关系更密切的C语言来完成。
然后通过执行命令
将hide.c编译为hide.so的动态链接库。以后各位如果有进程需要隐藏的话,只需要在代码里调用hide.so中的hide函数即可,同样unhide函数是它的逆过程。如下图所示,在Python中importctypes,使用它调用hide.so库即可实现当前Python2.7进程的隐藏与恢复。
至此,已经实现了内核级别的进程隐藏,可以愉快地做一些偷偷摸摸的事情了…不要想歪哦~