首頁技術文章正文

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

更新時間:2018-04-27 來源:黑馬程序員 瀏覽量:

1、 概述

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

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

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

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

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

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

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)建一個socket, 指定SOCK_STREAM參數(shù)代表基于TCP協(xié)議
         *   如果是UDP協(xié)議,則需要用SOCK_DGRAM
         */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
 
        /**
         * Step 2: 設置目標主機IP地址和端口號
         *   IP+Port, 標識網(wǎng)絡上某個主機的通信進程
         */
    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: 連接服務器
          */
    if (connect(sockfd, (struct sockaddr *)&dest,
                    sizeof(struct sockaddr_in)) != 0){
                /* 此處SYN Flood攻擊會用到 */
                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: 關閉連接
         */
    close(sockfd);
 
        return 0;
}

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

2.2 TCP Server程序

下面我們編寫一個TCP Server程序,還是老規(guī)矩,力求簡單,不做容錯處理
#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)建一個socket, 指定SOCK_STREAM代表TCP
         */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
 
        /**
         *  Step 2:   綁定一個端口號
         */
    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)聽連接
         */
    listen(sockfd, 5);
 
        fprintf(stdout, "Serve listenning....\n");
        while(1){
                /**
                 * Step 4: Accept 一個連接請求
                 */
                socklen_t client_len = sizeof(client_addr);
                newsockfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);
 
                /**
                 * Step 5: 從當前連接讀取數(shù)據(jù) */
                memset(buffer, 0, sizeof(buffer));
                int len = read(newsockfd, buffer, 100);
                printf("Received %d bytes: %s", len, buffer);
 
                /**
                 * Step 6: 關閉當前鏈接*/
                close(newsockfd);
        }
 
        /**
         * Step 7: 關閉套接字
         */
        close(sockfd);
 
    return 0;
}

一個Server程序的大致步驟為:

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

2. 綁定一個端口號

3. 開始監(jiān)聽

4. 接受一個連接請求。

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

6. 關閉連接請求

7. 關閉socket

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

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

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

1524800403460_1.png

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

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

2.數(shù)據(jù)有序傳輸? 每個數(shù)據(jù)包編個序號,數(shù)據(jù)包到達主機可能錯序,在傳輸層調整順序后上傳。

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

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

1524800412663_2.png

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

l 源端口號和目的端口號, 各占16bits

l 32位序號 (seq)

l 32位應答序號(ack)

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

l 保留: 6位

l 標志位: 6位, 包括 SYN、FIN、ACK、RST、PSH、URG

l 滑動窗口: 16位, 可用于流量控制

l 校驗: 16位

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

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

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

3. TCP SYN Flood 攻擊

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

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

1.第一次握手: 首先客戶端C(?)主動發(fā)起連接,發(fā)送SYN(連接請求標志), 以及序號SEQ=x(序號x隨機生成)到服務器端S。

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

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

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

三方握手建立連接的過程詳細見下圖

1524800420538_3.png

3.2 SYN Flooding 攻擊

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

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

詳細見下圖所示:

1524800427398_4.png

3.3 SYN Flood 攻擊防護手段

l tcp_max_syn_backlog: 半連接隊列長度

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

l tcp_syncookies : syn dookie

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

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

黑馬程序員C/C++與網(wǎng)絡攻防課程關鍵技術點

涉及到的熱門技術有:·

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

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

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

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

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

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

·GDB(逆向工具)

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

·VIM(文本編輯器)

·QT(跨平臺應用界面框架)

涉及到的新興技術有:

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

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

·Docker(虛擬化容器技術)

·Go-micro(Go語言微服務框架)

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

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

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

·RPC(遠程調用過程)

·Oracle(高級事務關系型數(shù)據(jù)庫)

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

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

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

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

·AppScan(漏洞掃描工具)

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

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

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

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

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

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


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


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


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


分享到:
在線咨詢 我要報名
和我們在線交談!