有算法就有破解法,因为它们都遵循了一定的数据结构和数学知识。所以网络安全是一个相对的概念,不可能出现绝对的安全!作为当今最流行的网络协议——TCP也是如此。那么TCP的安全问题究竟是哪些因素引起的呢?
一、TCP漏洞的来源
1.设计初心
我们知道TCP协议诞生于1973年,那时候计算机网络也是刚刚起步。在没有经验的前提下,开发者们主要的目标是为了实现网络的连通性。对于安全性,一是没有经验,二是设计的目的性就不在此。所以TCP协议的诞生之初就意味着它不可能在安全性方面有太高的造诣
2.TCP数据的传输形势——明文传输
不同于一些诞生比较晚的计算机网络协议——https和chap等等。TCP协议在传输数据的时候是明文传输的。这在一定程度上就导致数据安全存在很大的隐患。这也是很多md5等一些列加密算法产生的重要原因
3.TCP协议的首部字段缺乏安全性认证
TCP协议对于数据发送的源头是没有验证机制的,即使数据报中存在源端口字段(也包括网络层协议IP数据报中包含源IP字段)!也就是说,很多时候我们关系的问题是如何把该数据报准确无误的传给谁,但是却忘了这个数据报确实是源方(源IP字段指定的客户端)发送来的未经修改或未经窃取的数据报吗?
4.TCP的连接性是一把双刃剑
只要知道TCP协议的人就知道TCP的一个重要特点——它是面向连接的一个网络协议!更通俗的说就是TCP所进行的数据的交互都是在一个连接周期中进行的!还可以换句话说,如果你想对某个客户端的发起攻击,必须要做的一件事情就是劫持(或窃听)该客户端和某网络应用的一个TCP连接(当前计算机网络的半壁江山都是基于TCP的)!
所以如果我们的某个基于TCP协议进行连接的进程如果被劫持,也就等效于这次数据几乎全部遇难(除非全部关键数据都进行了相关的加密技术)。那么劫持TCP连接的关键在哪?
这个关键点就是报文首部的序号字段。我们知道,TCP的流量控制、数据失效重传功能、拥塞控制算法等等都与滑动窗口的大小(起始端点和窗口长度)有着密切的联系,而滑动窗口的大小取值恰恰依赖着这个 “序号” 字段。我们先回顾一下tcp首部中一些较为关键的字段及其分析:
序号 ===> 4byte;序号范围是[0,2^32 - 1]
序号增加到 2^32 - 1 后,下一个序号就又回到0。也就是说,序号使用mod 2^32 运算;由于序号字段有32位长,可对4GB的数据进行编号。在一般情况下可保证当序号重复使用时,旧序号的数据早已通过网络到达终点了
在一个TCP连接中传送的字节流中的每一个字节都按顺序编号。字节流的起始序号必须在连接建立时设置。TCP数据报首部中的序号字段值则指的是本报文段所发送的数据的第一个字节的序号。
例如,一报文段的序号字段值是301,而携带的数据共有100字节。这就表明:本报文段的数据的第一个字节的序号是301,最后一个字节的序号是400。显然,下一个报文段(如果还有的话)的数据序号应当从401开始,即下一个报文段的序号字段值应为401。这个字段的名称也叫做“报文段序号”。
==========================================================================
确认号 ===> 4byte;即期望收到对方下一个报文段的第一个数据字节的序号。若确认号为N,则表明:到序号N-1为止的所有数据都已正确收到。
例如,B收到了A发送的一个报文段,其序号字段值是501,而数据长度是200字节(序号501~700),此时,B期望收到A的下一个数据序号是701,于是B在发送给A的确认报文段中把确认号置为701。
==========================================================================
数据偏移 ===> 4bit;单位为4byte即32bit;它指出TCP报文段的数据起始处距离TCP报文段的起始处有多远。(即TCP报文段的首部长度)。因为该字段长4bit,单位为4byte。所以数据偏移的最大值是60字节,这也是TCP首部的最大长度(即选项长度不能超过40字节)。
==========================================================================
紧急URG(URGent)===> 1bit;
当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据),而不要按原来的排队顺序来传送。于是发送方TCP就把紧急数据插入到本报文段数据的最前面,而在紧急数据后面的数据仍是普通数据。这时要与首部中紧急指针(Urgent Pointer)字段配合使用
==========================================================================
确认ACK(ACKnowledgment)===> 1bit;仅当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。TCP规定,在连接建立后所有传送的报文段都必须把ACK置1
==========================================================================
推送PSH(PuSH) ===> 1bit;当两个应用进程进行交互式的通信时,有时在一端的应用进程希望在键入一个命令后立即就能够收到对方的响应,而不再等到整个缓存都填满了后再向上交付。这时,发送方TCP把PSH置1,并立即创建一个报文段发送出去。接收方TCP收到PSH=1的报文段,就尽快地(即“推送”向前)交付接收应用进程
==========================================================================
复位RST(ReSeT)===> 1bit;当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接。RST置1还用来拒绝一个非法的报文段或拒绝打开一个连接。RST也可称为重建位或重置位。
==========================================================================
同步SYN(SYNchronization)===> 1bit;在连接建立时用来同步序号
当SYN=1而ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应的报文段中使SYN=1和ACK=1。因此,SYN置为1就表示这是一个连接请求或连接接受报文
==========================================================================
终止FIN(FINis)===> 用来释放一个连接
当FIN=1时,表明此报文段的发送方的数据已发送完毕,并要求释放运输连接
==========================================================================
窗口 ===> 2byte;值是[0,2^16-1]之间的整数;窗口字段明确指出了现在允许对方发送的数据量。窗口值经常在动态变化着
窗口指的是发送本报文段的一方的接收窗口(而不是自己的发送窗口)。窗口值告诉对方:从本报文段首部中的确认号算起,接收方目前允许对方发送的数据量(以字节为单位)。之所以要有这个限制,是因为接收方的数据缓存空间是有限的
例如,发送了一个报文段,其确认号是701,窗口字段是1000。这就是告诉对方:“从701号算起,我(即发送此报文段的一方)的接收缓存空间还可接收1000个字节数据(字节序号是701~1700)
==========================================================================
大概了解了这些字段的作用之后,我们再从下图回顾一下TCP滑动窗口实现流量控制的具体步骤:
从上图中我们可以发现一个关键点——那就是只有我们掌握了某个tcp连接的下一个数据报序号和窗口大小,那么我们大多数情况下就可以顺利的劫持的此TCP连接,从而实现数据的监控甚至注入!
二、如何利用TCP的这些漏洞
通过以上的分析,我们已经明确了TCP安全的漏洞所在,那就是序号与滑动窗口的大小。而滑动窗口的大小可以通过多次分析tcp数据报首部的关键字段和数据长度加以获取。
对于TCP连接,不同的系统发出的数据报中的序列号的产生方法是不一样的,换句话说,从序列号可以得到该服务器或客户端的操作系统是属于windows系列还是Linux系列或者是mac系列等等。那么具体怎个不一样法呢?
当tcp连接出现异常的时候,我们向它发送一些不同标志位组合的报文,它们的反映是不一样的。举例来说,加入我们发送RET报文,目标主机如果是windows系列,它会返回一个RST报文,如果是LInux则不会做任何响应。得到了目标主机的操作系统型号,就可以更容易的获取滑动窗口的大小,然后根据报文中的序号字段实行劫持。
因为TCP使用的sequence number是一个32位的计数器,从0-4294967295。tcp为每一个连接选择一个初始序号ISN,为了防止因为延迟、重传等扰乱三次握手,ISN不能随便选取,不同系统有不同算法。理解tcp如何分配ISN以及ISN随时间变化的规律,对于成功地进行arp欺骗攻击很重要。
三、如何进行TCP欺骗
1.TCP欺骗的方法
非盲攻击:攻击者和被欺骗的目的主机在同一个网络上,攻击者可以简单地使用协议分析器(嗅探器)捕获tcp报文段,从而获得需要的序列号
盲攻击:由于攻击者和被欺骗的目标主机不在同一个网络上,攻击者无法使用嗅探器捕获tcp报文段。其攻击步骤与非盲攻击几乎相同,只不过在步骤三无法使用嗅探器,以使用tcp初始序列号预测技术得到初始序列号。在步骤攻击者X可以发送第一个数据包,但收不到A的响应包,难实现交互
2.TCP序号的产生方法
三种常用的产生方法:
①.64K规则---RFC793
②.机器时钟---RFC1948
③.伪随机数
以上三种序列号产生都是有一定的规则的,不是杂乱无章的:
RFC793
RFC793指出ISN可看作是一个32比特的计数器函数确定,每4ms加1,我们进行若干次的重复连接之后,求得数据的平均往返时间RTT,然后再根据序号的增速猜测下一个序号可能是多少
RFC1948
RFC1948通过连接标识符来区分序列号空间。每一个连接标识符由本地地址,本地端口,远程地址,远程端口来组成,并由一个函数计算标识符分的序列号地址空间偏移值(唯一)
此函数不能被攻击者获得,否则,攻击者可以通过计算获得ISN。于是,ISN就在这个偏移值上增加。ISN的值以这种方式产生能够抵受上面提到的对ISN的猜测攻击
ISN自身的值是按照一个常数值稳定增加的,所以F0需要保持相对的稳定性
<some secret>是一个系统特定的值(例如机器的启动时间,密码,初始随机数等),这些值并不会经常变。但是,如果Hash函数在实现上存在漏洞(我们无法保证一个绝对安全的Hash函数,况且,它的实现又与操作系统密切相关),攻击者就可以通过大量的采样,来分析<some secret>,其中,源ip地址,源端口,目的ip地址,目的端口都是不变的,这减少了攻击者分析的难度
Linux tcp的ISN生成器避免了这一点。它每5分钟计算一次<some secret>值,把泄漏<some secret>的风险降到了最低。
有一个办法可以做的更好:
取M=M+R(t)
ISN=M+F(sip,sport,dip,dport,<some secret>)
其中R()是一个关于时间的随机函数
伪随机数规则
构造TCPISN生成器的一些更直接的方法是:简单地选取一些随机数作为ISN。这就是给定一个32位的空间,指定ISN=R(t)。(假设RO是完全的非伪随机数生成函数)
4.TCP序号猜测前提
第一,攻击者能够在短时间内向服务器的某个开放的端口发起若干个TCP连接请求,这些请求用来分析服务器的ISN增长规律,从而推断出下一次连接的ISN的可能值,在这若干个连接请求后紧接着的就是用于攻击的连接请求,如果服务器在攻击者发起攻击的这一段时间没有建立其它的连接,那么其下一次连接建立的ISN被攻击者推断出的可能性就很高
第二,攻击者能够防止在攻击的过程中,被授权的客户机会因为收到从服务器发来的SYN/ACK而对该数据包做出响应(发送RST终止本次连接)。攻击者可以通过使用一个已经离线的主机的IP地址,或者向其假冒的客户机发起拒绝服务攻击来阻止该客户机响应服务器发来的数据包
第三,攻击者利用的是服务器上的一个应用层的协议,该协议是单纯地依赖于客户机的口地址认证和授权的,而不是诸如通过密钥协商或加密密钥认证的高层认证机制
第四,攻击者能够猜测或推断出从服务器发送给攻击者假冒的客户机的TCP数据,这些数据对于攻击者来说是看不到的RFC1948通过连接标识符来区分序列号空间。每一个连接标识符由本地地址,本地端口,远程地址,远程端口来组成,并由一个函数计算标识符分的序列号地址空间偏移值(唯一)。
此函数不能被攻击者获得,否则,攻击者可以通过计算获得ISN。于是,ISN就在这个偏移值上增加。ISN的值以这种方式产生能够抵受上面提到的对ISN的猜测攻击。
3.TCP序列号的获取步骤
RFC749
1、首先攻击方先发送一个syn包来获取服务器现在的tcp序列号
攻击方:S syn(ISN攻击方)
S:ACKISN攻击方)+SYN(ISNS#)
2、紧接着攻击方冒充被攻击的客户端向服务器发送syn包攻击方:S SYN(ISN攻击方),SRC=被攻击的客户端
3、于是,服务器发出一个响应包给被攻击的客户端,这个包攻击方是收不到的S:被攻击的客户端 SYN(ISNSS),ACK(INS被攻击的客户端)
4、攻击方计算INS$ INS$=INS#+R被攻击的客户端被攻击的客户端*Increment of ISN
5、攻击方:SACK(ISNSS)(冒充可信主机)
RFC1948
ISN=M+F(sip,sport,dip,dport,<some secret>)
其中
ISN32位的初始序列号
M单调增加的计数器
F单向散列哈希函数(例如MD4 or MD5)sip源ip地址
sport 源端口dip目的ip地址dport目的端口
<some secret>哈希函数可选部分,使远程攻击者更难猜到ISN
伪随机数
ISN=((PRNG())<<16)+R(t)32位
其中PRNG():一组随机指定的连续的16位数字
0x00000000--0xffff0000
R(t):16位随机数生成器(它的高位msb设成0)
0x00000000--0x0000ffff上面的公式被用于设计OpenBsd的ISN生成器,相关的源代码可以从下面的网址获得
http://www.openbsd.org/cgiin/cvsweb/src/sys/netinet/tcp_subr.c
4.对获取到的TCP序列号的处理
对TCP序列号的猜测不仅发生在三次握手的过程中,还发生在连接建立后的数据传送过程中
1、如果猜测正确,数据将会放到接收缓冲区中
2、如果序列号小于目的主机所期望的序列号,包被丢弃
3、如果序列号大于目的主机所期望的序列号.但是小于TCP的接收窗口范围,将被放到一个缓冲队列中,因为有可能是后发送的数据先到达了
4、如果不是目的主机所期望的序列号,又不在TCP1的接收窗n范围内,包被丢弃
5.什么是TCP会话劫持
服务器与信任主机三次握手建立连接后,服务器收到另一台合法主机发送的tcp报文前,攻击主机根据所截获的信息向服务器发出一个带有净荷的tcp报文,如果服务器先收到攻击报文,就可以把合法的tcp会话建立在攻击主机与被攻击主机之间
带有净荷的攻击报文能够使被攻击主机对下一个要收到的tcp报文中的确认序号(ackseq)的值的要求发生变化,从而使正常合法的客户端主机向被攻击主机发出的报文被被攻击主机(服务器)拒绝
tcp会话劫持攻击方式的好处在于使攻击者避开了被攻击主机对访问者的身份验证和安全认证,从而使攻击者直接进入对被攻击主机的的访问状态,因此对系统安全构成的威胁比较严重
6.如何进行会话劫持
1.会话劫持的目标应用
基于tcp的任何应用,如HTTP、FTP、Telnet等
2.会话劫持的工作原理
对于攻击者来说,所必须要做的就是窥探到正在进行tcp通信的两台主机之间传送的报文,这样攻击者就可以得知该报文的源ip、源tcp端口号、目的ip、目的tcp端号,从而可以得知其中一台主机对将要收到的下一个tcp报文段中seq和ackseq值的要求