Ubuntu系統開啟 ufw 防火牆之後,iptables -A 和 -I的差異

今天在用 iptables 設定每個IP限制幾個連線時,來回好幾次怎麼設定都不能正常運作,正在納悶到底是怎麼一回事時,我把 -A 的參數改成 -I 之後竟然正常了。所以打算追根究柢看看到底哪裡出了什麼問題了。我們先說說這個命令好了,

iptables -A INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 -j REJECT

一個簡單的 iptables 命令,限制每個 IP 只能 10 個 HTTP 連線,超過就丟棄封包不理它。無奈怎麼都不會正常運作,索性改成

iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 -j REJECT

嘿,竟然正常了。根據 iptables 語法,-A代表是Append附加在既有規則上,-I則是代表Insert添加在最前面,所以我就把整個 iptables 規則 dump 出來看看

# iptables-save > ~/rules

一看規則,明白了,雖然兩行的命令是一樣的,但順序不一樣。一個在 ufw 前面,一個在 ufw 後面。

-A INPUT -p tcp -m tcp --dport 80 -m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-sa
(上面的規則是 -I添加進來的)
...
...
...
-A INPUT -j ufw-before-logging-input
-A INPUT -j ufw-before-input
-A INPUT -j ufw-after-input
-A INPUT -j ufw-after-logging-input
-A INPUT -j ufw-reject-input
-A INPUT -j ufw-track-input
-A INPUT -p tcp -m tcp --dport 80 -m connlimit --connlimit-above 10 --connlimit-mask 32 --connlimit-sa
(上面的規則是 -A附加進來的)
...
...

我們知道 iptables 運作規定是由上往下執行,很顯然的,如果採用 -I,因為是添加在最前面,所以運作規則會在 ufw 之前。反之如果採用 -A,那麼附加的規則會在 ufw 之後。但是 ufw 之前已經設定

# ufw allow 80

所以按照 iptables 執行順序,只要是 80 port 的都會被 ufw 允許,所以 -A 添加的規則根本不會執行到,那當然運作就不正常了。而 -I 的命令則在 ufw 之前,所以才能先過濾掉,然後才交給 ufw 判斷,唉,浪費了不少時間。

CubieTruck簡易式阻擋DDoS防禦方式

DDoS是一種討厭的攻擊方式,駭客會在短時間內利用建立新連線方式阻擋他人連線的一種攻擊手法。這種攻擊手法相當難防禦,殊不見各大Server常常碰到此類型跳板式的DDoS攻擊,所以這裡用iptables做一個最簡易的防禦方式。

iptables -N WEB_SRV_DOS
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j WEB_SRV_DOS
iptables -A WEB_SRV_DOS -p tcp --syn -m multiport --dports 80,443 -m recent --rcheck --second 20 --hitcount 100 -j LOG --log-prefix "[Possible DOS Attack]"
iptables -A WEB_SRV_DOS -p tcp --syn -m multiport --dports 80,443 -m recent --rcheck --second 20 --hitcount 100 -j REJECT
iptables -A WEB_SRV_DOS -p tcp --syn -m multiport --dports 80,443 -m recent --set
iptables -A WEB_SRV_DOS -p tcp -m multiport --dports 80,443 -j ACCEPT

上面這段會把80/443(HTTP/HTTPS)Port新連線記錄下,最近20秒內如果想要建立連線超過100次,則會記錄下來並且丟棄封包進而阻擋DoS,因為  hitcount 超過 20,所以請參考這一篇文章來加大 xt_recent 的數值,以方便偵測。

如何限制CubieTruck對某個IP對HTTP Port只能有一定量的連線數目

CubieTruck是一台很小的伺服器,裡面的配備與資源相當陽春,所以經不起很多人同時連線,更遑論要阻擋DDoS了,所以我打算要用 iptables 來限制某個IP對HTTP/HTTPS Port只能有限定數量的連線,超過這個數目就丟棄封包不理會,算是一種最陽春的DDoS的阻擋了吧!

HTTP 80 Port,只要同一個IP超過10個連線就丟棄封包。

iptables -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 10 -j REJECT

HTTPS 443 Port,只要同一個IP超過10個連線就丟棄封包。

iptables -I INPUT -p tcp --dport 443 -m connlimit --connlimit-above 10 -j REJECT

但如果你的 Apache 服務器掛載很多種引擎,例如 ownCloud私有雲,常用來上傳和下載檔案,那這個數字 10 要自己拿捏好,不要阻擋了自己合法連線而拖慢速度。

另外,還有一點必須考量的是,這個被限制的IP位址可能是某個Proxy Server的IP位址,意味著Proxy Server後面可能有很多的電腦在後面,那麼10個連線就有點太少了。

在 Ubuntu 下如何增大 iptables 的 rt_recent 記錄表格大小

最近在研究如何使用 iptables 限制每個 IP 位址每分鐘可以連線多少次,以避免有人利用DDOS進行服務阻斷攻擊。但是發現不是出現錯誤訊息(使用 dmesg 觀看錯誤訊息),就是根本無法工作正常,錯誤訊息如下:

xt_recent: hitcount (200) is larger than packets to be remembered (20)

在網路上查了一下發現原來系統 iptables 也是有限制的,例如 Ubuntu 作業系統預設值是只能記錄最近的 100 個 IP 位址,而每個 IP 只能記錄最近的 20 筆記錄,所以你要 iptables 記錄最近 200 筆資料已經遠遠超出它可以記錄的預設值 20 筆了。而這些數值都在 /sys/module/xt_recent/parameters 目錄底下的,ip_list_tot (記錄最近幾個 IP位址),和 ip_pkt_list_tot(每個IP位址記錄最近的幾個封包)。

/sys/module/xt_recent/parameters/ip_list_tot = 100 --> 所以只能記錄最近 100 個 IP 位址
/sys/module/xt_recent/parameters/ip_pkt_list_tot = 20 --> 所以只能記錄每個IP位址最近 20 個封包

如果要更改這些設定,我找了很久,因為Linux版本很多,我尚無一個明確的方法,更糟糕的是這兩個虛擬檔案預設值只能讀取,不能寫入。所以還必須更改其寫入權限,所以我把它寫到 /etc/rc.local ,讓系統一開機時就可以更改。

# nano /etc/rc.local

在檔案尾部增加

chmod 600 /sys/module/xt_recent/parameters/ip_list_tot
chmod 600 /sys/module/xt_recent/parameters/ip_pkt_list_tot
echo "200" > /sys/module/xt_recent/parameters/ip_list_tot
echo "200" > /sys/module/xt_recent/parameters/ip_pkt_list_tot

這樣每次開機時就可以使 iptables 記錄 200 個 IP 位址,每個 IP 位址可以記錄 200 個封包記錄,但是這肯定會增加記憶體用量以及 CPU 的負載,所以副作用還不得而知,先試試看。建議各位不要設定太大!

我有看過核心 Kernel 編譯時的一些參數,這兩個數值不要超過 255,不然可能導致系統崩潰。而且此方法只能適用在 Ubuntu,其他的版本尚無驗證過!

如何防止WordPress暴力式登入攻擊

WordPress很容易遭受暴力式攻擊來試探密碼,其實也不只WordPress,所有的服務都怕,倒不是因為密碼強度不夠,而是怕這種無由來的暴力式攻擊會拖垮系統效能。像是 SSH 我取消了密碼登入,採用金鑰,而且一分鐘內登入不得超過三次,很快地暴力式攻擊就大幅減少了。

對於這種暴力式攻擊,如果第一時間發現,管理者可以採用 iptables 立刻把它給禁止連線,語法:

iptables -I INPUT -s 11.22.33.44 -j DROP
iptables -I OUTPUT -d 11.22.33.44 -j DROP

這鐵定立竿見影!但是如果你剛好不在身邊呢?我想到一個方法,就是根據上一篇文章提到的 如何幫Apache某個目錄加上帳號密碼保護,這次我們幫 wp-login.php 檔案加上密碼,這樣登入動作就會有兩次不同密碼防護,我相信暴力連線也可以大幅減少。

先到 wordpress 的目錄底下編輯 .htaccess 檔案,

# nano /var/www/wordpress/.htaccess

然後在這個檔案後面添上保護片段如下,

<Files wp-login.php>
AuthUserFile /etc/apache2/apache2.passwd
AuthName "Private access"
AuthType Basic
require user linaro
</Files>

這麼一來,想要登入執行 wp-login.php 時又得多一道密碼,我相信很多現成破解的程式就不管用了,而且兩道不同密碼,應該很夠用吧!

還有一種攻擊是專門試探 admin 密碼,即便 WordPress 已經取消管理者帳號非得 admin 了,但還是有很多機器人會來試探 admin 密碼,我們可以在你的佈景主題下的 functions.php 底下加入下面程式以避免:

add_filter( 'wp_authenticate', 'wpjam_no_admin_user' );
function wpjam_no_admin_user($user){
  if($user == 'admin'){
  exit;
  }
}

add_filter('sanitize_user', 'wpjam_sanitize_user_no_admin',10,3);
function wpjam_sanitize_user_no_admin($username, $raw_username, $strict){
  if($raw_username == 'admin' || $username == 'admin'){
  exit;
  }
  return $username;
}

這樣如果想要用 admin 登入 WordPress,登入畫面會變成空白頁。

在Ubuntu下iptables 下次開機套用上次規則

上一篇我們說到利用 iptables 來防止SSH/POP3暴力攻擊竊取你系統密碼,這方法運作的很好,但有一點小瑕疵。就是 iptables 在下次系統重開機時,並不會記錄上次規則。所以你每次開機就得重新手動輸入一次。我們先做一個小實驗,首先我們輸入剛剛 iptables 禁止暴力攻擊的命令(如果有輸入過請不要再輸入一次,會有副作用,也不好刪除)。

#iptables -I INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --update --seconds 60 --hitcount 3 -j REJECT
#iptables -I INPUT 2 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --set

然後看看目前 iptables 的規則,利用 22 這個 Port號碼關鍵字濾掉一些雜七雜八的設定。

#iptables -nvL | grep "22"

你應該可以看到類似這樣轉譯過給 iptable 的設定

18 864 REJECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW recent: UPDATE seconds: 60 hit_count: 3 name: ssh side: source reject-with icmp-port-unreachable
37 1812 tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22 state NEW recent: SET name: ssh side: source

然後 reboot 重新開再輸入一次 iptables -nvL | grep “22”,是不是發現剛剛的設定不見了。沒錯,系統並不會幫你記錄下來,所以下次重新開機時, iptables 的規則又重新來一次了。所以我們必須把這個規則先給紀錄在某個地方,然後在開機時把它給還原回來。我們要用 iptables-save (紀錄)和 iptables-restore(還原)這兩個指令。首先先記錄在 /etc/iptables.rules (紀錄檔案名稱可以自取,不限定)

#iptables-save > /etc/iptables.rules

你可以嘗試編輯這個檔案,內容應該是像 sendmail.cf 這種天書吧,那就別管它了。只要注意權限是否正確及可。

#chown root.root /etc/iptables.rules
#chmod 644 /etc/iptables.rules

然後到 /etc/network/目錄下找 /etc/network/interface 這個檔案,這是有關網路介面連結上或是失去連線的設定檔,所以只要有連線,開機時一定會讀取這個檔案的。使用你慣用的編輯器來編輯一下,到檔案尾端加上這些資訊。

# iptables
pre-up iptables-restore < /etc/iptables.rules

這行命令的意思就是告訴系統當某個網路介面連結上時,就用 iptables-restore把剛剛設定的/etc/ iptables.rules 給還原回去。編輯完之後,重新開機檢查看看是否剛剛設定的 iptables 規則已經套用了呢?(必須要有網路連結上)

如何在 Ubuntu 下避免 SSH/POP3 暴力攻擊

每天檢查 /var/log/auth.log 時,總會看到很多人想要登入這台 CubieTruck(真不明白意圖為何,不就一台小CubieTruck),雖說我已經做了下面保護了

  1. 採用 SSH 金鑰登入,而非一般密碼登入
  2. 嚴禁 root 登入
  3. 限制 IP 位址登入

但總是有那麼多無聊的人想要用暴力攻擊的方式進入試探你的密碼,之前找了很多防止暴力攻擊的方法(用 iptables的方式,而不是用 fail2ban),都不見成效。所以昨晚 Google 一晚,終於找到了,而且還不難。假定你的 SSH Port 是預設的 22的話,用 root 帳號輸入

#iptables -I INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --update --seconds 60 --hitcount 3 -j REJECT
#iptables -I INPUT 2 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --set

這樣就可以在每分鐘內企圖登入(不管登入成功與否)第四次以上,連線都不會建立成功。事實上我也想過是否會有人無聊到一直連線,讓我自己也登不進去呢?畢竟它可不認 IP,且不會管是否事後登入成功。但事實上機率很小的。原因

  1. 我一直都會有一個以上的登入 SSH,而這個方法不會影響到已經登入的 SSH。我可以利用這個 SSH 來禁止那個無聊 IP 登入
  2. 我的 SSH 還有另外一個非 22 Port,而這個 Port 只能內網登入,外網在IP分享器中是沒有開放的。我可以採用 VPN 先登入內網,然後再禁止那個無聊IP進入。
  3. 如果真的有心DDoS你的伺服器,除了這個方法,它還有很多方法可以使用,大可不必大費周章只攻擊你的 SSH。

還有另外一個Port也有可能,就是收信 POP3 Port 110/IMAP Port 143,它也可以用來暴力攻擊試探你的密碼,所以保險起見,也把 POP3 Port 110 /IMAP Port 143一併加入吧!

#iptables -I INPUT 1 -p tcp --dport 110 -m state --state NEW -m recent --name pop3 --update --seconds 60 --hitcount 3 -j REJECT
#iptables -I INPUT 2 -p tcp --dport 110 -m state --state NEW -m recent --name pop3 --set
#iptables -I INPUT 1 -p tcp --dport 143 -m state --state NEW -m recent --name imap --update --seconds 60 --hitcount 3 -j REJECT
#iptables -I INPUT 2 -p tcp --dport 143 -m state --state NEW -m recent --name imap --set

順道附上利用 iptables 禁止 a.b.c.d 的 IP登入你的 CubieTruck 的方法:

#iptables -I INPUT -s 11.22.33.44 -j DROP
#iptables -I OUTPUT -d 11.22.33.44 -j DROP

CubieTruck SSH SYN Flood 分析

相對於 HTTP,SSH的SYNC Flood也相對比較簡單,因為SSH一旦建立就很少斷線,不像一個網頁裡面含有十幾個連線,如果沒有使用Keep-alive機制,那就意味著要開啟十幾個HTTP連線來取得資料。

所以沒有懸念地,我們還是請出 iptables 大神來,SSH 的 Port 假定是預設的 22,至於每分鐘幾次連線,我想依照個人喜好去修改吧,反正不是常常建立 SSH 連線的,相對的這個方法可以擋掉一些用字典式攻擊密碼的連線。

#iptables -I INPUT 1 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --update --seconds 60 --hitcount 3 -j REJECT
#iptables -I INPUT 2 -p tcp --dport 22 -m state --state NEW -m recent --name ssh --set

上面兩行和之前的http寫法很相像,只是port換成SSH 22 port而已。告訴 iptables 每分鐘如果建立超過 4個新連線(含SYN Flag)就不要處理了,這樣就可以擋掉SSH SYN Flood。

這一講,我們提到很多SYN Flood的攻擊方式,包括HTTP/SSH SYNC Flood,以及基本的防禦方法。這算結束了嘛?我想這才是開始而已吧!

使用 iptables 禁止某個網路IP進入

近來有一些人會不斷地想要進入系統,希望他們是出自於學習的角度。不過為了保護系統,所以用 iptables 來禁止某些 ip 進入我的CubieTruck,這些 ip address 可以從 /var/log/auth.log 裡面得知,假定是 11.22.33.44,使用 iptables 來禁止他們進出系統

iptables -I INPUT -s 11.22.33.44 -j DROP
iptables -I OUTPUT -d 11.22.33.44 -j DROP

然後儲存規則,以利下次開機也可以使用

iptables-save > /etc/iptables-rules

如果想要查看目前規則,可以使用

iptables -L

如果要取消某個規則,則可以使用

iptables -D INPUT 剛剛看到的順序號碼

不要忘記修改完,要用 iptables-save 存檔喔。

寫一個 script 可以簡化這個流程

#! /bin/sh
echo "Ban IP for " $1
iptables -I INPUT -s $1 -j DROP
iptables -I OUTPUT -d $1 -j DROP