尝试TCP重置攻击时学到的东西

290 阅读7分钟

上周我读了Robert Heaton的一篇关于TCP重置攻击的精彩博文。我想这是一个很好的练习,尝试让作者的攻击代码在Linux上运行!在这个过程中,我学到了很多关于TCP和如何调试计算机网络的知识。在这个过程中,我学到了很多关于TCP和如何调试计算机网络的知识。 在这篇文章中,我高屋建瓴地介绍了什么是TCP复位攻击,并讲述了我如何让攻击代码在Linux上工作的故事。

什么是TCP复位攻击?

如果想更全面地了解什么是TCP重置攻击,我强烈建议你阅读Robert的博文,但在这里我给出一个高层次的概述。

关于TCP的一些背景

TCP是一个网络协议,用于互联网上的双方可靠地交换信息。 在A和B之间的任何连接中,如果A向B发送一个数据包,B将发送一个 "确认 "数据包,表明B收到该数据包。如果A没有看到B对该数据包的确认,按照TCP协议的规则,A将重新发送该数据,直到它看到确认。

关于TCP的一个重要细节是,所有数据包都有与之相关的有序的序列号。发送方发送的第一个数据包是一个随机的初始序列号,随后的每个数据包将有一个更高的序列号。当接收方确认数据包时,他们会发回一个确认号码,表明他们从发送方收到的最高序列号是什么。

理解这个问题的最好方法是使用一个叫做Wireshark的工具实际查看TCP数据包。

我们首先使用nc 程序来启动一个TCP服务器和客户端。

我们从客户端向服务器发送字符串 "hello"。对于这个交换,我们得到以下数据包(注意 "hello "是6字节,因为有换行符)。

TCP协议的另一个重要方面是它支持在TCP数据包上有不同的标志,其中之一是 "复位 "标志("RST")。 这个标志背后的想法是,如果TCP连接中的一方收到另一方的TCP复位数据包,它将立即关闭连接。这旨在用于计算机收到一个它不认识的TCP数据包的情况下--在这种情况下,计算机可以发回一个RST数据包。如果一台计算机在TCP连接仍然开放的情况下关机,而当它重新启动时收到了用于该TCP连接的数据包,就可能发生这种情况。

现在,攻击开始了!

好了,我们知道A和B两方可以各自发送设置了复位标志的数据包。然而,事实证明,如果你倾听网络上正在发生的流量,攻击者C可以发送一个 "假装 "是B的数据包给A,并设置RST标志。然后,A将关闭其连接。这样,攻击者就造成了连接的终止。

关于这种攻击的一个重要细节是,根据TCP规范,为了使TCP RST数据包被接受,RST数据包的序列号必须与RST数据包的接收者所期望的相同

假设A向B发送了一个序列号为10,确认号为12的单一数据包,其中包含5个字节的数据。 它将期望从B收到一个序列号为12,确认号为15(10+5)的确认数据包。

B可以发回我们刚才描述的那个数据包,或者B发送一个序列号为12的RST数据包也是有效的。 对于第三方C来说,要使连接失效,它必须向A发送一个数据包,假装是来自B,序列号为12。这个序列号要求是一个安全特征,因为攻击者必须能够准确地发送其中一方收到的序列号,如果有大量的数据被交换,这可能是困难的(但仍然可以做到)。

TLS实际上加密了什么?

当我读到这个攻击时,我的第一个问题是--好吧,TLS(加密的TCP,用于HTTPS连接)不是应该防止攻击者 "欺骗 "数据包或从事像这样的中间人攻击吗?

经进一步检查,答案是TCP头数据,如源端口和目的地的信息,是可以看到的。请看这个Wireshark对TLS连接数据的查看。

在你打开通过TLS发送的数据包的实际负载之前,没有办法验证发送者是否是它所声称的人。任何人都可以发送一个设置了源IP/端口的TCP数据包,如果不看TLS连接中数据包的内容,就没有办法验证是否是这样。

这实际上对互联网的运作很重要,因为路由器使用端口/IP地址的知识来正常工作(你的WiFi路由器可能使用NAT)。

现在,由于TCP重置攻击发生在TCP头数据层面,数据包的发件人没有办法被验证。因此,TCP重置攻击可以被执行,甚至通过TLS连接。

调试攻击代码

现在,回到文章开头的前提,在我一开始提到的那篇博文中,有一些攻击代码,实际上是在执行TCP攻击。我想,如果能让它在Linux上工作,将是一个很好的练习

设备 "名称

脚本使用scapy库来嗅探数据包,并在客户端向服务器发送数据包的情况下,向客户端发送一个带有RST标志的欺骗性TCP数据包。

我运行了这个脚本:

$ sudo venv/bin/python main.py 

并立即出现了错误:

OSError: [Errno 19] No such device

在谷歌上快速搜索后,我找到了这个Stackoverflow页面--原来Linux和MacOS对回环(localhost)设备的命名是不同的。在Linux上,该设备被命名为lo ,而在MacOS上,默认情况下,它是lo0

在脚本中改变了这一点,就立即解决了这个错误。

脚本似乎起作用了,但连接仍然是开放的

好吧,那么现在,用netcat会话打开,如下所示。

在一个单独的窗口中,我运行了攻击脚本:

 $ sudo venv/bin/python main.py
Starting sniff...

在通过netcat发送了另一条信息后,攻击脚本声称截获了数据包并发送了一个RST数据包!

 $ sudo venv/bin/python main.py
Starting sniff...
...
Grabbed packet src_ip=127.0.0.1 dst_ip=127.0.0.1 src_port=33362 dst_port=8000 seq=1967401732 ack=1844274764
jitter == 0, this RST packet should close the connection

然而,TCP连接仍然是开放的!

让我们再看一下Wireshark

在这一点上,有很多事情都可能出错。 在数据包层面,有可能脚本实际上并没有发送数据包。也许数据包被错误地配置了?也许Linux和MacOS有处理RST数据包的不同实现方式。

虽然最后一个假设在不做大量研究的情况下很难测试,但有了我们方便的朋友Wireshark,我们实际上可以看一下我们得到的数据包

因此,我再次运行了嗅探脚本,数据包确实在Wireshark中显示出来了!

因此,看起来确实有一个数据包正在发送,序列号似乎是正确的,而且端口似乎也是正确的!那么,这里发生了什么?

有一件小事你会注意到,RST包的窗口大小与我们在Wireshark转储中看到的其他TCP包不同。

窗口大小是否重要?

接下来我尝试改变窗口大小,使之与其他数据包一致。

没有效果。

尝试一个新的工具

看起来这个数据包的配置是正确的。那么这里发生了什么? 我们已经排除了脚本没有发送数据包,或者数据包配置错误的假设。但是,如果MacOS和Linux处理这个标志的方式不同呢?

这里的下一步是试图找到一种不同的方法来构建和发送数据包。如果我们能用不同的方法使这种攻击奏效,我们就能排除RST数据包在MacOS或Linux中工作方式不同的事实。

我阅读了一些关于向客户端发送欺骗性RST数据包的其他方法,发现了这个叫做netwox的方便工具,可以用来伪造数据包。这个演示有一个很好的TCP攻击的例子。

于是,我在安装了netwox 这个工具后,通过运行:

$  sudo netwox 40 -l 127.0.0.1 -m 127.0.0.1 -o 8000 -p 33760 -B -q 3545181336

其中33760是客户端的端口号,3545181336是正确的序列号。 看,它起作用了!连接关闭了。连接关闭了!

发现这些数据包之间的区别!

好了,我们有一个工作数据包的例子,和一个 "不工作 "数据包的例子。让我们看看你是否能发现其中的区别!

这很微妙。事实证明,这些数据包上的以太网目标地址是不同的。

所以,在这一点上,我们知道MacOS和Linux在处理TCP中的RST标志时没有区别。然而,scapynetwox 对数据包进行了不同的配置,这样目的地MAC地址就是scapy 上的 "广播 "地址,00:00:00:00netwox

在这一点上,我终于决定看一下scapy 文档(也许应该早点这样做),结果发现在故障排除部分,他们有一节就是关于这个的。从文档中,他们讨论了 "环回 "接口与其他网络接口的不同之处,以及在环回接口上发送的链路级数据包如何实际上不被分解/组装(因此被应用程序读取)。

scapy 提供的解决方案是在你的文件中加入这行代码conf.L3socket=L3RawSocket 。我试了一下,TCP重置攻击居然成功了

这个套接字设置是怎么回事?

这里究竟发生了什么,为什么scapy 所建议的改变会奏效?答案就在socket 系统调用的细节中。注意,在这一页中,它提到套接字可以监听不同的 "域",或 "协议族"。默认情况下,scapy 在打开套接字发送数据包时,使用PF_PACKET 协议族。这是一个链路层(以太网)协议,这就是为什么通过scapy 发送的数据包默认将以太网广播地址(ff:ff:ff:ff )作为目标。然而,这些数据包,作为链路层的数据包,当寻址到回环地址时,不会被正确地路由到那里,即使它们在wireshark中显示出来,因为Linux中回环接口的工作方式。

使用PF_INET 协议系列,数据包确实能够到达监听环回接口的应用程序,因为这些数据包是网络层数据包,确实被操作系统适当地路由到监听环回接口的应用程序。

总结

虽然我可能应该早点深入了解scapy ,但通过这个调试TCP重置攻击不工作练习,真的很有帮助,让我学到了很多关于计算机网络和如何调试它们的知识