当前护网蓝军主动防御工具越来越强,其他隧道如DNS、ICMP等因特征明显都有比较有效的检测防范方法,HTTP隧道因为是正常业务通道、数据比较难甄别而成为隐藏流量的首选,内存马已经成为常规武器。
在获得ROOT权限后,干掉主动防御软件可能不会那么容易,因为它可能并不是孤立而是分布式的、彼此间有联系,粗暴的直接停掉或杀掉防御进程会导致其他主机告警。因此,在此场景下想要持久化ROOT权限,内核远控的存在是有必要的。
内核ROOKIT常用LKMD方式实现,多数主动防御工具都不具备内核模块的检测能力,而模块为防止被lsmod查看到,可使用“断链法”隐藏。HTTP服务是基于TCP协议的,我们可以使用某种特定的HTTP请求激活下发命令,然后执行结果会在该请求的响应中带出。比如设计如下交互,先看请求:
GET / HTTP/1.1
将HTTP头中的cookie前面的UUID作为关键字,后跟远控命令的base64编码。内核远控在接收含有此关键字的TCP报文后(有效载荷大于0,即非SYN、SYN-ACK、ACK等握手应答包),解析并执行远控命令并在该HTTP响应(同样是TCP报文)的HTTP头中插入响应数据:
EagleEye-TraceId: hello rootkit
Netfilter是Linux内核中的一个框架,它提供一个标准的接口,通过该接口能够方便的进行不同的网络操作,包括包过滤、网络地址转换和端口转换。Netfilter在内核中提供一组钩子hooks,通过这些hooks,内核模块可以向TCP/IP协议栈注册回调函数。我们可以基于netfilter实现上文所述的逻辑功能:
static struct nf_hook_ops _prehook, _posthook;
上述代码逻辑清楚很容易理解,在模块装载时在网络层注册勾子,卸载时解除勾子,watch_in处理输入报文,相应的watch_out处理输出报文。
static unsigned int watch_in(unsigned int hooknum,
解析TCP载荷的过程中,要剥掉IP头和TCP头,注意skb一定要先线性化,否则报文内存是不连续的,不能按照指针加偏移量的方式访问。
如何查找HTTP请求对应的HTTP响应报文?TCP链路,可以通过源端口和目的端口这个二元组一一对应。在watch_in中记下该HTTP请求的端口信息,再在watch_out中进行匹配查找,找到后注入自定义内容。
static unsigned int watch_out(unsigned int hooknum,
经实验,修改TCP报文的操作会有一些耗时,大概几百毫秒。
本文提供一种内核远控的实现思路,至于在内核态能用来做什么可根据需求实现,如果想要回显(即修改HTTP响应、TCP回包)就不能执行IO等耗时操作。
完整代码可参考DEMO项目,该项目实现了无回显异步执行用户态shell功能
https://github.com/bigBestWay/cayenne