当前位置: 首页 > 科技观察

先从TCP协议的原理说起第一次重置攻击

时间:2023-03-15 16:13:39 科技观察

在说RST攻击之前,首先要了解TCP:如何通过三次握手建立TCP连接,如何关闭一个全双工与四次握手的连接,以及滑动窗口的工作原理。RST在什么情况下出现在TCP的标志位中进行数据传输。下面我会画一些简化的图,把上面的几点表达清楚,然后我就明白RST攻击是怎么回事了。1.什么是TCP?TCP是IP网络层之上的传输层协议,用于提供端口到端口的面向连接的可靠字节流传输。我用母语解释一下上面的关键字:端口到端口:IP层只关心数据包从一个IP到另一个IP的传输。IP层之上的TCP层加上端口后,就是面向进程的。每个端口可以对应用户进程。可靠:TCP会负责维护实际上不存在的连接概念,包括接收包后的确认包、丢包后的重传等,以保证可靠性。由于不同机器的带宽和处理能力的差异,TCP需要能够控制流量。字节流:TCP会将来自应用程序的字节流数据切割成许多数据包在网络上发送。IP数据包会乱序或重复,TCP协议必须能够恢复字节流的本来面目。从上面的TCP协议图可以看出,标志位有6个,其中RST位是在TCP出现异常时出现的,这也是我这篇文章的重点。2.通过三次握手建立连接接下来我将建立一个从A到B的TCP连接来说明三次握手是如何完成的。为了能够清楚的解释下面的RST攻击,有必要结合上图来谈谈:SYN标志、序列号、滑动窗口大小。在建立连接的请求中,标志位SYN必须设置为1。在这个请求中,会通知MSS段大小,这是本机期望接收的TCP数据包的最大大小。发送的数据TCP数据包有一个序列号。它是这样获得的:在最初发送SYN时,有一个初始序列号。根据RFC的定义,每个操作系统的实现都与系统时间相关。之后,序号的值会不断增加。比如原来的序号是100,如果这个TCP包的数据有10个字节,那么下一个TCP包的序号就会变成110。滑动窗口就是用来加速传输的。比如你发送一个seq=100的数据包,你应该收到这个数据包的确认ack=101,然后才能继续发送下一个数据包。但是有了滑动窗口,只要没有确认新包的seq,如果最小seq差值小于滑动窗口大小,就可以继续发送。3.滑动窗口滑动窗口无疑是用来加速数据传输的。为了保证“可靠性”,TCP需要确认一个数据包以表明接收端已收到。有了滑动窗口,接收端可以等待接收到很多包,只发送一个ack包来确认之前已经接收到的多个数据包。有了滑动窗口,发送方发送一个数据包后不需要等待它的ack,可以继续发送滑动窗口大小内的其他数据包。让我们举个例子。看上图,标志位是。表示所有标志位为0。标志位P表示该标志位为PSH的TCP包,用于快速数据传输。前三个数据包是三次握手。client表示自己的滑动窗口大小是65535(我的XP机器),server表示滑动窗口是5840(屏幕比较宽,所以没有切出)。从第四个包开始,client向server发送一个PSH包,数据长度为520字节,server发送一个ack确认包。注意此时win窗口的大小发生了变化。等等。对于倒数第二个和第三个数据包,服务器在滑动窗口内连续向客户端发送数据包,客户端发送的ack124同时确认前两个数据包。这就是滑动窗口的作用。如果说到TCP攻击,就需要注意了。在TCP的各种实现中,滑动窗口外的seq都会被扔掉!这个问题将在下面讨论。4、四次握手的正常关闭TCP连接先画一个简单的正常关闭连接状态转换图。还看到了FIN标志,用来表示连接正常关闭。图中左边是主动关闭连接,右边是被动关闭连接。您可以使用netstat命令查看标记的连接状态。FIN常闭,会按照buffer的先后顺序发送,即buffer中FIN之前的数据包全部发送完后发送FIN包,这一点与RST不同。5、RST标志RST表示reset,用于异常关闭连接。它在TCP的设计中是必不可少的。上面说了,发送RST包关闭连接时,不用等缓冲区里的包全部发送完(不像上面的FIN包),直接丢弃缓冲区里的包再发送RST数据包。接收端收到RST包后,不需要发送ACK包确认。TCP处理程序在它认为异常的时刻发送RST数据包。比如A向B发起连接,但是B并没有监听对应的端口。这时B的操作系统上的TCPhandler会发送一个RST包。再比如,AB已经正常建立连接。通信过程中,A向B发送FIN包,请求关闭连接。B发送ACK后,网络断开,A由于多种原因(如进程重启)放弃连接。网通接通后,B又开始发送数据包。A收到后表示压力很大。他不知道野连接是从哪里来的,所以他发送了一个RST包来强制关闭连接。B收到后会出现一个connectresetby。同行错误。6、RST攻击A和服务器B建立了一个TCP连接,此时C伪造一个TCP数据包发送给B,导致B异常断开与A的TCP连接,这就是RST攻击。其实从上面RST标志的作用,我们已经可以看出这种攻击是如何达到效果的。那么可以伪造什么样的TCP数据包来达到目的呢?让我们从上到下看看。假设C假装是A发来的数据包,如果这个数据包是RST数据包,毫无疑问B会丢弃与A的缓冲区上的所有数据,强行关闭连接。如果过去发送的数据包是SYN数据包,那么B会表示A已经疯了(与OS的实现有关),正常连接时会建立新的连接,B会主动发送RST数据包给A,并强制关闭断开连接。这两种方法都可以达到重置攻击的效果。看起来很吓人,但关键是,怎么伪装成A发给B的数据包呢?这里有两个关键因素,源端口和序列号。一个TCP连接是一个四元组,一个连接由源IP、源端口、目的IP、目的端口唯一确定。因此,如果C要伪造A发送给B的数据包,就必须在上面提到的IP头和TCP头中正确填写源IP、源端口、目的IP、目的端口。这里B是服务器,IP和端口都是公开的。A是我们要攻击的目标。IP当然知道,但是A的源端口不清楚,因为可能是A随机生成的。当然如果能查到windows、linux等常见OS的源端口生成规则,就可以了仍然可以完成。序号问题对应的是滑动窗口。序列号需要填写在伪造的TCP数据包中。如果A先于A发送给B时序列号的值不在B的滑动窗口内,B会主动丢弃。所以我们需要找到当时能够落入A和B之间滑动窗口的序号。这个可以暴力解决,因为一个序列的长度是32位,取值范围是0-4294967296。如果窗口大小像我上图抓到的windows下的65535,你只需要划分就知道最多只需要发送65537(4294967296/65535=65537)个包就可以有序号落入滑动窗口。RST包很小,IP头+TCP头只有40字节。计算我们的带宽,我们知道只需要几秒钟就可以完成。那么,序列号不是问题,就是源端口比较麻烦。如果各个操作系统不能完全随机生成源端口,或者黑客可以通过其他方式获取源端口,那么RST攻击就很容易,后果也很严重。