首先,我为什么要把这个开源?
MITRE ATT&CK 只提到被盗的或自签名的证书,而 NDR(据我所知)很少关注 x509 证书的内容,除了颁发 CA 是谁之外。一般来说,x509 证书是被信任的,并且可以毫无阻碍地穿过我们的防火墙。但本质上,它们只是文件,可以像其他任何文件一样轻松包含恶意负载。我们信任并忽略它们,因为它们是加密过程的核心组成部分,而我们已对这种加密过程习以为常。这个项目的主要目标是提高人们对一类我们已然信任的安全指标的认识,并突出展示可用于检测其恶意使用的方法。
我一直想知道威胁行为者是否曾经将 x509 证书用作其 C2 通信的一部分,不是用来加密网络流量,而是真正把 C2 通信嵌入到 x509 证书中。在野外寻找类似的东西 5 年之后,我终于决定自己把它写出来,看看是否可行……事实证明是可行的。
通过 HTTPS/TLS 发送的每一条加密消息都依赖 x509 证书的传输来实现。在建立 TLS 握手(下图)时,在第四步中服务器会将其 x509 证书发送给客户端。客户端验证证书,比较服务器支持的加密算法,并选择用于后续所有通信的算法。

正如此图所示,这只是 x509 证书从服务器到客户端的单向传输。这不太适合 C2 通信,因为客户端无法向服务器回复。充其量,它只能被用作单向数据传输机制(见下方“先前工作”部分)。
但还有另一种类型的 TLS 会话,称为双向 TLS 认证(mTLS),其中客户端和服务器都会交换 x509 证书,以此作为彼此认证的方式。

如上图所示,在双向认证过程中,服务器的 x509 证书会被发送给客户端进行认证,然后客户端的 x509 证书会被发送给服务器进行认证。这种工件交换代表了一个为 C2 服务器创建双向通信信道的机会。
由于服务器和客户端证书是由底层 SSL 库交换的,客户端没有机会在单个 mTLS 连接中从服务器证书中取出消息、运行命令并生成响应证书。这意味着 C2 信道的设计需要让请求-应答交换通过两个不同的双向 TLS 连接进行,有点像伪半双工传输模式。

请求/响应过程遵循以下步骤:
在我把这个跑通之后,我相当自豪,觉得自己真是既富有创造力又很厉害。
然后我偶然看到了 Jason Reaves 在 2018 年 BSides 上的演讲,他用 x509 证书通过 TLS 编写了一个恶意软件二进制投递器。一年后,Jason 发表了一篇论文,详细描述了一种使用 mTLS 的完整双向通信信道。
mTLS 要求客户端和服务器的证书都由同一个 CA 证书签名,因此第一步是生成你自己的 CA 私钥/证书对。
创建根 CA 私钥:
openssl genrsa -des3 -out hmCA.key 2048
注意:口令短语可以防止任何获得你私钥的人用自己的方式生成根证书。
创建根 CA 证书:
openssl req -x509 -new -nodes -key hmCA.key -sha256 -days 1825 -out hmCA.pem
将生成的密钥和证书文件复制到 certs/ca_certs 文件夹中。该项目附带了一个演示用的密钥/证书对,如果你愿意,可以跳过这一步。
启动客户端:
python client.py
启动服务器:
python server.py
我绝不想发布可能具有恶意的东西,却不详细说明如何在网络日志中检测它。
你可能会认为检测这种类型的 TLS 模式很容易,但事实并非如此简单。这个 C2 信道的主要特征之一是其半双工通信风格:完成服务器与客户端之间的一次完整请求/应答需要两次双向认证流程。随后,随着服务器向客户端发送不同的命令,这种情况会多次发生。
这意味着你应该寻找:
这看起来像是一套稳操胜券的检测规则,但正如我前面所说,这并不容易。事实证明,有一组企业服务也具有类似的 mTLS 流量模式,包括:
其中几个似乎是资产/设备管理服务,因此理论上,它们在遍历所有设备时应该每次都发送相同的证书集。你可以观察是否有多组 mTLS 会话每 N 小时重复一次,然后查看两组 mTLS 会话之间的证书哈希是否匹配,或大部分匹配。此外,还可以留意客户端证书是否在每个 mTLS 会话中都不相同,而服务器证书在所有会话中都相同。
SSL 检查是潜在地阻止这种类型 C2 通信信道的一种方式,因为 SSL 检查服务器不会拥有对客户端证书进行认证所需的恶意 CA 证书。