首頁(yè)技術(shù)文章正文

網(wǎng)絡(luò)攻防的藝術(shù)之TCP協(xié)議篇

更新時(shí)間:2018-04-27 來(lái)源:黑馬程序員 瀏覽量:

1、 概述

網(wǎng)絡(luò)攻擊的主要內(nèi)容包括系統(tǒng)安全攻防、網(wǎng)絡(luò)安全攻防、物理攻擊與社會(huì)工程學(xué)三部分: 系統(tǒng)安全攻防主要是利用軟件安全漏洞進(jìn)行攻擊,網(wǎng)絡(luò)安全攻防利用協(xié)議棧的安全漏洞(不局限于此), 物理攻擊與社會(huì)工程學(xué)攻擊主要是利用人的心里弱點(diǎn)、物理設(shè)計(jì)缺陷。

TCP(Transmission Control Protocol) 傳輸控制協(xié)議是TCP/IP協(xié)議棧的核心協(xié)議,它位于IP協(xié)議層之上,在網(wǎng)絡(luò)上的兩臺(tái)計(jì)算機(jī)之間提供可靠的、有序的通信通道。許多應(yīng)用比如瀏覽器、SSH、Telnet、Email等使用TCP進(jìn)行通信。TCP協(xié)議處于為應(yīng)用提供主機(jī)到主機(jī)通信服務(wù)的傳輸層。

一般我們講TCP提供可靠的有連接服務(wù),這個(gè)可靠包括三層含義

  • 數(shù)據(jù)有序傳輸
  • 丟包重傳機(jī)制
  • 流量控制機(jī)制

2、TCP協(xié)議的工作原理

我們通過(guò)一個(gè)簡(jiǎn)單的TCP client程序和TCP Server程序來(lái)展示TCP建立連接、數(shù)據(jù)傳輸、斷開連接的過(guò)程。以下這兩個(gè)程序中,為了能清晰說(shuō)明程序的通信過(guò)程,不做容錯(cuò)處理,力求簡(jiǎn)單。工作當(dāng)中這樣的程序是不能正常工作的。

2.1 TCP Client 程序
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/ip.h>
 
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SER_ADDR "127.0.0.1"
#define SER_PORT 9999
//#define SER_ADDR "172.16.28.98"
 
/* main function */
int main(int argc, char *argv[])
{
        /**
         * Step 1: 創(chuàng)建一個(gè)socket, 指定SOCK_STREAM參數(shù)代表基于TCP協(xié)議
         *   如果是UDP協(xié)議,則需要用SOCK_DGRAM
         */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
 
        /**
         * Step 2: 設(shè)置目標(biāo)主機(jī)IP地址和端口號(hào)
         *   IP+Port, 標(biāo)識(shí)網(wǎng)絡(luò)上某個(gè)主機(jī)的通信進(jìn)程
         */
    struct sockaddr_in dest;
    memset(&dest, 0, sizeof(struct sockaddr_in));
    dest.sin_family = AF_INET;
    dest.sin_addr.s_addr = inet_addr(SER_ADDR);
    dest.sin_port = htons(SER_PORT);
 
        /**
         * Step 3: 連接服務(wù)器
          */
    if (connect(sockfd, (struct sockaddr *)&dest,
                    sizeof(struct sockaddr_in)) != 0){
                /* 此處SYN Flood攻擊會(huì)用到 */
                fprintf(stdout, "Error for connect: %s\n", strerror(errno));
                return 1;
        }
 
        /**
         * Step 4: 向Server發(fā)送數(shù)據(jù)
         */
 
        char *buffer1 = "Hello Server!\n";
    char *buffer2 = "Hello Again!\n";
    write(sockfd, buffer1, strlen(buffer1));
 
    write(sockfd, buffer2, strlen(buffer2));
 
        /**
         *  Step 5: 關(guān)閉連接
         */
    close(sockfd);
 
        return 0;
}

一個(gè)客戶端程序大概如下幾個(gè)步驟: 1. 創(chuàng)建一個(gè)socket,通過(guò)過(guò)指定參數(shù)SOCK_STREAM,來(lái)標(biāo)識(shí)基于TCP傳輸, 如果需要用UDP協(xié)議的話,則需要指定SOCK_DGRAM. 特別指出,如果需要通過(guò)原始套接字進(jìn)行通訊,需要指定SOCK_RAW。 2. 指定地址信息, 在網(wǎng)絡(luò)上,我們通過(guò)IP地址和Port來(lái)標(biāo)識(shí)一個(gè)特定主機(jī)上的進(jìn)程,此處填寫Server端的IP地址和端號(hào)。 3. 與Server建立連接, TCP是基于連接下協(xié)議,因此在數(shù)據(jù)傳輸之前,需要通過(guò)三次握手建立連接。 4. 收發(fā)數(shù)據(jù), 一旦連接建立成功,C/S兩端就可以通過(guò)write/send/sendto/sendmsg發(fā)送數(shù)據(jù),可以通過(guò)read/recv/recvfrom/recvmsg/接收數(shù)據(jù) 5. 關(guān)閉連接, 當(dāng)數(shù)據(jù)收發(fā)完畢后,連接不在需要時(shí),可以通過(guò)close斷開連接。

2.2 TCP Server程序

下面我們編寫一個(gè)TCP Server程序,還是老規(guī)矩,力求簡(jiǎn)單,不做容錯(cuò)處理
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
 
#define SER_ADDR 9999
 
int main(int argc, char *argv[])
{
    int sockfd, newsockfd;
    struct sockaddr_in my_addr, client_addr;
    char buffer[100];
 
        /**
         * Step 1: 創(chuàng)建一個(gè)socket, 指定SOCK_STREAM代表TCP
         */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
        /**
         *  Step 2:   綁定一個(gè)端口號(hào)
         */
    memset(&my_addr, 0, sizeof(struct sockaddr_in));
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(SER_ADDR);
    bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr_in));
 
        /**
         * Step 3: 監(jiān)聽(tīng)連接
         */
    listen(sockfd, 5);
 
        fprintf(stdout, "Serve listenning....\n");
        while(1){
                /**
                 * Step 4: Accept 一個(gè)連接請(qǐng)求
                 */
                socklen_t client_len = sizeof(client_addr);
                newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
 
                /**
                 * Step 5: 從當(dāng)前連接讀取數(shù)據(jù) */
                memset(buffer, 0, sizeof(buffer));
                int len = read(newsockfd, buffer, 100);
                printf("Received %d bytes: %s", len, buffer);
 
                /**
                 * Step 6: 關(guān)閉當(dāng)前鏈接*/
                close(newsockfd);
        }
 
        /**
         * Step 7: 關(guān)閉套接字
         */
        close(sockfd);
 
    return 0;
}

一個(gè)Server程序的大致步驟為:

1. 創(chuàng)建一個(gè)socket

2. 綁定一個(gè)端口號(hào)

3. 開始監(jiān)聽(tīng)

4. 接受一個(gè)連接請(qǐng)求。

5. 收發(fā)數(shù)據(jù)

6. 關(guān)閉連接請(qǐng)求

7. 關(guān)閉socket

其中 4、5、6可作為一個(gè)循環(huán),多次響應(yīng)連接請(qǐng)求。

2. 3 掀開數(shù)據(jù)傳輸?shù)拿婕?/p>

一旦連接建立, OS分別為Client端和Server端申請(qǐng)兩個(gè)Buffer, 一個(gè)是SendBuffer,用于發(fā)送數(shù)據(jù),一個(gè)是ReceiveBuffer,用于接收數(shù)據(jù)。 TCP協(xié)議是全雙工的,兩端都可以發(fā)送和接收數(shù)據(jù)。詳細(xì)流程見(jiàn)下圖:

1524800403460_1.png

這里面有幾個(gè)問(wèn)題,我們此處并不會(huì)對(duì)TCP協(xié)議完整展開解釋,選取和我們后續(xù)課程相關(guān)重點(diǎn)的描述一下:

1.TCP提供面向連接的服務(wù), 連接的建立過(guò)程在下一章節(jié)中,重點(diǎn)描述。

2.數(shù)據(jù)有序傳輸? 每個(gè)數(shù)據(jù)包編個(gè)序號(hào),數(shù)據(jù)包到達(dá)主機(jī)可能錯(cuò)序,在傳輸層調(diào)整順序后上傳。

3.丟包重傳機(jī)制:引入滑動(dòng)窗口機(jī)制, 窗口內(nèi)的數(shù)據(jù)如果沒(méi)有接到應(yīng)答ack, “超時(shí)”進(jìn)行重傳

4.流量控制機(jī)制:引入滑動(dòng)窗口機(jī)制后,接收端實(shí)時(shí)通知發(fā)送端當(dāng)前自己接受窗口大小,從而約束發(fā)送端的發(fā)送,進(jìn)行流量控制

1524800412663_2.png

TCP 部分一般稱之為Segment, 數(shù)據(jù)段, (補(bǔ)充: 在應(yīng)用層--消息、傳輸層--數(shù)據(jù)段Segment、網(wǎng)絡(luò)層--包/分組 packet、 鏈路層--幀frame、 物理層bits),對(duì)于TCP header的格式如上圖所述, 詳細(xì)解讀如下:

l 源端口號(hào)和目的端口號(hào), 各占16bits

l 32位序號(hào) (seq)

l 32位應(yīng)答序號(hào)(ack)

l TCP header長(zhǎng)度: 4位, 以4字節(jié)度量, 故Header最長(zhǎng)為64字節(jié)

l 保留: 6位

l 標(biāo)志位: 6位, 包括 SYN、FIN、ACK、RST、PSH、URG

l 滑動(dòng)窗口: 16位, 可用于流量控制

l 校驗(yàn): 16位

l 緊急指針:16位, 當(dāng)URG標(biāo)志置位時(shí), 此指針有效,用于帶外數(shù)據(jù)

l 選項(xiàng):0~320bits, 以32bits為單位,TCP可以通過(guò)options攜帶一些補(bǔ)充數(shù)據(jù)

我們講,TCP是面向連接的服務(wù), 因此就存在建立連接, 斷開連接等操作。后續(xù)我們選取針對(duì)連接建立過(guò)程和連接斷開過(guò)程進(jìn)行攻擊方面的展示。

3. TCP SYN Flood 攻擊

3.1 TCP 建立連接(三次握手)

我們說(shuō)TCP提供面向連接的服務(wù), 因此數(shù)據(jù)發(fā)送前需要先通過(guò)三次握手建立連接:

1.第一次握手: 首先客戶端C(?)主動(dòng)發(fā)起連接,發(fā)送SYN(連接請(qǐng)求標(biāo)志), 以及序號(hào)SEQ=x(序號(hào)x隨機(jī)生成)到服務(wù)器端S。

2.第二次握手: 服務(wù)器端S接受到SYN后, 向客戶端C也發(fā)送SYN及ACK, 且ack=x+1, 以及序號(hào)Seq=y(序號(hào)y隨機(jī)生成)。

3.第三次握手: 客戶端接到SYN及ACK后, 核查ack是否為x+1, 若正確, 則客戶端C發(fā)送ACK 且ack=y+1,至服務(wù)器端S。

4.服務(wù)器端S接收到ACK,核查ack是否為y+1. 若正確,則連接正常建立。

三方握手建立連接的過(guò)程詳細(xì)見(jiàn)下圖

1524800420538_3.png

3.2 SYN Flooding 攻擊

在探討SYN攻擊之前,我們先看看linux內(nèi)核對(duì)SYN是怎么處理的: 1. Server接收到SYN連接請(qǐng)求。 內(nèi)部維護(hù)一個(gè)隊(duì)列(我們暫稱之半連接隊(duì)列,半連接并不準(zhǔn)確), 發(fā)送ack及syn給Client端,等待Client端的ack應(yīng)答,接收到則完成三次握手建立連接。 如果接收不到ack應(yīng)答,則根據(jù)延時(shí)重傳規(guī)則繼續(xù)發(fā)送ack及syn給客戶段。

利用上述特點(diǎn)。我們構(gòu)造網(wǎng)絡(luò)包,源地址隨機(jī)構(gòu)建,意味著當(dāng)Server接到SYN包時(shí),應(yīng)答ack和syn時(shí)不會(huì)得到回應(yīng)。在這種情況下, Server端,內(nèi)核就會(huì)維持一個(gè)很大的隊(duì)列來(lái)管理這些半連接。 當(dāng)半連接足夠多的時(shí)候,就會(huì)導(dǎo)致新來(lái)的正常連接請(qǐng)求得不到響應(yīng)。 也就是所謂的DOS攻擊。

詳細(xì)見(jiàn)下圖所示:

1524800427398_4.png

3.3 SYN Flood 攻擊防護(hù)手段

l tcp_max_syn_backlog: 半連接隊(duì)列長(zhǎng)度

l tcp_synack_retries: syn+ack 的重傳次數(shù)

l tcp_syncookies : syn dookie

一般的防御措施就是就是減小SYN+ACK重傳次數(shù),增加半連接隊(duì)列長(zhǎng)度,啟用syn cookie。不過(guò)在高強(qiáng)度攻擊面前,調(diào)優(yōu) tcp_syn_retries 和 tcp_max_syn_backlog 并不能解決根本問(wèn)題,更有效的防御手段是激活 tcp_syncookies,在連接真正創(chuàng)建起來(lái)之前,它并不會(huì)立刻給請(qǐng)求分配數(shù)據(jù)區(qū)存儲(chǔ)連接狀態(tài),而是通過(guò)構(gòu)建一個(gè)帶簽名的序號(hào)來(lái)屏蔽偽造請(qǐng)求。

傳智播客黑馬程序員C/C++與網(wǎng)絡(luò)攻防學(xué)科培養(yǎng)專項(xiàng)白帽子安全人才,課程包含 C語(yǔ)言開發(fā)實(shí)戰(zhàn)、C高級(jí)編程、C++核心編程與桌面應(yīng)用開發(fā)、Linux高并發(fā)服務(wù)器開發(fā)、信息安全與企業(yè)應(yīng)用開發(fā)、分布式云平臺(tái)開發(fā)、入侵檢測(cè)與網(wǎng)絡(luò)攻防等階段。

黑馬程序員C/C++與網(wǎng)絡(luò)攻防課程關(guān)鍵技術(shù)點(diǎn)

涉及到的熱門技術(shù)有:·

Nginx(高并發(fā)反向代理服務(wù)器)

·GIT(分布式版本控制系統(tǒng))

·Redis(NoSQL緩存數(shù)據(jù)庫(kù))

·Memcache(key-value分布式緩存數(shù)據(jù)庫(kù))

·Libevent(高并發(fā)反應(yīng)堆模式API)

·Epoll(Linux內(nèi)核高級(jí)多路IO技術(shù))

·GDB(逆向工具)

·SHM(共享內(nèi)存映射機(jī)制)

·VIM(文本編輯器)

·QT(跨平臺(tái)應(yīng)用界面框架)

涉及到的新興技術(shù)有:

·fastDFS(分布式文件系統(tǒng))

·Golang(Google推出的開發(fā)編程語(yǔ)言)

·Docker(虛擬化容器技術(shù))

·Go-micro(Go語(yǔ)言微服務(wù)框架)

·Beego(Go語(yǔ)言高性能web服務(wù)器框架)

·GEO(地理位置核心算法)

·ASN.1(跨平臺(tái)安全傳輸協(xié)議)

·RPC(遠(yuǎn)程調(diào)用過(guò)程)

·Oracle(高級(jí)事務(wù)關(guān)系型數(shù)據(jù)庫(kù))

涉及到的網(wǎng)絡(luò)攻防技術(shù)有:

·Kali Linux(Hacker操作系統(tǒng))

·Wireshark(網(wǎng)絡(luò)抓包分析工具)

·Aircrack-ng(可破解WEP/WPA/WPA2加密)

·AppScan(漏洞掃描工具)

·DDos(分布式拒絕服務(wù)攻擊)

·Web滲透(Web頁(yè)面代碼的攻擊形式)

·iptables(Linux內(nèi)核防火墻技術(shù))

·NetCat(網(wǎng)絡(luò)攻擊瑞士軍刀)

·TCPDump(Linux內(nèi)核網(wǎng)絡(luò)協(xié)議捕捉器)

·SQLMAP(SQL注入漏洞攻防技能)


本文版權(quán)歸黑馬程序員C/C++與網(wǎng)絡(luò)攻防學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!


作者:黑馬程序員C/C++與網(wǎng)絡(luò)攻防學(xué)院


首發(fā):http://c.itheima.com/


分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!