如何使用 Cisco 3725 路由器在 GNS3 中运行 CAM 表溢出攻击?
好吧,您正在进入仿真和物理世界互连的空间。
首先,让我们介绍一下基础知识:3725 是一个路由器,它具有一些有限的交换能力,因为它可以(在现实世界中)使用交换模块,并且在 IOS 中需要交换代码。
当您编写“标准 GNS3 开关”时,我假设您指的是由 dynamips 模拟的 NM-16ESW 模块?如果是这样,那正是您在 3725 中使用的模块和代码。
对于任何安全类型的测试,包括 CAM 耗尽攻击甚至端口安全,我只会在真实环境中进行测试。由于多种原因,在运行时设置中模拟/解释并不总是提供相同(或可重复)的结果,并且它在任何有时间限制的功能中都是显而易见的,例如 QoS 和安全机制的某些部分(依赖于适当的时间和IOS 中事件触发的顺序)。
现在,回到你的问题:答案有两部分:
- 首先,在引入 NM-16ESW 时重新添加的用于管理“软件切换”IOS 代码的 CLI 输出的代码在产品生命周期中经历了大量更改。其中一项扩展是添加“背压”以在新地址泛滥时允许更快的 MAC 老化,当时的独立交换机(Catalyst 2950 和更高型号 - 2960、3560 和 3750)中也存在相同的代码。由于您使用的是全新的 IOS (12.4(15)T),因此您可能正在使用该功能。因此,交换机可能只是快速老化旧的 MAC,它没有看到任何进出的流量,并安装您正在泛洪的新条目 - 顺便说一句,您的泛洪速度有多快?
- 答案的另一部分是该命令已多次修复,因为它并不总是提供当前情况,而是从 ASIC 收集的一些较旧的缓存命令。
同样,在模拟环境中进行这种测试只会把它推得太远,我会回到一些硬件设置并对其进行测试/实验室以反映真实场景。即使你成功了,你以后也可能无法以可预测的方式重复它。
首先,我必须表明我在IT 安全StackExchange 网站上最活跃。由于当前的网站可能会覆盖不同的公众,我认为更明智的做法是,虽然我采用潜在攻击者的观点,但本文中的所有信息仅用于教育目的,特别是为了了解具体威胁正在影响超越神话和过于简单化话语的网络。
我不鼓励也不赞成在任何未经授权的网络上使用下面描述的方法(我的意思是:如果你想学习获取 GNS3,这就是整个线程的内容:)!)。
很抱歉这个答案的长度,但尽管我进行了研究,但我没有设法在网络上找到关于这个主题的任何令人满意的资源。大多数“概念验证”要么通过在 CAM 表被填充的步骤处停止并假设但从未真正展示过切换反应,要么通过使用一些人为的技巧,例如在泛洪之前清除切换 MAC 表而存在偏差。
我在这里的目标是提供适用于模拟和真实环境的具体步骤,重点关注与 GNS3 虚拟化和常见错误方法相关的问题,最重要的是提供足够的背景信息来理解为什么事情会这样。
简短的回答:是的,可以在 GNS3 中模拟 CAM 溢出攻击,但这有一些要求:
- 知道与真实齿轮的差异所在,
- 了解您真正可以期待什么,
- 使用正确的工具,
- 更正当前影响的错误
dynamips
(GNS3 后面的 Cisco 路由器模拟器)。
我现在将逐一讨论这些观点。
了解与真实齿轮的不同之处
出于性能原因,很多 switch 的东西实际上不是 IOS 代码的一部分,而是在硬件中实现的。这包括 ARL 或地址解析逻辑,它提供了在 MAC 地址表中添加、删除和查找条目的所有方法。
因此,为了让 NM-16ESW 模块在 GNS3 中工作,Dynamips 必须重新实现所有这些通常由硬件提供的服务,或者至少将其推得足够远,以允许未经修改的 IOS 在其上正确运行。
可悲的是,这确实是未完成的工作,如该模块的源代码标题中所述:
* NM-16ESW ethernet switch module (experimental!)
*
* It's an attempt of proof of concept, so not optimized at all at this time.
* Only L2 switching will be managed (no L3 at all).
*
* To do next: QoS features (CoS/DSCP handling).
所以你会被警告:正如 Łukasz 的回答中所述,忘记 QoS 并期待一些奇怪的事情。
希望在这里我们不是在处理 QoS,而是在处理 CAM 溢出,并且除了最后一个错误(我希望在未来的 GNS3 版本中应该包含更正)之外,还有两个主要的奇怪之处让我们关注:一个是影响MAC地址表大小和其他MAC地址老化过程。
第一个区别:MAC 地址表大小最高为 8189 个条目
这是您问题的主要主题,但实际上不是问题。
CAM 溢出攻击利用了交换机无法向其 CAM 表添加任何新条目的事实,因此回退到“表现得像集线器”(正如经常描述的那样,我稍后会回来讨论这一点)。
很可能是由于一个小错误,似乎 MAC 表在 8189 个条目而不是 8192 个条目处被认为已满。但是,完整仍然意味着已满:ARL 仍将无法存储任何补充条目,并且 CAM 溢出攻击仍然会成功.
第二个区别:aging-time
设置不兑现
默认情况下,MAC 条目应在 MAC 地址表中保留至少 5 分钟(=300 秒),如aging-time
设置所定义:
SW1#show mac-address-table aging-time
Mac address aging time 300
然而,在真实装备中,这个参数背后的整个过程是在硬件中实现的,而这个设置目前被 Dynamips 对 NM-16ESW 模块的实现简单地忽略了。
Dynamips 实现了自己的垃圾收集系统,该系统仅在 30 秒后删除旧的 MAC 条目,使 CAM 溢出攻击明显更加难以稳定(但可能是针对Łukasz 描述的“背压”功能的一个很好的训练)。
负责此操作的代码可以在dev_nm_16esw.c文件的第 2516 行附近找到:
/* Start the MAC address ager */
data->ager_tid = timer_create_entry(15000,FALSE,10,
(timer_proc)bcm5600_arl_ager,data);
这会bcm5600_arl_ager()
每 15 秒启动一次该功能。该函数的作用是扫描整个 CAM 表并检查与每个 MAC 地址关联的命中标志:
- 如果设置了标志,则取消设置它,
- 如果未设置该标志,则从表中删除 MAC 地址。
每当交换机从相应的 MAC 地址接收到新数据包时,就会重新启用此标志,将活动地址保留在表中。
你将不得不采取这种行为考虑在内,以设计一个成功的CAM溢出攻击:
- 仅使用随机 MAC 地址不会做到这一点(抱歉
macof
...),因为它会允许交换机每 30 秒刷新一次所有伪造的地址,从而使漏洞利用变得不稳定, - 每个 MAC 地址必须至少每 15 秒用作发送者一次,
- 实际上,由于负载增加可能导致的问题,为了避免单个数据包丢失或延迟到达,您希望每个 MAC 地址在 15 秒内使用两到三次。并且不要认为更多会有帮助,这应该足以使您的洪水既稳定又可靠,整个 LAN 上的所有交换机上的 CAM 表都一致且不断地填充。
了解您真正可以期待什么
正如介绍中所解释的,许多文献将这种攻击解释为“使交换机表现得像集线器”。虽然对外行来说是一个很好的概述,但从技术角度来看,这种过于简化的描述是错误的。
为了理解,我会回忆一下开关在正常情况下的工作原理,它们背后的算法是什么,以确保我们都在同一页面上:
- 交换机在某个端口接收传入的数据包,
- 然后交换机检查源 MAC 地址是否已存储在 MAC 地址表中。如果不是,并且有空闲插槽,它会记录这个与其传入端口相关联的新 MAC 地址(顺便说一下,如果该地址已经存在但与另一个端口相关联,它将使用新端口更新记录) . 这也是重置与此条目关联的老化计时器的机会,无论它是否是新条目。
- 然后交换机检查目标 MAC 地址是否已存储在 MAC 地址表中。如果是,那么这一切都很好,交换机在与匹配的 CAM 表条目关联的接口上输出数据包。如果不是,交换机将在除传入接口之外的所有接口上输出数据包(所有接口都属于同一 VLAN +中继端口,只要该 VLAN 未被修剪)。
现在,让我们看看当 CAM 溢出条件被触发并且他确实退回到所谓的“集线器”模式时,开关如何工作......实际上所有这些都是无稽之谈:没有集线器模式并且触发了 CAM 溢出严格没有。开关继续像往常一样工作:
- 对于传入的数据包,当且仅当源 MAC 地址不存在于表中时,CAM 溢出才会产生任何影响,因为交换机将没有空闲插槽来添加这个新的插槽,因此将跳过此步骤。如果地址已经存在于表中,交换机将照常重置其老化计时器。
- 对于传出数据包,当且仅当表中不存在目标 MAC 地址时,交换机才会确实通过其“所有”接口发送数据包。如果表中存在 MAC 地址,则交换机完全没有理由做出奇怪的行为:它会像往常一样继续并仅通过与 MAC 地址关联的端口发送数据包。
这样做的主要后果是:
- 尽管经常被告知,CAM 溢出攻击并不是将交换机变成集线器的神奇方式。您不会转发所有通过交换机的流量。
- 您将无法窃听任何已经处于活动状态的通信(即在 MAC 泛洪开始之前发起的任何通信)。交换机已经知道设备的 MAC 地址,合法数据包将定期重置交换机的老化计数器。无论您如何使用洪泛,这些设备的 MAC 地址都将保留在交换机的 CAM 表中,并且交换机只会将流量转发到适当的端口。
- 您将最有可能能够窃听只从路由器到先前非设备(关机或休眠模式,例如)单面通信。在实际场景中,至少在工作时间内,交换机的 CAM 表中几乎会永久保留路由器的 MAC 地址,因为网络上的几乎所有流量都将通过它,因此会刷新老化计时器。因此,MAC 泛洪的主要目标是防止以前不活动的设备也将其 MAC 地址成功注册到交换机上。举一个具体的结果示例,大多数情况下您将无法窃听用户的密码和请求,但您可能能够获得服务器提供的会话标识符和数据。
- 但以令人沮丧的消息结束,您将获得的是,如果您注意不要让交换机过载,它们会很高兴地将您的泛洪数据包从交换机转发到交换机,直到它们污染整个第 2 层 LAN。只有 VLAN 修剪或途中的第 3 层设备会限制这种传播,否则即使是仅提供不相关 VLAN 端口的交换机也会看到它们的 CAM 表被填满。换句话说,根据拓扑细节,从 VLAN 2 发起攻击可以让您访问从多台交换机转发的 VLAN 2 流量,还可以让您影响 VLAN 3 交换机的行为。
使用正确的工具
经典推荐用于 CAM 表溢出攻击的工具是macof
(来自dsniff项目,多年未维护)。然而,这个工具让我产生了一些幻想故事中的原始野蛮人的效果:野蛮、低效和不可靠。
该工具使用动态生成的完全随机 MAC 地址生成数据包。这是错误的,原因有二:
- 正如我们在上面看到的,每个不活动的 MAC 地址都会从 CAM 表中自动删除,暂时释放大量可用插槽来记录真正的 MAC 地址,直到我们设法再次填充表(如果目标是多个,这可能需要一些时间)关掉)。正如我们还看到的,一个真实的数据包足以用真实信息更新 CAM 表,并最终结束我们对这个特定目标的窃听。
统计上,随机生成的 MAC 中有一半设置了I/G 组位。但是,禁止使用组 MAC 地址作为发送方,如IEEE 802.3-2002, Section 3.2.3(b) 中所述:
在源地址字段中,第一位被保留并设置为 0。
Cisco 交换机(至少)意识到这一点,并将此类数据包视为格式错误并丢弃它们。这意味着它们生成的数据包中有一半
macof
被它们遇到的第一个交换机丢弃。
macof
它还依赖于一些暴力策略,在攻击者的设备和网络允许的情况下尽可能快地发送其恶意数据包。这会导致几个问题:
- 交换机在泛洪过程中可能会出现故障甚至崩溃(我遇到了几个报告说交换机的管理平面在泛洪过程中被冻结),
- 由于交换机端造成的负载,这些数据包可能无法可靠地从交换机到交换机中继,导致只有第一个面向攻击者的交换机的 CAM 表有效溢出,
- 由于攻击方的负载,网络链接完全拥塞或 CPU 使用率达到最大值。在所有情况下,不可能从同一设备捕获任何流量,这很可悲,因为捕获流量正是这次攻击的目标。通常的建议是在捕捉时停止泛洪,并定期在泛洪和捕捉之间交替(例如每分钟考虑真实齿轮的 5 分钟默认老化,而对于 Dynamips 的 30 秒,它变得毫无希望)。我还建议有足够的运气在交换有趣的信息时确实捕获,并有足够的运气能够正确地应对在这种情况下似乎非常不可行的周期性 MAC 表清理。
一个好的 CAM 溢出攻击工具应该:
- 不使用超过必要的资源以允许可靠的窃听,
- 生成格式良好的数据包(即,没有任何会被丢弃的无用数据包,也没有会使 Wireshark(或 IDS...)抱怨的数据包),
- 确保 CAM 表保持不断填充,以便新设备没有机会注册其 MAC 地址。
macof
未能满足这三个要求,因此不是合适的工具。快速搜索没有发现任何相关的替代方案,所以我选择了Scapy路线(Scapy 是一个 Python 库和交互式工具,允许自由构建和操作网络数据包)。
这是我用来在 GNS3 环境中成功测试 CAM 表溢出的代码:
#! /usr/bin/python
nbpkts = 8192
iface = "eth0"
import sys
from scapy.all import sendpfast, Ether, IP, RandIP, RandMAC, TCP
print("Initializing...")
# We first build all packets...
pkts = []
for i in xrange(0, nbpkts):
macaddr = str(RandMAC())
# Quick-and-dirty way to ensure that the I/G remains unset
macaddr = macaddr[:1] + "0" + macaddr[2:]
# This packet structure mimics a TCP SYN sent to a HTTP server.
# A random dst mac should also work, setting one fixed can be useful
# to easily filter-out flood-related packets when capturing traffic.
# You can use IPs valid for your range, but be cautious that if any
# host is made to send some RST for instance its MAC address will be
# registered by the switches.
pkts.append(Ether(src=macaddr, dst="ff:ff:ff:ff:ff:ff")/
IP(src=str(RandIP()), dst=str(RandIP()))/
TCP(dport=80, flags="S", options=[('Timestamp', (0, 0))]))
print("Launching attack, press Ctrl+C to stop...")
# ...and then we send them in loop.
while True:
# Adapt pps (Packets Per Second) to your needs. Running a complex
# GNS3 topology on a low-end machine will take all the CPU causing
# packet loss, pps will then need to be high to replay lost packets.
# Given enough CPU, packet loss can remain low and pps can be lowered
# too.
sendpfast(pkts, iface=iface, file_cache=True, pps=5000, loop=999)
这是一个快速而肮脏的例子,可以通过多种方式改进。例如,如果它用于真实齿轮,使用两个连续的发送迭代可能是有意义的,第一个快速以快速接管 CAM 表,第二个以慢得多的速度工作,充分利用5分钟的老化延迟尽量保持在雷达之下(这个默认的延迟改变的时候一般是调高不调低,而且我还有点怀疑有人不注意开启端口安全在他的开关上真的会打扰改变这种设置)。
更正当前影响 dynamips 的错误
可悲的是,当您完成所有这些后,您会发现当它们的 CAM 表被正确填充时,GNS3 中的交换机不会开始通过它们的“所有”端口泛洪数据包,而是会丢弃它们。
这是由于一个错误影响了bcm5600_handle_rx_pkt()
负责处理接收到的数据包的功能,位于dev_nm_16esw.c文件的第 2170 行附近:
/* Source MAC address learning */
if (!bcm5600_src_mac_learning(d,p))
return(FALSE);
目前,当 ARL 未能存储新的 MAC 地址时,传入的处理将中止,从而有效地导致数据包被丢弃。修复只是忽略 ARL 状态并继续处理数据包,因为这是真正的设备实际所做的:
/* Source MAC address learning */
bcm5600_src_mac_learning(d,p);
我已经向 GNS3 团队提出了这个问题,因此可以在 GNS3 未来的更新中修复它。我还提倡将 MAC 表垃圾收集超时从当前的 15 秒提高到 5 分钟,以更接近真实的齿轮行为。
在上游修复之前,它需要手动修改和重新编译 Dynamips 源代码,但这是一个非常快速和简单的过程(不需要重新编译整个 GNS3,只需要重新编译dynamips
二进制文件,我在链接的票证中提供了补丁多于)。
完成此操作后,您将能够使用基于路由器的交换机以稳定且可预测的方式在 GNS3 中测试和重复 MAC 溢出攻击。
最后附上两个注意事项:
虽然基于路由器的交换机允许测试 CAM 溢出攻击,但它们不允许测试适当的缓解技术,因为它们没有实现端口安全。我认为这是 IOS 而不是 GNS3 的限制,因为相关选项甚至在 shell 中都没有阻止。IOU提出了这些选项,但是由于其 CAM 表允许近 2 亿个条目(与真实 IOS 的 8192 个条目相比),传统 CAM 溢出攻击似乎无法实现。因此,IOU 与基于路由器的交换机相反:它们可用于测试缓解技术,但不能重现攻击。另请注意,生成树协议 (STP) 的 IOU 实现存在严重缺陷,必须避免拓扑循环。
说到 STP 并且取决于拓扑,成为 STP 根 (
yersinia stp -attack 4
) 应该会由于拓扑变化导致大多数 MAC 表动态条目的清除,并且可以为您提供更有效的泛洪和窃听体验 ;)。