1、三次握手的具体流程
所谓三次握手,即建立TCP连接,就是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。在socket编程中,这一过程由客户端执行connect来触发,整个流程如下图所示:
(1)第一次握手:客户机的TCP首先向服务器的TCP发送一个连接请求报文段。这个特殊的报文段中不含应用层数据,其首部中的SYN标志位被置为1。另外,客户机会随机选择一个起始序号seq=J(连接请求报文不携带数据,但要消耗一个序号)。
(2)第二次握手:服务器的TCP收到连接请求报文段后,如同意建立连接,就向客户机发回确认,并为该TCP连接分配TCP缓存和变量。在确认报文段中,SYN和ACK位都被置为1,确认号字段的值为J+1,并且服务器随机产生起始序号seq=K(确认报文不携带数据,但也要消耗一个序号)。
(3)第三次握手:当客户机收到确认报文段后,还要向服务器给出确认,并且也要给该连接分配缓存和变量。这个报文段的ACK标志位被置1,确认字段为K+1,该报文段可以携带数据,若不携带数据则不消耗序号。
成功进行以上三步后,就建立了TCP连接。
2、TCP三次握手缺陷引起的SYN泛洪攻击
SYN泛洪攻击利用TCP三次握手协议的缺陷,向目标主机发送大量的伪造源地址的SYN连接请求,使得被攻击方资源耗尽,从而不能够为正常用户提供服务。
在TCP协议三次握手的连接过程中,如果一个用户向服务器发送了SYN报文,服务器又发出 SYN+ACK 应答报文后未收到客户端的 ACK 报文,这种情况下服务器端会再次发送SYN+ACK给客户端,并等待一段时间后丢弃这个未完成的连接,这段时间的长度称为SYN Timeout,一般来说这个时间是分钟的数量级。
SYN 泛洪攻击所做的就是利用这个SYN Timeout和TCP/IP协议族中的另一个漏洞: 报文传输过程中对报文的源 IP 地址完全信任进行攻击。SYN 泛洪攻击通过发送大量的伪造 TCP 连接报文而造成大量的 TCP 半连接,服务器端将为了维护这样一个庞大的半连接列表而消耗非常多的资源。这样服务器端将忙于处理攻击者伪造的TCP连接请求而无法处理正常连接请求,甚至会导致堆栈的溢出崩溃。
造成SYN泛洪攻击最主要的原因是TCP/IP协议的脆弱性。TCP/IP是一个开放的协议平台,它将越来越多的网络连接在一起,它基于的对象是可信用户群,所以缺少一些必要的安全机制,带来很大的安全威胁。例如常见的IP欺骗、TCP连接的建立、ICMP数据包的发送都存在巨大的安全隐患,给SYN泛洪攻击带来可乘之机。在本次实验下我们将采用kali linux虚拟机进行泛洪攻击。
在Linux应用编程如果设置为非阻塞模式,则连接时,connect发送SYN包后立即返回-EINPROGRESS,表示操作正在处理中;随后应用可以在connect返回后做一些其它的处理,最后在select函数中来捕获socket的连接、读写、异常事件以触发相关操作,下面我们看看内核中的相关实现:
client发送2个包,一个SYN包,一个对服务器的响应ACK包。
client函数调用链:connect-->sys_connect->inet_stream_connect->tcp_connect...
看inet_stream_connect中实现的部分代码段:
switch (sock->state) { ... /*此处调用tcp_connect函数发送SYN包*/ err = sk->prot->connect(sk, uaddr, addr_len); if (err < 0) //出错则退出 goto out; sock->state = SS_CONNECTING; /* 此处仅设置socket的状态为SS_CONNECTING表示连接状态正在处理; * 不同之处在于非阻塞情况下,返回值设置为-EINPROGRESS表示操作正在处理 * 而阻塞式情况则在获得ACK包后将返回值置为-EALREADY. */ err = -EINPROGRESS; break; } timeo = sock_sndtimeo(sk, flags&O_NONBLOCK); //注意,如果此时设置了非阻塞选项,则timeo返回0 //如果socket对应的sock状态是SYN包已发送或收到SYN包并发送了ACK包,并等待对端发送第三此的ACK包 if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { /* 错误返回码err前面已经设置 */ if (!timeo || !inet_wait_for_connect(sk, timeo)) /*注意上面所判断的2中情况,1、如果是非阻塞模式,则!timeo为1,则直接跳到out返回-EINPROGRESS结束connect函数 2、若为阻塞模式,则在inet_wait_for_connect函数中通过schedule_timeout函数放弃cpu控制权睡眠,等待服务器端 发送ACK响应包后被唤醒继续处理。如果没有异常出现,则置socket状态为SS_CONNECTED,表示连接成功,正确返回 */ goto out; err = sock_intr_errno(timeo); if (signal_pending(current)) /*处理未决信号*/ goto out; } ... sock->state = SS_CONNECTED; err = 0; out: release_sock(sk); return err;
服务器端此时必须是监听状态,则其函数调用链为:
netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->
tcp_rcv_state_process-->tcp_v4_conn_request-->tcp_v4_send_synack...
在tcp_v4_conn_request,中部分代码如下:
case TCP_LISTEN: if(th->ack) /*监听时收到的ack包都丢弃?*/ return 1; if(th->syn) {/*如果是SYN包,则调用tcp_v4_conn_request*/ if(tp->af_specific->conn_request(sk, skb) < 0) return 1; ...
原文:https://www.cnblogs.com/gfsh/p/12103922.html