技术分享 | Linux 入侵检测中的进程创建监控

发布者:网易易盾
发布于:2019-07-21 20:48

作者简介:张博,网易高级信息安全工程师。


0x00 简介

在入侵检测的过程中,进程创建监控是必不可少的一点,因为攻击者的绝大多数攻击行为都是以进程的方式呈现,所以及时获取到新进程创建的信息能帮助我们快速地定位攻击行为。

本文将介绍一些常见的监控进程创建的方式,包括其原理、Demo、使用条件和优缺点。行文仓促,如果有哪些错误和不足,还望大家批评指正。


0x01 常见方式

目前来看,常见的获取进程创建的信息的方式有以下四种:

  • So preload
  • Netlink Connector
  • Audit
  • Syscall hook

下面我们就从原理、Demo、使用条件和优缺点来了解一下这四种方式。


0x02 So preload

原理

首先跟大家介绍两点基础知识:

1.Linux 中大部分的可执行程序是动态链接的,常用的有关进程执行的函数例如 execve均实现在 libc.so 这个动态链接库中。

2.Linux 提供了一个 so preload 的机制,它允许定义优先加载的动态链接库,方便使用者有选择地载入不同动态链接库中的相同函数。

结合上述两点不难得出,我们可以通过 so preload 来覆盖 libc.so 中的 execve等函数来监控进程的创建。

Demo

下面我们就来实现一个简单的 demo 。

1.创建文件 hook.c ,内容如下:

#define _GNU_SOURCE

#include


该文件的主要部分就是重新定义了 execve函数,在原始的 execve执行之前打印可执行文件的名字。

2.生成动态链接库:gcc hook.c-fPIC-shared-o hook.so

3.将上面生成的动态链接库注册成 preload :echo'/path/to/hook.so'>/etc/ld.so.preload

4.退出当前 shell 并重新登录(下面会讲原因),执行命令即可看到我们编写的代码已被执行:


使用条件

该方法没有什么条件限制,只需有 root 权限即可(做入侵监控程序 root 权限是必需的,后面的几种方法默认也都是在 root 权限下)。

优缺点

优点

  • 轻量级,只修改库函数代码,不与内核进行交互。

缺点

对于使用方法的第四步,可能大家会有疑问:为什么一定要重新获取 shell 才可以看到效果呢?这是因为其实在当前 shell 下执行命令(也就是执行 execve)的实际上是当前的 shell 可执行程序,例如 bash ,而 bash 所需的动态链接库在其开始运行时就已确定,所以我们后续添加的 preload 并不会影响到当前 bash ,只有在添加 preload 之后创建的进程才会受 preload 的影响。这也就得出了该方法的第一个缺点:

  • 只能影响在 preload 之后创建的进程,这就需要检测 Agent 安装得越早越好,尽量在其他应用进程启动之前就完成安装。

除此之外还有以下几点缺点:

  • 无法监控静态链接的程序:目前一些蠕虫木马为了降低对环境的依赖性都是用静态链接,不会加载共享库,这种情况下这种监控方式就失效了。
  • 容易被攻击者发现并篡改:目前一些蠕虫木马本身也会向 /etc/ld.so.preload 中写入后门,以方便其对机器的持久掌控,这种情况下这种监控方式也会失效。
  • 攻击者可通过 int80h绕过 libc 直接调用系统调用,这种情况下这种监控方式也会失效。


0x03 Netlink Connector

原理

在介绍 Netlink Connector 之前,首先了解一下 Netlink 是什么,Netlink 是一个套接字家族(socket family),它被用于内核与用户态进程以及用户态进程之间的 IPC 通信,我们常用的 ss命令就是通过 Netlink 与内核通信获取的信息。

Netlink Connector 是一种 Netlink ,它的 Netlink 协议号是 NETLINK_CONNECTOR,其代码位于 9f9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6@1L8%4u0$3j5h3I4V1M7#2)9J5c8X3I4A6L8Y4g2^5i4K6u0r3N6s2u0W2k6g2)9J5c8X3#2S2M7%4c8W2M7W2)9J5c8X3c8J5K9i4k6W2M7Y4y4Q4x3V1k6U0L8$3&6F1k6h3y4@1L8%4t1`. 中,其中 connectors.c 和 cnqueue.c 是 Netlink Connector 的实现代码,而 cnproc.c 是一个应用实例,名为进程事件连接器,我们可以通过该连接器来实现对进程创建的监控。

系统架构:

(图片来源:296K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2K6L8r3W2V1k6i4y4Z5j5i4u0W2i4K6u0W2L8X3g2@1i4K6u0r3K9$3g2J5L8X3g2D9N6r3I4$3i4K6u0r3K9$3g2J5L8X3g2D9i4K6u0V1M7s2u0G2j5#2)9J5k6r3y4G2L8X3&6W2j5%4c8G2M7W2)9J5k6r3q4F1k6q4)9J5k6r3y4G2L8Y4c8S2K9h3&6W2M7Y4y4Q4c8f1k6Q4b7V1y4Q4z5o6V1`.


具体流程:

(图片来源:6bdK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1j5@1K9r3!0#2i4K6u0W2N6$3W2F1i4K6u0r3N6$3!0J5k6s2m8J5k6i4y4K6i4K6u0r3i4K6y4r3M7q4)9K6c8o6t1&6y4e0R3$3i4@1g2r3i4@1u0o6i4K6R3&6


图中的 ncp 为 Netlink Connector Process,即用户态我们需要开发的程序。

Demo

在 Github 上已有人基于进程事件连接器开发了一个简单的进程监控程序:682K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Y4k6%4u0S2L8X3c8W2M7#2)9J5k6r3y4D9L8$3&6W2M7#2)9J5c8Y4m8E0L8$3&6Q4x3V1k6T1L8r3!0T1i4K6u0r3L8h3q4K6N6r3g2J5i4K6u0r3M7%4u0U0i4K6u0r3M7r3#2G2L8W2)9J5k6h3x3`. ,其核心函数为以下三个:

  • nl_connect:与内核建立连接
  • set_proc_ev_listen:订阅进程事件
  • handle_proc_ev:处理进程事件

其执行流程正如上图所示。

我们通过 gcc pmon.c-o pmon生成可执行程序,然后执行该程序即可看到效果:


获取到的 pid 之后,再去 /proc/<pid>/目录下获取进程的详细信息即可。

使用条件

内核支持 Netlink Connector

  • 版本 > 2.6.14
  • 内核配置开启: cat/boot/config-$(uname-r)|egrep'CONFIG_CONNECTOR|CONFIG_PROC_EVENTS'

优缺点

优点

  • 轻量级,在用户态即可获得内核提供的信息。

缺点

  • 仅能获取到 pid ,详细信息需要查 /proc/<pid>/,这就存在时间差,可能有数据丢失。


0x04 Audit

原理

Linux Audit 是 Linux 内核中用来进行审计的组件,可监控系统调用和文件访问,具体架构如下(图片来源:900K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6L8r3q4U0K9#2)9J5k6h3g2F1k6$3W2F1k6h3g2J5K9h3&6Y4i4K6u0r3M7%4W2K6j5$3q4D9L8q4)9J5k6r3q4#2k6r3W2@1K9h3&6Y4i4K6u0V1j5i4c8Q4x3X3c8K6j5$3q4D9k6g2)9J5k6r3f1$3j5e0y4U0j5e0S2S2j5K6q4T1z5q4!0q4c8W2!0n7b7#2)9^5z5g2!0q4c8W2!0n7b7#2)9&6b7b7`.`.


1.用户通过用户态的管理进程配置规则(例如图中的 go-audit ,也可替换为常用的 auditd ),并通过 Netlink 套接字通知给内核。

2.内核中的 kauditd 通过 Netlink 获取到规则并加载。

3.应用程序在调用系统调用和系统调用返回时都会经过 kauditd ,kauditd 会将这些事件记录下来并通过 Netlink 回传给用户态进程。

4.用户态进程解析事件日志并输出。

Demo

从上面的架构图可知,整个框架分为用户态和内核态两部分,内核空间的 kauditd 是不可变的,用户态的程序是可以定制的,目前最常用的用户态程序就是 auditd ,除此之外知名的 osquery 在底层也是通过与 Audit 交互来获取进程事件的(d72K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0k6h3c8A6N6h3#2Q4x3X3g2U0L8$3#2Q4x3V1k6H3j5h3I4S2L8Y4c8A6M7W2)9J5c8X3q4#2k6r3W2@1K9h3&6Y4i4K6u0V1N6$3W2@1K9q4)9J5k6r3!0K6M7i4g2W2M7Y4W2Q4x3X3c8H3j5i4u0@1i4K6u0V1L8$3&6W2i4K6u0V1K9h3&6@1M7X3!0V1N6h3y4@1K9h3!0F1i4K6u0V1N6r3!0Q4x3X3c8@1K9r3g2Q4x3X3c8D9K9h3&6#2P5q4)9J5k6r3q4#2k6r3W2@1i4K6u0V1k6Y4u0S2L8h3g2%4L8%4u0C8i4K6u0V1x3U0p5%4z5e0j5%4j5$3g2U0y4o6l9$3i4@1g2r3i4@1u0o6i4K6R3&6i4@1f1K6i4K6R3H3i4K6R3J5i4@1f1@1i4@1t1^5i4K6S2n7i4@1f1&6i4K6W2p5i4@1p5J5i4@1f1$3i4K6R3^5i4K6V1I4i4@1f1@1i4@1u0n7i4@1q4o6i4@1f1#2i4@1t1H3i4@1t1I4i4@1f1%4i4@1q4q4i4K6R3H3i4@1f1#2i4K6S2p5i4K6V1#2i4@1f1@1i4@1u0n7i4K6S2n7i4@1f1%4i4@1u0n7i4K6S2p5i4@1f1@1i4@1t1^5i4K6R3H3i4@1f1@1i4@1t1^5i4K6S2n7i4@1f1#2i4@1p5$3i4K6R3J5i4@1f1@1i4@1u0p5i4K6V1#2i4@1f1&6i4K6R3H3i4K6W2m8i4@1f1^5i4@1u0r3i4K6R3%4 auditd 来监控进程创建。

首先安装并启动 auditd :

  • apt update && apt install auditd
  • systemctl start auditd && systemctl status auditd

auditd 软件包中含有一个命名行控制程序 auditctl,我们可以通过它在命令行中与 auditd 进行交互,用如下命令创建一个对 execve这个系统调用的监控:

  • auditctl -a exit,always -F arch=b64 -S execve

再通过 auditd 软件包中的 ausearch来检索 auditd 产生的日志:

  • ausearch -sc execve | grep /usr/bin/id


整个过程的执行结果如下:


至于其他的使用方法可以通过 man auditd和 man auditctl来查看。

使用条件

内核开启 Audit

  • cat/boot/config-$(uname-r)|grep^CONFIG_AUDIT

优缺点

优点

  • 组件完善,使用 auditd 软件包中的工具即可满足大部分需求,无需额外开发代码。
  • 相比于 Netlink Connector ,获取的信息更为全面,不仅仅是 pid 。

缺点

  • 性能消耗随着进程数量提升有所上升,需要通过添加白名单等配置来限制其资源占用。


0x05 Syscall hook

上面的 Netlink Connector 和 Audit 都是 Linux 本身提供的监控系统调用的方法,如果我们想拥有更大程度的可定制化,我们就需要通过安装内核模块的方式来对系统调用进行 hook 。

原理

目前常用的 hook 方法是通过修改 sys_call_table( Linux 系统调用表)来实现,具体原理就是系统在执行系统调用时是通过系统调用号在 sys_call_table中找到相应的函数进行调用,所以只要将 sys_call_table中 execve对应的地址改为我们安装的内核模块中的函数地址即可。

具体的实现细节可参考 YSRC 的这篇关于驭龙 HIDS 如何实现进程监控的文章:cedK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8X3&6@1c8e0g2r3e0V1@1^5g2h3q4j5f1f1k6o6y4h3H3@1K9f1E0g2g2i4M7`. ,这里贴出文章里的一张图方便大家对整个流程有个直观地了解:


Demo

关于 Syscall hook 的 Demo ,我在 Github 上找了很多 Demo 代码,其中就包括驭龙 HIDS 的 hook 模块,但是这些都无法在我的机器上( Ubuntu 16.04 Kernel 4.4.0-151-generic )正常运行,这也就暴露了 Syscall hook 的兼容性问题。

最后我决定使用 Sysdig 来进行演示,Sysdig 是一个开源的系统监控工具,其核心原理是通过内核模块监控系统调用,并将系统调用抽象成事件,用户根据这些事件定制检测规则。作为一个相对成熟的产品,Sysdig 的兼容性做得比较好,所以这里用它来演示,同时也可以方便大家自己进行测试。

具体步骤如下:

1.通过官方的安装脚本进行安装:

curl-s 16cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6x3#2)9J5k6h3q4E0j5i4A6G2L8X3q4%4M7#2)9J5k6h3y4G2L8g2)9J5c8X3c8G2N6$3&6D9L8$3q4V1i4K6u0W2k6s2u0S2K9h3!0K6i4K6u0W2j5$3!0E0i4K6u0r3M7%4c8S2j5X3I4W2i4K6u0r3K9h3&6K6N6r3q4D9L8q4)9J5k6s2y4&6M7$3c8A6k6H3`.`. | sudo bash

2.检测内核模块是否已经安全:lsmod|grep sysdig

3.启动对 execve的监控:sysdig evt.type=execve

最终的执行效果如下:


有关于 Sysdig 的更多信息可以访问其 wiki 进行获取,另外,Sysdig 团队推出了一个专门用于安全监控的工具 Falco ,Falco 在 Sysdig 的基础上抽象出了可读性更高的检测规则,并支持在容器内部署,同样,大家如果感兴趣可以访问其 wiki 获取更多信息。

使用条件

  • 可以安装内核模块。
  • 需针对不同 Linux 发行版和内核版本进行定制。

优缺点

优点

  • 高定制化,从系统调用层面获取完整信息。

缺点

  • 开发难度大。
  • 兼容性差,需针对不同发行版和内核版本进行定制和测试。


0x06 总结

本文共讲了4种常见的监控进程创建的方法,这些方法本质上是对库函数或系统调用的监控,各有优劣,这里我再各用一句话总结一下:

  • So preload :Hook 库函数,不与内核交互,轻量但易被绕过。
  • Netlink Connector :从内核获取数据,监控系统调用,轻量,仅能直接获取 pid ,其他信息需要通过读取 /proc/<pid>/来补全。
  • Audit :从内核获取数据,监控系统调用,功能多,不只监控进程创建,获取的信息相对全面。
  • Syscall hook :从内核获取数据,监控系统调用,最接近实际系统调用,定制度高,兼容性差。

对我个人来讲,单纯地看监控进程创建这方面,我还是更推荐使用 Netlink Connector 的方式,这种方式在保证从内核获取数据的前提下又足够轻量,方便进行定制化开发。如果是想要进行全方面的监控包括进程、网络和文件,Audit 是一个不错的选择。

另外本文是以 Demo 的形式对功能进行介绍,主要是想起到一个抛砖引玉的作用,至于各方法的稳定性并没有进行充分地测试,如果各位有这方面的测试数据欢迎在这里和大家分享讨论。


0x07 参考

82dK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1j5@1K9r3!0#2i4K6u0W2N6$3W2F1i4K6u0r3N6$3!0J5k6s2m8J5k6i4y4K6i4K6u0r3i4K6y4r3M7q4)9K6c8o6t1&6y4e0R3$3

ce2K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1k6h3y4Z5i4K6u0W2L8h3g2A6N6s2g2S2L8W2)9J5k6h3y4G2L8g2)9J5c8U0t1H3x3e0W2Q4x3V1j5H3x3g2)9J5c8U0p5%4i4K6u0r3k6r3W2K6N6s2u0A6j5Y4g2@1k6h3c8Q4x3X3c8Z5K9h3c8K6i4K6u0V1j5$3I4#2M7%4c8W2M7W2)9J5k6r3q4J5j5$3S2A6N6r3g2U0N6s2g2J5k6g2)9J5k6r3c8W2M7$3W2Y4L8W2)9J5k6h3S2@1L8h3H3`.

e8cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2A6j5X3#2Q4x3X3g2U0L8$3#2Q4x3V1k6V1k6i4k6W2L8r3!0H3k6i4u0%4L8%4u0C8M7#2)9J5c8X3y4F1i4K6u0r3L8r3W2F1N6i4S2Q4x3V1k6D9i4K6u0V1L8r3!0Q4x3X3c8#2M7$3g2Q4x3X3c8K6M7r3q4U0k6g2)9J5k6r3q4#2k6r3W2@1i4K6u0V1N6r3!0G2L8q4)9J5c8X3W2F1k6r3g2^5i4K6u0W2K9s2c8E0L8l9`.`.

c76K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6D9K9h3&6#2P5q4)9J5k6r3q4#2k6r3W2@1i4K6u0W2j5$3!0E0i4K6u0r3j5$3!0F1k6X3W2Y4N6i4u0A6L8X3N6Q4x3X3c8S2L8X3c8Q4x3X3c8S2N6h3c8A6N6r3W2F1k6#2)9J5k6r3I4A6L8Y4g2^5i4K6u0V1M7%4W2K6N6r3g2E0M7#2)9J5k6s2N6A6N6r3S2Q4x3X3c8S2N6h3c8A6N6q4)9J5k6r3c8S2k6h3#2G2L8W2)9J5c8R3`.`.

766K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0P5g2)9J5k6h3!0K6j5$3S2A6L8X3q4Q4x3X3g2F1k6i4c8Q4x3V1k6E0j5h3y4%4k6g2)9J5c8X3u0D9L8$3N6Q4x3V1j5$3x3o6x3#2z5o6x3`.

0b8K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9J5c8X3&6@1c8e0g2r3e0V1@1^5g2h3q4j5f1f1k6o6y4h3H3@1K9f1E0g2g2i4M7`.

93cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6E0M7q4)9J5k6i4N6W2K9i4S2A6L8W2)9J5k6i4q4I4i4K6u0W2j5$3!0E0i4K6u0r3M7#2)9K6c8W2)9#2k6W2)9#2k6X3u0A6P5W2)9K6c8p5#2*7g2i4A6a6c8q4p5H3e0@1c8C8P5f1&6m8i4K6y4p5i4K6y4p5i4K6t1$3j5h3#2H3i4K6y4n7L8h3W2V1i4K6y4p5x3U0t1@1y4K6b7^5x3K6R3#2y4q4)9J5y4X3q4E0M7q4)9K6b7X3W2V1P5q4)9K6c8o6u0Q4x3U0k6S2L8i4m8Q4x3@1u0K6L8W2)9K6c8o6R3I4y4e0R3^5x3$3t1H3x3X3q4T1x3o6l9H3x3o6V1#2y4U0V1#2z5h3j5%4z5r3x3K6k6U0x3I4k6e0u0T1i4K6t1$3j5h3#2H3i4K6y4n7M7$3y4W2L8X3g2Q4x3@1b7J5x3b7`.`.

fb7K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6V1M7X3q4A6L8%4y4Q4x3V1k6K6P5i4y4V1K9h3M7`.

8b6K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3j5h3I4U0L8%4y4W2j5%4g2J5K9i4c8&6i4K6u0r3k6X3q4D9j5$3)9`.




声明:该文观点仅代表作者本人,转载请注明来自看雪