原文连接:https://fuckcloudnative.io/posts/deploy-k3s-cross-public-cloud/html
TCP 重置攻击 是使用一个单一的数据包来执行的,只有几个字节大小。攻击者制做并发送一个伪造的 TCP 重置包来干扰用户和网站的链接,欺骗通讯双方终止 TCP
链接。咱们伟大的 xx 长城便运用了这个技术来进行 TCP 关键字阻断。python
理解 TCP 重置攻击并不须要具有深厚的网络知识功底,只须要一台笔记本就能够对本身进行模拟攻击。本文将会带你了解 TCP 重置攻击的原理,同时会帮助你理解不少关于 TCP 协议的特性。本文主要内容:linux
Python
脚原本模拟攻击下面开始分析 TCP 重置攻击原理。git
这一段略过,缘由你懂得,感兴趣的请直接看原文。github
在 TCP 重置攻击中,攻击者经过向通讯的一方或双方发送伪造的消息,告诉它们当即断开链接,从而使通讯双方链接中断。正常状况下,若是客户端收发现到达的报文段对于相关链接而言是不正确的,TCP 就会发送一个重置报文段,从而致使 TCP 链接的快速拆卸。bash
TCP 重置攻击利用这一机制,经过向通讯方发送伪造的重置报文段,欺骗通讯双方提早关闭 TCP 链接。若是伪造的重置报文段彻底逼真,接收者就会认为它有效,并关闭 TCP 链接,防止链接被用来进一步交换信息。服务端能够建立一个新的 TCP 链接来恢复通讯,但仍然可能会被攻击者重置链接。万幸的是,攻击者须要必定的时间来组装和发送伪造的报文,因此通常状况下这种攻击只对长链接有杀伤力,对于短链接而言,你还没攻击呢,人家已经完成了信息交换。服务器
从某种意义上来讲,伪造 TCP 报文段是很容易的,由于 TCP/IP 都没有任何内置的方法来验证服务端的身份。有些特殊的 IP 扩展协议(例如 IPSec
)确实能够验证身份,但并无被普遍使用。客户端只能接收报文段,并在可能的状况下使用更高级别的协议(如 TLS
)来验证服务端的身份。但这个方法对 TCP 重置包并不适用,由于 TCP 重置包是 TCP 协议自己的一部分,没法使用更高级别的协议进行验证。网络
尽管伪造 TCP 报文段很容易,但伪造正确的 TCP 重置报文段并完成攻击却并不容易。为了理解这项工做的难度,咱们须要先了解一下 TCP 协议的工做原理。并发
TCP 协议的目标是向客户端发送一份完整的数据副本。例如,若是个人服务器经过 TCP 链接向你的计算机发送个人网站的 HTML
,你的计算机的 TCP 协议栈应该可以以我发送的形式和顺序输出 HTML
。tcp
然而现实生活中个人 HTML 内容并非按顺序发送的,它被分解成许多小块(称为 TCP 分组),每一个小块在网络上被单独发送,并被从新组合成原来发送的顺序。这种从新组合后的输出被称为 TCP 字节流。
将分组重建成字节流并不简单,由于网络是不可靠的。TCP分组可能会被丢弃,可能不按发送的顺序到达客户端,也可能会被重复发送、报文损坏等等。所以,TCP 协议的职责是在不可靠的网络上提供可靠的通讯。TCP 经过要求链接双方保持密切联系,持续报告它们接收到了哪些数据来实现可靠通讯,这样服务端就可以推断出客户端还没有接收到的数据,并从新发送丢失的数据。
为了进一步理解这个过程,咱们须要了解服务端和客户端是如何使用序列号(sequence numbers)来标记和跟踪数据的。
TCP 协议的通讯双方, 都必须维护一个序列号(sequence numbers),对于客户端来讲,它会使用服务端的序列号来将接收到的数据按照发送的顺序排列。
当通讯双方创建 TCP 链接时,客户端与服务端都会向对方发送一个随机的初始序列号,这个序列号标识了其发送数据流的第一个字节。TCP 报文段包含了 TCP 头部,它是附加在报文段开头的元数据,序列号就包含在 TCP 头部中。因为 TCP 链接是双向的,双方均可以发送数据,因此 TCP 链接的双方既是发送方也是接收方,每一方都必须分配和管理本身的序列号。
当接收方收到一个 TCP 报文段时,它会向发送方返回一个 ACK
应答报文(同时将 TCP 头部的 ACK
标志位置 1),这个 ACK
号就表示接收方指望从发送方收到的下一个字节的序列号。发送方利用这个信息来推断接收方已经成功接收到了序列号为 ACK
以前的全部字节。
TCP 头部格式以下图所示:
一个确认应答报文的 TCP 头部必须包含两个部分:
TCP 总共有 6
个标志位,下文就会讲到其中的 RST
标志位。
TCP 头部包含了多个选项,其中有一个选择确认选项(
SACK
),若是使用该选项,那么当接收方收到了某个范围内的字节而不是连续的字节时,就会发送SACK
告知对方。例如,只收到了字节1000~3000
和4000~5000
,但没有收到3001~3999
。为了简单起见,下文讨论 TCP 重置攻击时将忽略选择确认选项。
若是发送方发送了报文后在一段时间内没有收到 ACK
,就认为报文丢失了,并从新发送报文,用相同的序列号标记。这就意味着,若是接收方收到了重复的报文,可使用序列号来判断是否见过这个报文,若是见过则直接丢弃。网络环境是错综复杂的,每每并非如咱们指望的同样,先发送的数据包,就先到达目标主机,反而它很骚,可能会因为网络拥堵等乱七八糟的缘由,会使得旧的数据包,先到达目标主机。通常分两种状况:
这两种状况对发送方来讲实际上是同样的,发送方并不能区分是哪一种状况,因此只能从新发送数据包。
只要不频繁重复发送数据,额外的开销基本能够忽略。
构建伪造的重置包时须要选择一个序列号。接收方能够接收序列号不按顺序排列的报文段,但这种容忍是有限度的,若是报文段的序列号与它指望的相差甚远,就会被直接丢弃。
所以,一个成功的 TCP 重置攻击须要构建一个可信的序列号。但什么才是可信的序列号呢?对于大多数报文段(除了重置包,即 RST
包)来讲,序列号是由接收方的接收窗口大小决定的。
想象一下,将一台上世纪 90
年代初的古老计算机,链接到现代千兆光纤网络。闪电般快速的网络能够以使人瞠目结舌的速度向这台古老的计算机传送数据,速度远远超过该计算机的处理能力。但并无什么卵用,由于只有接收方接收并处理了报文,才能认为这个报文已经被收到了。
TCP 协议栈有一个缓冲区,新到达的数据被放到缓冲区中等待处理。但缓冲区的大小是有限的,若是接收方的处理速度跟不上发送方的发送速度,缓冲区就会被填满。一旦缓冲区被填满,多余的数据就会被直接丢弃,也不会返回 ACK。所以一旦接收方的缓冲区有了空位,发送方必须从新发送数据。也就是说,若是接收方的处理速度跟不上,发送方的发送速度再快也没用。
缓冲区到底有多大?发送方如何才能知道何时能够一次发送更多的数据,何时该一次发送不多的数据?这就要靠 TCP 滑动窗口了。接收方的滑动窗口大小是指发送方无需等待确认应答,能够持续发送数据的最大值。 假设接收方的通告窗口大小为 100,000
字节,那么发送方能够无需等待确认应答,持续发送 100,000
个字节。再假设当发送方发送第 100,000
个字节时,接收方已经发送了前 10,000
个字节的 ACK,这就意味着窗口中还有 90,000
个字节未被确认,发送方还能够再持续发送 10,000
个字节。若是发送了 10,000
个字节的过程当中没有收到任何的 ACK
,那么接收方的滑动窗口将被填满,发送方将中止发送新数据(能够继续发送以前丢失的数据),直到收到相关的 ACK
才能够继续发送。
TCP 链接双方会在创建链接的初始握手阶段通告对方本身窗口的大小,后续还能够动态调整。TCP 缓冲区大的服务器可能会声明一个大窗口,以便最大限度提升吞吐量。TCP 缓冲区小的服务器可能会被迫声明一个小窗口,这样作会牺牲必定的吞吐量,但为了防止接收方的 TCP 缓冲区溢出,仍是颇有必要的。
换个角度来看,TCP 滑动窗口大小是对网络中可能存在的未确认数据量的硬性限制。咱们能够用它来计算发送方在某一特定时间内可能发送的最大序列号(max_seq_no
):
max_seq_no = max_acked_seq_no + window_size
其中 max_acked_seq_no
是接收方发送的最大 ACK 号,它表示发送方知道接收方已经成功接收的最大序列号。window_size 是窗口大小,它表示容许发送方最多发送的未被确认的字节。因此发送方能够发送的最大序列号是:max_acked_seq_no + window_size
。
TCP 规范规定,接收方应该忽略任何序列号在接收窗口以外的数据。例如,若是接收方确认了全部序列号在 15,000
如下的字节,且接收窗口大小为 30,000
,那么接下来接收方只能接收序列号范围在 15,000 ~ 45,000
之间的数据。若是一个报文段的部分数据在窗口内,另外一部分数据在窗口外,那么窗口内的数据将被接收确认,窗口外的数据将被丢弃。注意:这里忽略了选择确认选项,再强调一遍!
对于大多数 TCP 报文段来讲,滑动窗口的规则告诉了发送方本身能够接收的序列号范围。但对于重置报文来讲,序列号的限制更加严格,这是为了抵御一种攻击叫作盲目 TCP 重置攻击(blind TCP reset attack
),下文将会解释。
对于 TCP 重置报文段来讲,接收方对序列号的要求更加严格,只有当其序列号正好等于下一个预期的序列号时才能接收。继续搬出上面的例子,接收方发送了一个确认应答,ACK 号为 15,000
。若是接下来收到了一个重置报文,那么其序列号必须是 15,000
才能被接收。
若是重置报文的序列号超出了接收窗口范围,接收方就会直接忽略该报文;若是其序列号在接收窗口范围内,那么接收方就会返回一个 challenge ACK
,告诉发送方重置报文段的序列号是错误的,并告之正确的序列号,发送方能够利用 challenge ACK
中的信息来从新构建和发送重置报文。
其实在 2010 年以前,TCP 重置报文段和其余报文段的序列号限制规则同样,但没法抵御盲目 TCP 重置攻击,后来才采起这些措施施加额外的限制。
若是攻击者可以截获通讯双方正在交换的信息,攻击者就能读取其数据包上的序列号和确认应答号,并利用这些信息得出假装的 TCP 重置报文段的序列号。相反,若是没法截获通讯双方的信息,就没法肯定重置报文段的序列号,但仍然能够批量发出尽量多不一样序列号的重置报文,以指望猜对其中一个序列号。这就是所谓的盲目 TCP 重置攻击(blind TCP reset attack
)。
在 2010 年以前 TCP 的原始版本中,攻击者只须要猜对接收窗口内的随便哪个序列号便可,通常只需发送几万个报文段就能成功。采起额外限制的措施后,攻击者须要发送数以百万计的报文段才有可能猜对序列号,这几乎是很难成功的。更多细节请参考 RFC-5963。
如下实验是在
OSX
系统中完成的,其余系统请自行测试。
如今来总结一下伪造一个 TCP 重置报文要作哪些事情:
ACK
标志位置位 1 的报文段,并读取其 ACK
号。RST
标志位置为 1),其序列号等于上面截获的报文的 ACK
号。这只是理想状况下的方案,假设信息交换的速度不是很快。大多数状况下为了增长成功率,能够连续发送序列号不一样的重置报文。为了实验简单,咱们可使用本地计算机经过 localhost
与本身通讯,而后对本身进行 TCP 重置攻击。须要如下几个步骤:
下面正式开始实验。
可使用 netcat 工具来创建 TCP 链接,这个工不少操做系统都预装了。打开第一个终端窗口,运行如下命令:
$ nc -nvl 8000
这个命令会启动一个 TCP 服务,监听端口为 8000
。接着再打开第二个终端窗口,运行如下命令:
$ nc 127.0.0.1 8000
该命令会尝试与上面的服务创建链接,在其中一个窗口输入一些字符,就会经过 TCP 链接发送给另外一个窗口并打印出来。
编写一个攻击程序,使用 Python 网络库 scapy
来读取两个终端窗口之间交换的数据,并将其打印到终端上。完整的代码参考个人 GitHub 仓库,代码的核心是调用 scapy
的嗅探方法:
t = sniff( iface='lo0', lfilter=is_packet_tcp_client_to_server(localhost_ip, localhost_server_port, localhost_ip), prn=log_packet, count=50)
这段代码告诉 scapy
在 lo0
网络接口上嗅探数据包,并记录全部 TCP 链接的详细信息。
lo0
(localhost)网络接口上进行监听。localhost
,且端口号为 8000
)的数据包。lfilter
规则的数据包。上面的例子只是将数据包打印到终端,下文将会修改函数来伪造重置报文。下面开始修改程序,发送伪造的 TCP 重置报文来进行 TCP 重置攻击。根据上面的解读,只须要修改 prn 函数就好了,让其检查数据包,提取必要参数,并利用这些参数来伪造 TCP 重置报文并发送。
例如,假设该程序截获了一个从(src_ip
, src_port
)发往 (dst_ip
, dst_port
)的报文段,该报文段的 ACK 标志位已置为 1,ACK 号为 100,000
。攻击程序接下来要作的是:
IP/Port
应该是截获数据包的目的 IP/Port
,反之亦然。RST
标志位置为 1,以表示这是一个重置报文。scapy
的 send
方法,将伪造的数据包发送给截获数据包的发送方。对于个人程序而言,只需将这一行取消注释,并注释这一行的上面一行,就能够全面攻击了。按照步骤 1 的方法设置 TCP 链接,打开第三个窗口运行攻击程序,而后在 TCP 链接的其中一个终端输入一些字符串,你会发现 TCP 链接被中断了!
ACK
号彻底相同。Wireshark
,监听 lo0 网络接口,并使用过滤器 ip.src == 127.0.0.1 && ip.dst == 127.0.0.1 && tcp.port == 8000
来过滤无关数据。你能够看到 TCP 链接的全部细节。总的来讲,TCP 重置攻击既深奥又简单,祝你实验顺利。
Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12离线安装包发布地址http://store.lameleg.com ,欢迎体验。 使用了最新的sealos v3.3.6版本。 做了主机名解析配置优化,lvscare 挂载/lib/module解决开机启动ipvs加载问题, 修复lvscare社区netlink与3.10内核不兼容问题,sealos生成百年证书等特性。更多特性 https://github.com/fanux/sealos 。欢迎扫描下方的二维码加入钉钉群 ,钉钉群已经集成sealos的机器人实时能够看到sealos的动态。