SYN ***是最多見又最容易被利用的一種***手法。相信不少人還記得2000年YAHOO網站遭受的***事例,當時***利用的就是簡單而有效的SYN***,有些 網絡蠕蟲病毒配合SYN***形成更大的破壞。本文介紹SYN***的基本原理、工具及檢測方法,並全面探討SYN***防範技術。
1、TCP握手協議
在TCP/IP協議中,TCP協議提供可靠的鏈接服務,採用三次握手創建一個鏈接。
第一次握手:創建鏈接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
(TCP 鏈接示意圖)
(TCP 關閉示意圖)
完成三次握手,客戶端與服務器開始傳送數據,在上述過程當中,還有一些重要的概念:
未鏈接隊列: 在三次握手協議中,服務器維護一個未鏈接隊列,該隊列爲每一個客戶端的SYN包(syn=j)開設一個條目,該條目代表服務器已收到SYN包,並向客戶發出 確認,正在等待客戶的確認包。這些條目所標識的鏈接在服務器處於Syn_RECV狀態,當服務器收到客戶的確認包時,刪除該條目,服務器進入 ESTABLISHED狀態。
Backlog參數:表示未鏈接隊列的最大容納數目。
SYN-ACK 重傳次數: 服務器發送完SYN-ACK包,若是未收到客戶確認包,服務器進行首次重傳,等待一段時間仍未收到客戶確認包,進行第二次重傳,若是重傳次數超過系統規定的最大重傳次數,系統將該鏈接信息從半鏈接隊列中刪除。注意,每次重傳等待的時間不必定相同。
半鏈接存活時間:是指半鏈接隊列的條目存活的最長時間,也即服務從收到SYN包到確認這個報文無效的最長時間,該時間值是全部重傳請求包的最長等待時間總和。有時咱們也稱半鏈接存活時間爲Timeout時間、SYN_RECV存活時間。
2、SYN***的基本原理
SYN***屬於DOS***的一種,它利用TCP協議缺陷,經過發送大量的半鏈接請求,耗費CPU和內存資源。SYN***除了能影響主機外,還能夠危 害路由器、防火牆等網絡系統,事實上SYN***並無論目標是什麼系統,只要這些系統打開TCP服務就能夠實施。
從上圖可看到,服務器接收到鏈接請求(syn= j),將此信息加入未鏈接隊列,併發送請求包給客戶(syn=k,ack=j+1),此時進入SYN_RECV狀態。當服務器未收到客戶端的確認包時,重 發請求包,一直到超時,纔將此條目從未鏈接隊列刪除。配合IP欺騙,SYN***能達到很好的效果,一般,客戶端在短期內僞造大量不存在的IP地址,向服 務器不斷地發送syn包,服務器回覆確認包,並等待客戶的確認,因爲源地址是不存在的,服務器須要不斷的重發直至超時,這些僞造的SYN包將長時間佔用未 鏈接隊列,正常的SYN請求被丟棄,目標系統運行緩慢,嚴重者引發網絡堵塞甚至系統癱瘓。
3、SYN***工具
SYN***實現起來很是的簡單,互聯網上有大量現成的SYN***工具。
windows系統下的SYN工具
以 synkill.exe爲例,運行工具,選擇隨機的源地址和源端囗,並填寫目標機器地址和TCP端囗,激活運行,很快就會發現目標系統運行緩慢。若是*** 效果不明顯,多是目標機器並未開啓所填寫的TCP端囗或者防火牆拒絕訪問該端囗,此時可選擇容許訪問的TCP端囗,一般,windows系統開放 tcp139端囗,UNIX系統開放tcp七、2一、23等端囗。
4、檢測SYN***
檢測SYN***很是的方便,當你在服務器上看到大量的半鏈接狀態時,特別是源IP地址是隨機的,基本上能夠判定這是一次SYN***。咱們使用系統自帶的netstat 工具來檢測SYN***:
html
# netstat -n -p TCP
linux
tcp 0 0 10.11.11.11:23 124.173.152.8:25882 SYN_RECV -
windows
tcp 0 0 10.11.11.11:23 236.15.133.204:2577 SYN_RECV -
安全
tcp 0 0 10.11.11.11:23 127.160.6.129:51748 SYN_RECV -
bash
tcp 0 0 10.11.11.11:23 222.220.13.25:47393 SYN_RECV -
服務器
tcp 0 0 10.11.11.11:23 212.200.204.182:60427 SYN_RECV -
cookie
tcp 0 0 10.11.11.11:23 232.115.18.38:278 SYN_RECV -
網絡
tcp 0 0 10.11.11.11:23 239.116.95.96:5122 SYN_RECV -
併發
tcp 0 0 10.11.11.11:23 236.219.139.207:49162 SYN_RECV -less
複製代碼
上面是在LINUX系統中看到的,不少鏈接處於SYN_RECV狀態(在WINDOWS系統中是SYN_RECEIVED狀態),源IP地址都是隨機的(也多是同一個IP的不少SYN_RECV鏈接狀態),代表這是一種帶有IP欺騙的SYN***。
咱們也能夠經過下面的命令直接查看在LINUX環境下某個端囗的未鏈接隊列的條目數:
#netstat –atun | grep SYN_RECV | grep :80 | wc -l
複製代碼
顯示TCP端囗80的未鏈接數請求及個數,雖然還遠達不到系統極限,但應該引發管理員的注意。
5、SYN***防範技術
關於SYN***防範技術,人們研究得比較早。概括起來,主要有兩大類,一類是經過防火牆、路由器等過濾網關防禦,另外一類是經過加固TCP/IP協議棧防範.但必須清楚的是,SYN***不能徹底被阻止,咱們所作的是儘量的減輕SYN***的危害,除非將TCP協議從新設計。
1、過濾網關防禦
這裏,過濾網關主要指明防火牆,固然路由器也能成爲過濾網關。防火牆部署在不一樣網絡之間,防範外來非法***和防止保密信息外泄,它處於客戶端和服務 器之間,利用它來防禦SYN***能起到很好的效果。過濾網關防禦主要包括超時設置,SYN網關和SYN代理三種。
■ 網關超時設置:防火牆設置SYN轉發超時參數(狀態檢測的防火牆可在狀態表裏面設置),該參數遠小於服務器的timeout時間。當客戶端發送完SYN 包,服務端發送確認包後(SYN+ACK),防火牆若是在計數器到期時還未收到客戶端的確認包(ACK),則往服務器發送RST包,以使服務器從隊列中刪 去該半鏈接。值得注意的是,網關超時參數設置不宜太小也不宜過大,超時參數設置太小會影響正常的通信,設置太大,又會影響防範SYN***的效果,必須根據 所處的網絡應用環境來設置此參數。
■SYN 網關:SYN網關收到客戶端的SYN包時,直接轉發給服務器;SYN網關收到服務器的SYN/ACK包後,將該包轉發給客戶端,同時以客戶端的名義給服務 器發ACK確認包。此時服務器由半鏈接狀態進入鏈接狀態。當客戶端確認包到達時,若是有數據則轉發,不然丟棄。事實上,服務器除了維持半鏈接隊列外,還要 有一個鏈接隊列,若是發生SYN***時,將使鏈接隊列數目增長,但通常服務器所能承受的鏈接數量比半鏈接數量大得多,因此這種方法能有效地減輕對服務器的 ***。
■SYN 代理:當客戶端SYN包到達過濾網關時,SYN代理並不轉發SYN包,而是以服務器的名義主動回覆SYN/ACK包給客戶,若是收到客戶的ACK 包,代表這是正常的訪問,此時防火牆向服務器發送ACK包並完成三次握手。SYN代理事實上代替了服務器去處理SYN***,此時要求過濾網關自身具備很強 的防範SYN***能力。
2、加固tcp/ip協議棧
防範SYN***的另外一項主要技術是調整tcp/ip協議棧,修改tcp協議實現。主要方法有SynAttackProtect保護機制、SYN cookies技術、增長最大半鏈接和縮短超時時間等。tcp/ip協議棧的調整可能會引發某些功能的受限,管理員應該在進行充分了解和測試的前提下進行此項工做。
■ SynAttackProtect機制 (針對windows操做系統)
爲防範SYN***,win2000系統的tcp/ip協議棧內嵌了SynAttackProtect機制,Win2003系統也採用此機制。 SynAttackProtect機制是經過關閉某些socket選項,增長額外的鏈接指示和減小超時時間,使系統能處理更多的SYN鏈接,以達到防範 SYN***的目的。默認狀況下,Win2000操做系統並不支持SynAttackProtect保護機制,須要在註冊表如下位置增長 SynAttackProtect鍵值:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
複製代碼
當SynAttackProtect值(如無特別說明,本文提到的註冊表鍵值都爲十六進制)爲0或不設置時,系統不受SynAttackProtect保護。
當SynAttackProtect值爲1時,系統經過減小重傳次數和延遲未鏈接時路由緩衝項(route cache entry)防範SYN***。
當SynAttackProtect值爲2時(Microsoft推薦使用此值),系統不只使用backlog隊列,還使用附加的半鏈接指示,以此來處理更多的SYN鏈接,使用此鍵值時,tcp/ip的TCPInitialRTT、window size和可滑動窗囗將被禁止。
咱們應該知道,平時,系統是不啓用SynAttackProtect機制的,僅在檢測到SYN***時,才啓用,並調整tcp/ip協議棧。那麼系統 是如何檢測SYN***發生的呢?事實上,系統根據TcpMaxHalfOpen,TcpMaxHalfOpenRetried 和TcpMaxPortsExhausted三個參數判斷是否遭受SYN***。
TcpMaxHalfOpen 表示能同時處理的最大半鏈接數,若是超過此值,系統認爲正處於SYN***中。Win2000 server默認值爲100,Win2000 Advanced server爲500。
TcpMaxHalfOpenRetried定義了保存在backlog隊列且重傳過的半鏈接數,若是超過此值,系統自動啓動 SynAttackProtect機制。Win2000 server默認值爲80,Win2000 Advanced server爲400。
TcpMaxPortsExhausted 是指系統拒絕的SYN請求包的數量,默認是5。
若是想調整以上參數的默認值,能夠在註冊表裏修改(位置與SynAttackProtect相同)
■ SYN cookies技術
咱們知道,TCP協議開闢了一個比較大的內存空間backlog隊列來存儲半鏈接條目,當SYN請求不斷增長,並這個空間,導致系統丟棄SYN鏈接。爲使半鏈接隊列被塞滿的狀況下,服務器仍能處理新到的SYN請求,SYN cookies技術被設計出來。
SYN cookies應用於linux、FreeBSD等操做系統,當半鏈接隊列滿時,SYN cookies並不丟棄SYN請求,而是經過加密技術來標識半鏈接狀態。
在TCP實現中,當收到客戶端的SYN請求時,服務器須要回覆SYN+ACK包給客戶端,客戶端也要發送確認包給服務器。一般,服務器的初始序列號 由服務器按照必定的規律計算獲得或採用隨機數,但在SYN cookies中,服務器的初始序列號是經過對客戶端IP地址、客戶端端囗、服務器IP地址和服務器端囗以及其餘一些安全數值等要素進行hash運算,加 密獲得的,稱之爲cookie。當服務器遭受SYN***使得backlog隊列滿時,服務器並不拒絕新的SYN請求,而是回覆cookie(回覆包的 SYN序列號)給客戶端,若是收到客戶端的ACK包,服務器將客戶端的ACK序列號減去1獲得cookie比較值,並將上述要素進行一次hash運算,看 看是否等於此 cookie。若是相等,直接完成三次握手(注意:此時並不用查看此鏈接是否屬於backlog隊列)。
在RedHat linux中,啓用SYN cookies是經過在啓動環境中設置如下命令來完成:
# echo 1 > /proc/sys/net/ipv4/tcp_syncookies
複製代碼
注:也能夠經過修改其它參數,或者使用/proc/sys/net/ipv4/netfilter/ip_contrack_*
■ 增長最大半鏈接數(加大未鏈接隊列空間)
大量的SYN請求致使未鏈接隊列被塞滿,使正常的TCP鏈接沒法順利完成三次握手,經過增大未鏈接隊列空間能夠緩解這種壓力。固然backlog隊列須要佔用大量的內存資源,不能被無限的擴大。
WIN2000:除了上面介紹的TcpMaxHalfOpen, TcpMaxHalfOpenRetried參數外,WIN2000操做系統能夠經過設置動態backlog(dynamic backlog)來增大系統所能容納的最大半鏈接數,配置動態backlog由AFD.SYS驅動完成,AFD.SYS是一種內核級的驅動,用於支持基於 window socket的應用程序,好比ftp、telnet等。AFD.SYS在註冊表的位置:
HKLM\System\CurrentControlSet\Services\AFD\Parameters
複製代碼
EnableDynamicBacklog值爲1時,表示啓用動態backlog,能夠修改最大半鏈接數。
MinimumDynamicBacklog表示半鏈接隊列爲單個TCP端囗分配的最小空閒鏈接數,當該TCP端囗在backlog隊列的空閒鏈接小於此臨界值時,系統爲此端囗自動啓用擴展的空閒鏈接(DynamicBacklogGrowthDelta),Microsoft推薦該值爲20。
MaximumDynamicBacklog是當前活動的半鏈接和空閒鏈接的和,當此和超過某個臨界值時,系統拒絕SYN包,Microsoft推薦MaximumDynamicBacklog值不得超過2000。
DynamicBacklogGrowthDelta值 是指擴展的空閒鏈接數,此鏈接數並不計算在MaximumDynamicBacklog內,當半鏈接隊列爲某個TCP端囗分配的空閒鏈接小於 MinimumDynamicBacklog時,系統自動分配 DynamicBacklogGrowthDelta所定義的空閒鏈接空間,以使該TCP端囗能處理更多的半鏈接。Microsoft推薦該值爲10。
LINUX:Linux用變量tcp_max_syn_backlog定義backlog隊列容納的最大半鏈接數。在Redhat 7.3中,該變量的值默認爲256,在AS中,是1024。這個值是遠遠不夠的,一次強度不大的SYN***就能使半鏈接隊列佔滿。咱們能夠經過如下命令修改此變量的值:
# sysctl -w net.ipv4.tcp_max_syn_backlog="2048"
複製代碼
Sun Solaris Sun Solaris:用變量tcp_conn_req_max_q0來定義最大半鏈接數,在Sun Solaris 8中,該值默認爲1024,能夠經過add命令改變這個值:
# ndd -set /dev/tcp tcp_conn_req_max_q0 2048
複製代碼
HP-UX:HP-UX用變量tcp_syn_rcvd_max來定義最大半鏈接數,在HP-UX 11.00中,該值默認爲500,能夠經過ndd命令改變默認值:
#ndd -set /dev/tcp tcp_syn_rcvd_max 2048
複製代碼
■縮短超時時間
上文提到,經過增大backlog隊列能防範SYN***;另外減小超時時間也使系統能處理更多的SYN請求。咱們知道,timeout超時時間,也 即半鏈接存活時間,是系統全部重傳次數等待的超時時間總和,這個值越大,半鏈接數佔用backlog隊列的時間就越長,系統能處理的SYN請求就越少。爲 縮短超時時間,能夠經過縮短重傳超時時間(通常是第一次重傳超時時間)和減小重傳次數來實現。
Win2000第一次重傳以前等待時間默認爲3秒,爲改變此默認值,能夠經過修改網絡接口在註冊表裏的TcpInitialRtt註冊值來完成。重傳次數由TcpMaxConnectResponseRetransmissions 來定義,註冊表的位置是:
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
複製代碼
固然咱們也能夠把重傳次數設置爲0次,這樣服務器若是在3秒內還未收到ack確認包就自動從backlog隊列中刪除該鏈接條目。
LINUX:Redhat使用變量tcp_synack_retries定義重傳次數,其默認值是5次,總超時時間須要3分鐘。
# sysctl -w net.ipv4.tcp_synack_retries="0"
複製代碼
Sun Solaris Solaris: 默認的重傳次數是3次,總超時時間爲3分鐘,能夠經過ndd命令修改這些默認值。
綜合上述的方法:在linux下能夠經過修改/etc/ sysctl.conf,添加下列選項達到效果。
## add by geminis for syn crack
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog="2048"
net.ipv4.tcp_synack_retries="1"
複製代碼
更多設置參考:sysctl.conf
六.編寫bash腳本進行防範(個人方法是統計同一個IP的狀態包並處理)
#!/bin/sh
## 定義變量
MAX_TOTAL_SYN_RECV="1000"
MAX_PER_IP_SYN_RECV="20"
MARK="SYN_RECV"
PORT="80"
LOGFILE="/var/log/netstat_$MARK-$PORT"
LOGFILE_IP="/var/log/netstat_connect_ip.log"
DROP_IP_LOG="/var/log/netstat_syn_drop_ip.log"
## iptables初始化,拒絕非法包和不明狀態的包,容許請求包和已經鏈接的包進入
iptables -F -t filter
iptables -A INPUT -p TCP ! --syn -m state --state NEW -j DROP
iptables -A INPUT -p ALL -m state --state INVALID -j DROP
iptables -A INPUT -p ALL -m state --state ESTABLISHED,RELATED -j ACCEPT
## 初始化變量
if [ -z $MARK ];then
MARK="LISTEN"
fi
if [ -z $PORT ];then
SPORT="tcp"
else
SPORT=":$PORT"
fi
######################## end
## 保存netstat結果到指定記錄文件中便於分析
netstat -atun|grep $MARK|grep $SPORT 2>/dev/null >$LOGFILE
REPEAT_CONNECT_IP=`less $LOGFILE|awk '{print $5}'|cut -f1 -d ':'|sort|uniq -d |tee > $LOGFILE_IP`
## 若是IP記錄文件不爲空,則從原來的記錄文件中讀取記錄並添加規則
if [ -s $DROP_IP_LOG ];then
for i in `less $DROP_IP_LOG|awk '{print $1}'`;do
/sbin/iptables -A INPUT -p ALL -s $i -j DROP
done
fi
for i in `less $LOGFILE_IP`;do
## 統計同一個IP在在的SYN_RECV狀態
REPEAT_CONNECT_NUM=`grep $i $LOGFILE|wc -l`
## 若是超過了預設的同一個IP的鏈接數,就拒絕此IP的鏈接包進入
if [ $REPEAT_CONNECT_NUM -gt $MAX_PER_IP_SYN_RECV ];then
echo "$i $REPEAT_CONNECT_NUM" >> $DROP_IP_LOG
iptables -A INPUT -p ALL -s $i -j DROP
fi
done
## 統計全部狀態爲SYN_RECV狀態的數據包,若是數量超過預設,就重置狀態。
ALL_CONNECT=`uniq -u $LOGFILE|wc -l`
echo $ALL_CONNECT
## count repeat connections ,if the accout is large than default number,then drop packages
if [ $ALL_CONNECT -gt $MAX_TOTAL_SYN_RECV ];then
echo $ALL_CONNECT
exit
fi
複製代碼
修改iptables
iptables -A INPUT -p tcp --syn -m limit --limit 1/s -j ACCEPT
iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
echo 2048 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 1 > /proc/sys/net/ipv4/tcp_synack_retries
echo 1 > /proc/sys/net/ipv4/tcp_syn_retries
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
複製代碼
查詢某ip併發鏈接數
netstat -na|grep SYN|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -r
複製代碼
統計SYN_RECV
netstat -na |grep SYN_RECV |grep 80 |wc -l
複製代碼
查看各個狀態總數
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
複製代碼
sysctl內核( /etc/ sysctl.conf )
net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
net.ipv4.tcp_max_syn_backlog = 65536
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.ipv4.tcp_max_tw_buckets = 5000
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_mem = 196608 262144 393216
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 120
net.ipv4.ip_local_port_range = 1024 65535