对我们现有的知识来说这是一种新的攻击方式。通常人们总是会质疑到TCP握手过程中两端都认证了彼此的IP地址。那么这种攻击会告诉我们这并不总是真的。
在跟方提斯大学的合作研究项目中,笔者和Raoul Houkes研究针对TCP的不同攻击方式,包括在执行过程中和针对协议层次的攻击。最终我们发现了一种针对协议层次的攻击。
A:你好B,我是A,发送数字5。
B:你好A,我是B,5,发送数字3。
A:你好B,我是A,3,发送数字6。我想访问example.net。
B:你好A,我是B,6,发送数字4。这是数据:…
至此以后,A可以向B发送数据,B也可以向A发送数据了。随着A和B的通信,每一次数据包中的数字都会递增。通过这种措施来跟踪数据包是否被对方所接收,以保证可靠传输。
这个协议是在1981年那个缺乏安全防护意识的年代所提出的。ARPANET当时急需一种协议满足:发送数据前无需担心转发出错、每次传输对数据进行校验并检测错误和保持有序的数据包等特性。TCP就满足这些所有的需求。
上面所说的数字,实际上应该叫“序列号(sequence)”和“确认号(acknowledgement)”,它们用于确保传输中的安全和可靠。但这就导致了两个问题:
1、序列号和确认号字段长度不够大(32bit); 2、带有错误号码的数据包会被直接丢弃但却不关闭连接。换句话说,在发送带有正确确认号的数据包前无论发送多少带有错误确认号的数据包,这个正确的确认包都会被正常接收。
A:你好B,我是C,发送数字5。
B:你好C,我是B,5,发送数字3。
A:你好B,我是C,1,发送数字6。我想访问example.net。
B:你好C,我是B,你的数据错误。请关闭连接。
A:你好B,我是C,2,发送数字6。我想访问example.net。
B:你好C,我是B,你的数据错误。请关闭连接。
A:你好B,我是C,3,发送数据6。我想访问example.net。
B:你好C,我是B,6,发送数字4。这是数据:…
在这个例子中,主机A从来没有收到任何来自主机B的消息,而且主机B并不知道它回复的是一个伪造的IP地址,主机A将自己的IP伪造成了C。
当然,这里有一个前提就是主机C不会发生类似于“这到底怎么回事?”的数据包(或者RST数据包),不过这都不是问题,使用一个不存在的IP(比如:0.0.0.0)或者利用防火墙(客户端通常位于防火墙之后或者使用NAT,再或者同时使用这两种)。
但主机B等待主机C确认的时间是很有限的。在内核版本为4.2的Linux中,我测试结果为20s。也就是说在20s后,我们需要重新开始(发送另一个SYN包),但这没什么区别,因为发送的数字完全是随机的。
那么攻击的代价如何?平均需要120GB的网络流量(包含以太网头部、IP头部和TCP头部封装的60比特)同时发起连接。运气不好时可能需要200GB的流量,但运气好时仅需要72GB的流量。
我们快速的查询了下后发现,具有1Gbps带宽的VPS价格非常便宜。如果你能充分利用带宽,那么平均的攻击时间为17分11秒。
通常我们会想注入一个payload,比如发送命令。这个命令需要附加在现有的数据后,那么需要更大的流量进行攻击。例如,发送 GET / HTTP/1.0/n/n
平均需要152GB流量和20分钟。而这些连接在日志文件中全部会显示为正常的连接。
另一个例子是在某些系统的管理界面上绕过黑名单或者白名单。这种方式在90年代非常受欢迎,即使现在也依旧很多应用还只这么做。
POC
研究怎么能没POC呢?下面的截图全部来自于Wireshark。
我过滤出了相关的数据包,如图所示目标全是192.168.36.17。第一个数据包是一个初始化数据包,实际发送者为192.168.36.11,但它伪造成了192.168.36.18。我们的目标回应了伪造的IP地址,然后我们的工具开始猜测正确的确认号。注意从0.x秒到8.x秒我们过滤到了大量攻击的数据包。另一方面,我们猜测的数字可以从2的32次方(40多亿)一直递减到0,这是由Wireshark提供的一些相关数字决定的。最终我们找到了正确的数字。确认号(relative ack number)为1正是我们想要的!在接收到正确的包后,SSH服务器返回它的banner信息,就像平时接收到正常TCP连接一样。
服务器选取的随机数是0x0006943f(431167)。
在某个时刻,我们的脚本跑到了0x00069440f(431168),这是一个正确的确认号。
最终,SSH像进行正常连接一样给我们返回了banner信息。
原始的数据包只有15秒,因为我在循环日志(rotating logs)前只采集了15秒的数据。听起来没什么事,但是总共有5544384个数据包近半个Gb。如果你想看到这些,你可以自己进行攻击实验。
我实验的数据包可以从这里下载到: spoofed-tcp-connection.pcap
最后,我所使用的攻击脚本可以从这里下载到: attack-tcp.py
这仅仅只是一个验证用的不可维护的代码
结论
鉴于TCP协议本身的性质,这种攻击很难防御。对于确认号不正确的猜测攻击的数据包会被直接丢弃并被要求关闭连接,但是这中间还是留下一段足够利用的时间。
为了进行双方相互的认证,例如TLS等额外的安全措施是很必要的。即使不认证客户端的证书,TLS也会对会话进行加密。欺骗将变得不可行。
今日教训:不要使用基于IP地址的认证方式,不要相信IP地址白名单,当有安全需求时使用安全的协议。
*原文: [lgms.nl] ,FB小编xiaix编译,转自须注明来自FreeBuf黑客与极客(FreeBuf.COM)