2016年4月4日 星期一

fail2ban: 新手老手 root 網管都要練的金鐘罩

fail2ban 標誌 只要你所管理的 linux 伺服器掛在網路上, 就一定要學會使用 fail2ban 保護它。 fail2ban 讓你用最少的力氣同時對 ssh 跟 apache 施以最基本的防護、 抵擋暴力攻擊和收割機騷擾。 本教學文主要針對新手; 但後半所提供的一些小程式,對老手可能也有用處。

先前介紹的 denyhosts 2008 年推出最後更新; fail2ban 則還持續在更新, 所以我就改用 fail2ban 了。 本文介紹的是 0.8.6 (跟 0.8.4) 版。

如果你先前已經手動設定 iptables 防火牆, 且網路速度因為規則太多而變慢, 可以考慮把舊的設定刪掉。 (不刪也沒關係啦。) 先把舊的設定備份起來: iptables-save > ~/iptables.rules.v4 這樣萬一以後改變心意, 還可以用 iptables-restore 還原。 然後照著 這一段 把 iptables 清乾淨。 (那一整篇很值得從頭開始看!)

為了加強防護, 還可以 把 ssh 設定成滴水不漏

[2017/5/14] 另一個很值得幫伺服器做的保護措施是 定期自動更新 ( 簡體中文)。

一、 基本設定

根據 手冊, 客製設定應該寫在 /etc/fail2ban/jail.local 裡面。 這個檔裡面沒提到的, 就用 /etc/fail2ban/jail.conf 的預設值。 所以 不必 把整個 jail.conf 複製到 jail.local。 貼入短短幾句即可:

[DEFAULT]
ignoreip = 127.0.0.1/8 999.999.999.0/24 888.888.888.0/24

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 5
findtime = 600
bantime  = 1200

其中 ignoreip 那句是白名單 -- 這些好朋友不論怎麼攻擊你的伺服器, 都還是一律放行 :-) 而 [sshd] 那一節是從 /etc/fail2ban/jail.conf 裡面抄過來改的。 也就是說, 即使沒有在 jail.local 裡面加上這一節, sshd 本來預設就會受到保護。 上面表示要求 fail2ban 定時檢查 /var/log/auth.log , 如果在 10 分鐘內 (findtime) 發現同一 IP 企圖連線 5 次 (maxRetry), 就把這個 IP 封鎖 20 分鐘 (banTime)。

注意: 在採用 systemd 的系統上, 請在 [DEFAULT] 那一節加上 backend = systemd, 並且把所有的 logpath 刪掉。 那一句。 詳見 這個問答

改好之後重新啟動: service fail2ban restart

二、 測試確認

fail2ban-client status 應該會看到 jail list 清單裡已經出現了 sshd, 表示目前已有 sshd 一個服務受到 fail2ban 的保護。

再來, 開一個新的命令列視窗專門查看記錄檔。 後面一直要持續觀察, 請不要用 ^C 打斷這個視窗; 資料太亂時可以按幾次 Enter 鍵。

  • init 系統用戶請下: tail -f /var/log/fail2ban.log
  • systemd 系統用戶請下: journalctl -f -u ssh

回到原來的命令列視窗, 試著把自己 ban 掉:

  • 如果你人就在伺服器 (叫它 Z 好了) 電源開關旁邊, 請從另一部電腦 (叫它 X 好了) 連續試著故意用錯誤密碼 ssh 連線登入 Z。 (攻擊!)
  • 如果伺服器在遠方, 請先從手邊的電腦 X 用 ssh 登入另一部伺服器 Y, 再確認可以從 Y 登入 Z, 最後才另開一個分頁, 從 X 直接攻擊 Z -- 否則 Z 把 X 列入黑名單 (封鎖掉) 之後, 你就哭哭了! (還好啦, 等二十分鐘就自動解鎖了。)

注意剛剛觀察記錄檔的視窗。 它的反應可能會有點 lag, 因為它隔一段時間才會去檢查記錄檔, 然後才會封鎖 X。

一定要測試到自己被封鎖為止才算數。 我曾在 proxmox 上面架設 debian 8 的 OpenVZ container, 成功地啟動 fail2ban, log 檔也開始動起來了; 但就是無法阻擋入侵。 後來不知道什麼時候, container 的 fail2ban 突然就好了。 (因為 host 重開嗎?)

三、 查看及解鎖

fail2ban-client status ssh 查看一下目前有哪些 IP 被封鎖、 過去總共有多少 IP 被封鎖。

如果把自己的 X 鎖住了... 歐歐~~ 希望你還能夠從 Y 登入 Z。 然後下: iptables -L --line-numbers 查出 「想刪除的規則的序號」 nn, 再用 iptables -D fail2ban-ssh nn 刪除那條規則。 注意 1: 小心別刪到 fail2ban-ssh 自己的通則。 萬一刪到了, 就 service fail2ban restart 重新啟動吧。 注意 2: 刪除一條規則之後, 下面的會遞補上來, 所以後面的規則序號都會減一。 從 HowtoForge 看到的。

四、 寄信通知

你可以叫 fail2ban 用 e-mail 向你報告它封鎖了哪些 IP。 不過, 這兩天實驗很久的心得是: 不要設定 e-mail 通知比較安靜啦, 還可以直接略過這一節。 如果你一定要設的話...

請先手動寄 e-mail, 確認至少 root 可以寄信給自己。

然後在設定檔裡加一句 action = %(action_mwl)s 就可以了。 但是建議先別這麼設! 我設定 apache2 防護 (下詳) 並且重新啟動 fail2ban 沒多久, 我自己就被 DNS 伺服器給封鎖掉了 :-( 因為 action_mwl 會用 whois 指令 (透過 DNS?) 去查看到底是哪些邪惡 IP 在攻擊你。 當時正好有很多邪惡的 IP 在攻擊我, 於是 fail2ban 一口氣問了 DNS 很多問題, 然後 DNS 以為我是來亂的, 就直接把苦主我當成邪惡 IP 封鎖掉了~~

首先在 jail.local 的 "[DEFAULT]" 那一節加上這兩句:

action_ml = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
            %(mta)s-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"]
action = %(action_ml)s

(若是較舊的 0.8.4 版, 要把 ", chain="%(chain)s" 刪掉)

這是從 jail.conf 裡面抄過來修改過的。 意思是: 凡是觸發 fail2ban 時, 就採取 action_ml 行動; 所謂 action_ml 行動, 就是先採取 banaction 行動, 再採取 {mta}-lines 行動。 這裡的 {mta} 會代值進去: 像我的 jail.conf 裡面設定 mta = sendmail 所以 %(mta)s-lines 會代換成 sendmail-lines。 於是它會去找 action.d/sendmail-lines 這個檔案。 如果你的 mta 不是 sendmail, 以下需要新增的檔名請自行更改。

當然, 原先 fail2ban 套件裡面並沒有附 action.d/sendmail-lines 這個檔案。 這是我從 action.d/sendmail-whois-lines.conf 改來的。 基本上就是把查詢 whois 那句刪掉而已。

重新啟動: service fail2ban restart 如果出現很長的 python 錯誤訊息, 請看最後一句。 如果沒有錯誤訊息但也沒有成功, 那有可能是讀不到它要的檔案 (已把 action.d/sendmail-lines 剪貼回去了嗎? 檔名正確嗎?) 請先改試其他系統內建的 action 看看。

另外, 可以用 destemail=你@公司.com 設定收件人地址。

五、 自建 filter 阻擋深層路徑騷擾

去年所發現的 收割機騷擾 apache 事件, 後來又出現其他新的騷擾 IP, 於是我的手動防禦當然又逐漸失效了。 而且認真想想, 這些 IP 好像又不是單純的收割機。 因為它們沒在抓有意義的頁面, 而是一直在抓一些很深的、 不存在的頁面 -- 以下取自我的 /var/log/apache2/access.log:

40.77.167.21 - - [02/Apr/2016:05:35:03 +0800] "GET /~ckhung/index.php/a/a/b/al/b/al/b/al/b/svg/dl/b/tk/b/dg/c/s/b/pr/ HTTP/1.1" 200 4096 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
40.77.167.21 - - [02/Apr/2016:06:35:24 +0800] "GET /~ckhung/index.php/a/a/b/al/b/al/b/al/b/svg/p/algotutor/b/svg/b/al/mm/c/l/ HTTP/1.1" 200 4097 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
40.77.167.21 - - [02/Apr/2016:08:50:14 +0800] "GET /~ckhung/index.php/a/a/b/al/b/al/b/al/b/svg/p/algotutor/s/c/v/c/mentor/c/p/toy/ HTTP/1.1" 200 4100 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"

讀過 這篇 我才知道有一種攻擊叫做 apache overflow; 我開始懷疑這些攻擊者是想要找 apache 的漏洞? 可是 fail2ban 預設的 filter.d/apache-overflows.conf 看起來弱弱的, 沒什麼效果。 沒關係, 有了 fail2ban, 凡是可以 「用 regexp 從某個服務的 log 檔裡面觀察出規則」 這種類型的攻擊, 現在我都知道該如何對付了。

請先檢查你的伺服器跟我有沒有相同的遭遇:

cd ~/public_html ; find . -type f | sed 's#[^/]##g' | sort | uniq -c
perl -ne 'print "$1\n" if m#GET ((/[^/\s]*)+) #' /var/log/apache2/access.log | sed 's#[^/]##g' | sort | uniq -c
perl -ne 'print if m#GET ((/[^/\s]*){20,}) #' /var/log/apache2/access.log

第一句話會產生一個簡單的統計數據, 顯示你的個人網頁目錄底下深淺各種層次 (/abc/def/xyz) 的目錄各有多少。 第二句話會產生另一個簡單的統計數據, 看看你的 log 檔裡面有多少筆 「很深」 (GET 後面那串包含很多個 /) 的記錄。 第三句話則會撈出所有 20 層以上的記錄。

想要阻擋這類流量, 請先把 apache-deepurls.conf 貼到 /etc/fail2ban/filter.d 底下。 其中 failregex = <HOST>.*GET\s+(/[^/\s]*){9} 這一句最後面的數字, 決定超過幾層目錄的記錄將觸發封鎖。 再用 fail2ban-regex /var/log/apache2/access.log /etc/fail2ban/filter.d/apache-deepurls.conf 這個指令測試我寫的規則對你的記錄檔有沒有幫助。 改一下大括弧裡的數字, 甚至改一下 regexp, 直到測試滿意為止。 然後在 /etc/fail2ban/jail.local 裡面加上這幾句:

[apache-deepurls]
enabled  = true
port     = http
filter   = apache-deepurls
logpath  = /var/log/apache2/access.log
maxretry = 2

如果沒有加上 findtime、 bantime、 maxretry 這幾句, 就會沿用 [DEFAULT] 那一節 (ssh、 apache-deepurls、 ... 等等所有封鎖規則共用) 的預設值。

請再次確認你的 action 並沒有設定要去查詢 whois (乾脆暫時先設定成 action = %(action_)s 就好) 最後重新啟動 fail2ban, 馬上感受到你的流量在幾分鐘之內大幅下降 :-) 隔一陣子再查看 fail2ban-client status apache-deepurls, 會看到已有很多騷擾 IP 被封鎖。

六、 延長封鎖累犯之一: cron

有些 IP 很白目, 被阻擋半小時一小時之後, 又不斷地回來騷擾。 雖然頻率已大幅降低, 還是很煩。 於是決定用 cron 掃描 fail2ban 的 log 檔, 把累犯寫入 /etc/hosts.deny。

請把 repeated-fail2ban.pl 放到 /etc/fail2ban (或隨便哪裡都可以)。 要先安裝一個 perl 模組才能使用我寫的這支小程式: apt-get install libdatetime-perl。 可以這樣執行: /etc/fail2ban/repeated-fail2ban.pl -d 8 -g 4 -i 6 它會印出過去 8 天之內被 fail2ban 封鎖的 (1) 可疑子網域 (包含 4 個或更多被封鎖 IP) (2) 累犯 IP (被封鎖 6 次或更多), 類似這樣:

# repeated-fail2ban: [20160327-20160404 g=4 i=6]  125.212.232.[4](18) 157.55.39.[4](130) 221.203.142.[5](22) 62.4.15.46(13) 207.46.13.[4](42) 40.77.167.[6](237)
ALL: 125.212.232. 157.55.39. 221.203.142. 62.4.15.46 207.46.13. 40.77.167.

IP 最後一碼的方括弧內是同一子網域的惡意 IP 數; 小括弧則是該 IP 或該子網域被封鎖的總次數。 已列入子網域群組的 IP 就不另外單獨列出。 第二列是適合貼到 /etc/hosts.deny 的內容。 第一列則是提供較詳細資訊的註解。 如果使用 -f apache2 這個選項, 那麼它就改產生適用於 apache2 設定檔的語法格式。 注意: 我的程式只查看 /var/log/fail2ban.log.1 跟 /var/log/fail2ban.log, 所以實際上最多只能看到過去 7-13 天的記錄。

再把 repeated-fail2ban.sh 抓回去並改名放到 /etc/cron.daily/repeated-fail2ban 還要 chmod a+x /etc/cron.daily/repeated-fail2ban 才會生效。 它每天呼叫上述 perl 程式檢查累犯及共犯, 然後用 /etc/hosts.deny 跟 /etc/apache2/conf.d/repeated-fail2ban 來列出較長時間 (數天) 的黑名單。

使用這招的好處是: 對 ssh 服務而言, 你可以一口氣封鎖整個網段, 讓 fail2ban 比較輕鬆。 缺點是: /etc/hosts.deny 只適用於 xinetd 所啟用的服務 (例如 ssh); 像 apache2 就不適用, 所以必須另外處理。 而且 apache2 的 deny 設定運作的層次不是低層的 iptables, 所以 fail2ban 還是會看到攻擊者 (還是很忙)、 攻擊者還是會看到 403 forbidden (而不是完全連不上)。

七、 延長封鎖累犯之二: 第二層 fail2ban

fail2ban 的規則, 一般檢查和封鎖的範圍大約是幾十分鐘到幾小時。 那如果用 fail2ban 檢查自己的 log 檔呢? 它就能夠比較宏觀地看到哪些惡意 IP 一直不死心, 就像上節所說的, 被封鎖一段時間之後, 又捲土重來, 一天重複個幾十次。 那就再寫一個 filter 把這些 IP 封鎖久一點囉。

請把 f2b-ad.conf 抓回去放在 /etc/fail2ban/filter.d 底下, 並且用 fail2ban-regex /var/log/fail2ban.log /etc/fail2ban/filter.d/f2b-ad.conf 測試看看對你的資料有沒有效果。 (注意: 這個 filter 只查看 (第五節所談的) apache-deepurl 所抓到的惡意 IP。) 若有效果, 就可以在 jail.local 裡面加上這一段:

[f2b-ad]
enabled  = true
port     = http
filter   = f2b-ad
logpath  = /var/log/fail2ban.log
findtime = 86400
bantime  = 604800
maxretry = 4

重新啟動 fail2ban 之後, 凡是過去 24 小時之內曾被重複封鎖 4 次的 IP, 都會被自動封鎖一週。

如果也想對 ssh 做相同的事, 可以另外寫一個類似的 filter。

八、 proxmox

[2017/5/13] 請把 這個過濾規則檔 照抄放到 /etc/fail2ban/filter.d/ 底下, 並且參考 這個設定檔 修改你的 jail.local。 詳見 這一篇

九、 結語

網管 (還有秘書、社群分析師、...) 一定要學 字串樣版 regexp 啦! 這是超有用、 C/P 值超高的學習投資。

「自建 filter 阻擋深層路徑騷擾」 這一節雖然成功地擋下大部分這類的攻擊, 但我還是不懂攻擊者的目的是什麼。 更奇怪的是, 那個 IP 竟然是微軟的。 微軟是很賤沒錯 (例如 挾持電腦廠商、 加速 「舊電腦垃圾化」) 但也應該不至於這麼低級吧? 而我也很難想像潰客竟然可以控制那麼多個微軟的 IP。 找不到合理的解釋, 只好到 到 Apache Lounge 發問, 若有新的心得再回來這裡補。

對付累犯的那兩節, 我也才剛開始採用。 長期效果如何, 有待觀察。

春假好幾天都在寫這篇, 比寫學術論文還認真! (握拳) 但我覺得網管們分享防禦知識/經驗, 是一件很有意義的事。 如果你也遇到深層路徑騷擾, 或是其他奇怪、 fail2ban 沒有 filter 可以處理的問題, 請留言分享一下 log 檔裡面的幾句, 讓大家核對一下是否有來自相同 IP 的類似攻擊。 甚至也可以寄略長一段的 log 內容 給我, 我可以幫你寫 filter。 讓我們一起透過知識經驗分享來讓攻擊者更常撞牆 :-)

十、更多 fail2ban 中文教學文

  1. Vixual: 用 Fail2Ban 防範暴力破解 (SSH、vsftp、dovecot、sendmail)
  2. 清華大學 計算機與通訊中心: fail2ban 教學
  3. 「就是資安 Simply Security」: [工具介紹] 利用 fail2ban 避免密碼遭受暴力破解法(錯誤嘗試)
  4. 「網管人 Netadmin」: fail2ban主機型入侵偵測 即時防護網路服務

1 則留言:

  1. 如果使用密鑰登陸 還用擔心這種事情嗎?

    回覆刪除