更新時(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è)可靠包括三層含義
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)下圖:
這里面有幾個(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)行流量控制
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)下圖
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)下圖所示:
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/