[linux]如何使用IPSET和IPTABLES功能來預先過濾掉一些已知的惡意IP

雖然盡可能地消除對外服務開放的PORT,但是主機仍會有被fail2ban監控到一些惡意IP,用程式碼或方式在暴力拆解TRY可以登入的弱點掃描。
這個很煩人,但因為LOG有些測試的內容很有創意,腦袋不清晰會誤以為自己的主機怎麼會有這種帳號。

利用最近很夯的chatGPT,魔法溝通後目前找到一個應該是有效的方式。
網路上有一些專門維護的組織團體,會固定維護提供已知的惡意IP清單下載。
有些是免費的、有些是收費的。
不過就跟Pi-Hole或Adguard Home類似的功能,我們找到的免費IP清單來利用亦可。

目前透過的免費方案有這五個:
1. https://www.abuseipdb.com/ 這個AbuseIPDB可以免費註冊拿到API,但是每天有更新限制次數。
2. Emerging Threats的清單https://rules.emergingthreats.net/fwrules/emerging-Block-IPs.txt
3. FireHOL的清單https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
4. Blocklist.de的清單https://lists.blocklist.de/lists/all.txt
5. Spamhaus的清單https://www.spamhaus.org/drop/drop.txt
透過一個簡單的script指令和設定來定時下載更新檔案,然後合併處理移除彼此重複的IP值。
最後就會產出一個ip.blacklist檔案,隨時可以拿來利用。
PS. 截至目前為止,已知的IPV4惡意IP約快9萬個、IPV6約快3千個。

也許有人是純用iptables,或者firewalld延伸應用。
接下來script的範例檔案,是目前測試出來的可以用的做法。
首先,要先確認是不是都有安裝到這些套件:
sudo apt install ipset iptables netfilter-persistent ipset-persistent iptables-persistent

sudo nano banIPlist-jir.sh

撰寫下面的內容(下載):

#!/bin/bash
### 250406 with IPset mode to block mass IPs.
# 設定黑名單檔案儲放路徑和處理的暫存位置
BLACKLIST_FILE="/etc/fail2ban/ip.blacklist"
TEMP_FILE="/var/tmp/ip.blacklist.tmp"
# 日誌檔案的路徑和異常通知信的收件人
LOG_FILE="/var/log/iptables_blacklist_jir.log"
NOTIFY_EMAIL="FaultReceiveUser@on.the.net"
# ipset 名稱
SET_NAME="blacklist_jir"
SET_NAME_IPV6="blacklist_jir_ipv6"

echo "$(date '+%Y-%m-%d %H:%M:%S') starting... banIPlist-jir.sh ..." | tee -a $LOG_FILE

# 檢查是否帶入 --apply-ipset 參數
if [[ "$1" == "--apply-ipset" ]]; then
echo "只執行 ipset 規則應用到 iptables..." | tee -a $LOG_FILE
# 刪除舊的 IPSET 規則(如果存在)
for i in $(sudo iptables -L INPUT -n --line-numbers | grep $SET_NAME | awk '{print $1}' | sort -nr); do
sudo iptables -w -D INPUT $i | tee -a $LOG_FILE
done
for i in $(sudo ip6tables -L INPUT -n --line-numbers | grep $SET_NAME_IPV6 | awk '{print $1}' | sort -nr); do
sudo ip6tables -w -D INPUT $i | tee -a $LOG_FILE
done

# 套用 ipset 到 iptables 和 ip6tables
sudo iptables -w -I INPUT -m set --match-set $SET_NAME src -j DROP | tee -a $LOG_FILE
sudo ip6tables -w -I INPUT -m set --match-set $SET_NAME_IPV6 src -j DROP | tee -a $LOG_FILE
echo "完成 ipset 規則應用。" | tee -a $LOG_FILE

#### 選用的功能OPTIONAL:
echo "只執行 封鎖webmin port: 10000 規則應用到 iptables..." | tee -a $LOG_FILE
# 刪除舊的 封鎖webmin 規則(如果存在)到 iptables 和 ip6tables
for i in $(sudo iptables -L INPUT -n --line-numbers | grep 'tcp dpt:10000' | awk '{print $1}' | sort -nr); do
sudo iptables -w -D INPUT $i | tee -a $LOG_FILE | tee -a $LOG_FILE
done
#
for i in $(sudo ip6tables -L INPUT -n --line-numbers | grep 'tcp dpt:10000' | awk '{print $1}' | sort -nr); do
sudo ip6tables -w -D INPUT $i | tee -a $LOG_FILE | tee -a $LOG_FILE
done
# 套用 封鎖webmin 本機以外的連線 到 iptables 和 ip6tables
sudo iptables -w -A INPUT -p tcp -s 127.0.0.1 --dport 10000 -j ACCEPT | tee -a $LOG_FILE
sudo iptables -w -A INPUT -p tcp --dport 10000 -j REJECT | tee -a $LOG_FILE
#
sudo ip6tables -A INPUT -p tcp -s ::1 --dport 10000 -j ACCEPT | tee -a $LOG_FILE
sudo ip6tables -w -A INPUT -p tcp --dport 10000 -j REJECT | tee -a $LOG_FILE
echo "完成 封鎖webmin port: 10000 規則應用。" | tee -a $LOG_FILE
####

exit 0
fi

# 獲取當前外部浮動IP (IPv4 and IPv6)
CURRENT_IP=$(curl -s4 ifconfig.me)
CURRENT_IPv6=$(curl -s6 ifconfig.me)
# 驗證IP地址獲取是否成功
if [ -z "$CURRENT_IP" ] && [ -z "$CURRENT_IPv6" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 錯誤:無法獲取當前IP地址" | tee -a $LOG_FILE
exit 1
fi
# 檢查當前自己的IP是否在黑名單中
if grep -q "^$CURRENT_IP$" $BLACKLIST_FILE; then
SUBJECT="警告: 外部IP $CURRENT_IP 在黑名單中 detected"
BODY="您的外部IP地址 $CURRENT_IP 被列入黑名單。請檢查並處理。\n\n狀態: 列入黑名單"
echo -e "$BODY" | mail -s "$SUBJECT" "$NOTIFY_EMAIL"

# 移除當前IP地址
echo "$(date '+%Y-%m-%d %H:%M:%S') handle...外部IP $CURRENT_IP 在黑名單中 detected" | tee -a $LOG_FILE
grep -v "^$CURRENT_IP$" $BLACKLIST_FILE > $TEMP_FILE && mv $TEMP_FILE $BLACKLIST_FILE
fi

# 檢查當前自己的IPv6是否在黑名單中
if grep -q "^$CURRENT_IPv6$" $BLACKLIST_FILE; then
SUBJECT="警告: 外部IPv6 $CURRENT_IPv6 在黑名單中 detected"
BODY="您的外部IPv6地址 $CURRENT_IPv6 被列入黑名單。請檢查並處理。\n\n狀態: 列入黑名單"
echo -e "$BODY" | mail -s "$SUBJECT" "$NOTIFY_EMAIL"

# 移除當前IPv6地址
echo "$(date '+%Y-%m-%d %H:%M:%S') handle...外部IPv6 $CURRENT_IPv6 在黑名單中 detected" | tee -a $LOG_FILE
grep -v "^$CURRENT_IPv6$" $BLACKLIST_FILE > $TEMP_FILE && mv $TEMP_FILE $BLACKLIST_FILE
fi

# 清除舊規則和ipset集合(如果存在)
echo "$(date '+%Y-%m-%d %H:%M:%S') 清除舊的 IPv4 和 IPv6 規則和 ipset 集合..." | tee -a $LOG_FILE
# 刪除舊的 IPSET 規則(如果存在)
for i in $(sudo iptables -L INPUT -n --line-numbers | grep $SET_NAME | awk '{print $1}' | sort -nr); do
sudo iptables -w -D INPUT $i | tee -a $LOG_FILE
done
for i in $(sudo ip6tables -L INPUT -n --line-numbers | grep $SET_NAME_IPV6 | awk '{print $1}' | sort -nr); do
sudo ip6tables -w -D INPUT $i | tee -a $LOG_FILE
done

# 刪除firewall-cmd: IPv4 and IPv6 規則
echo "將 ipset 集合 刪除 firewalld ..." | tee -a $LOG_FILE
sudo firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -m set --match-set $SET_NAME src -j DROP | tee -a $LOG_FILE
sudo firewall-cmd --direct --remove-rule ipv6 filter INPUT 0 -m set --match-set $SET_NAME_IPV6 src -j DROP | tee -a $LOG_FILE

# 檢查並刪除已存在的 ipset 集合
echo "$(date '+%Y-%m-%d %H:%M:%S') 檢查並刪除已存在的 ipset 集合..." | tee -a $LOG_FILE
if sudo ipset list $SET_NAME > /dev/null 2>&1; then
sudo ipset destroy $SET_NAME | tee -a $LOG_FILE
echo "$(date '+%Y-%m-%d %H:%M:%S') 刪除ipset集合 $SET_NAME" | tee -a $LOG_FILE
fi
if sudo ipset list $SET_NAME_IPV6 > /dev/null 2>&1; then
sudo ipset destroy $SET_NAME_IPV6 | tee -a $LOG_FILE
echo "$(date '+%Y-%m-%d %H:%M:%S') 刪除ipset集合 $SET_NAME_IPV6" | tee -a $LOG_FILE
fi

# 創建新的 ipset 集合來處理已知近10萬筆封鎖IP
echo "$(date '+%Y-%m-%d %H:%M:%S') 創建新的 IPv4 和 IPv6 ipset 集合..." | tee -a $LOG_FILE
sudo ipset create $SET_NAME hash:ip hashsize 262144 maxelem 100000 | tee -a $LOG_FILE
sudo ipset create $SET_NAME_IPV6 hash:ip family inet6 hashsize 32768 maxelem 100000 | tee -a $LOG_FILE

# 讀取黑名單中的每個 IP 並根據其類型添加到 ipset 集合中
echo "$(date '+%Y-%m-%d %H:%M:%S') 開始添加 IP 地址到 ipset 集合..." | tee -a $LOG_FILE
IPV4_ADDRESSES=()
IPV6_ADDRESSES=()

while read -r ip; do
# 跳過空行
if [[ -z "$ip" ]]; then
continue
fi
# 檢查是否為 IPv6 地址
if [[ "$ip" =~ : ]]; then
# 添加 IPv6 地址到列表
IPV6_ADDRESSES+=($ip)
else
# 添加 IPv4 地址到列表
IPV4_ADDRESSES+=($ip)
fi
done < "$BLACKLIST_FILE" # 批量添加 IPv4 地址到 ipset 集合 for ip in "${IPV4_ADDRESSES[@]}"; do sudo ipset add $SET_NAME $ip echo "$(date '+%Y-%m-%d %H:%M:%S') 添加 IPv4 地址到 ipset: $ip" | tee -a $LOG_FILE done # 批量添加 IPv6 地址到 ipset 集合 for ip in "${IPV6_ADDRESSES[@]}"; do sudo ipset add $SET_NAME_IPV6 $ip echo "$(date '+%Y-%m-%d %H:%M:%S') 添加 IPv6 地址到 ipset: $ip" | tee -a $LOG_FILE done # 刪除舊的 IPSET 規則(如果存在) for i in $(sudo iptables -L INPUT -n --line-numbers | grep $SET_NAME | awk '{print $1}' | sort -nr); do sudo iptables -w -D INPUT $i | tee -a $LOG_FILE done for i in $(sudo ip6tables -L INPUT -n --line-numbers | grep $SET_NAME_IPV6 | awk '{print $1}' | sort -nr); do sudo ip6tables -w -D INPUT $i | tee -a $LOG_FILE done # 將 ipset 集合應用到 iptables 和 ip6tables echo "將 ipset 集合應用到 iptables 和 ip6tables..." | tee -a $LOG_FILE sudo iptables -w -I INPUT -m set --match-set $SET_NAME src -j DROP | tee -a $LOG_FILE sudo ip6tables -w -I INPUT -m set --match-set $SET_NAME_IPV6 src -j DROP | tee -a $LOG_FILE ### echo "將 ipset 集合應用到 firewalld ..." | tee -a $LOG_FILE sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m set --match-set $SET_NAME src -j DROP | tee -a $LOG_FILE sudo firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -m set --match-set $SET_NAME_IPV6 src -j DROP | tee -a $LOG_FILE ### # show status in the end echo "$(date '+%Y-%m-%d %H:%M:%S') iptables -L INPUT -v -n | grep $SET_NAME" | tee -a $LOG_FILE sudo ipset list $SET_NAME | grep "Header: family inet hashsize" | tee -a $LOG_FILE sudo ipset list $SET_NAME | grep "Number of entries" | tee -a $LOG_FILE echo "$(date '+%Y-%m-%d %H:%M:%S') iptables -L INPUT -v -n | grep $SET_NAME_IPV6" | tee -a $LOG_FILE sudo ipset list $SET_NAME_IPV6 | grep "Header: family inet hashsize" | tee -a $LOG_FILE sudo ipset list $SET_NAME_IPV6 | grep "Number of entries" | tee -a $LOG_FILE # echo "$(date '+%Y-%m-%d %H:%M:%S') ip6tables -L INPUT -v -n | grep $SET_NAME_IPV6" | tee -a $LOG_FILE sudo iptables -L INPUT -v -n | grep $SET_NAME | tee -a $LOG_FILE sudo ip6tables -L INPUT -v -n | grep $SET_NAME_IPV6 | tee -a $LOG_FILE # sudo netfilter-persistent save sudo ipset-persistent save echo "$(date '+%Y-%m-%d %H:%M:%S') Finished ... banIPlist-jir.sh ..." | tee -a $LOG_FILE exit 0

存檔離開。

#修改可執行
sudo chmod +x ./banIPlist-jir.sh
#執行,這個筆數越大,整體執行時間會越久。
sudo ./banIPlist-jir.sh

最後,上面的檔案如果執行完成、也正常運作。
我們讓它遇到重開機時,先預先載入復原這個防護狀態。要執行備份和功能啟用。
#設定存檔
sudo netfilter-persistent save
sudo ipset-persistent save
#或者這樣存檔
sudo dpkg-reconfigure ipset-persistent
sudo dpkg-reconfigure iptables-persistent
#啟用和檢查
sudo systemctl enable netfilter-persistent
sudo systemctl start netfilter-persistent
sudo systemctl status netfilter-persistent

然後,有必要好用的話,可以寫到crontab,固定間隔就更新新的黑名單IP。
另外,我有寫特別的參數值,--apply-ipset是讓iptables設定值意外清空的時候,可以預載回來。
可以用這兩個指令來查看:
sudo iptables -L INPUT -v -n
sudo ip6tables -L INPUT -v -n

延伸參考REF:
https://dhtar.com/make-ipset-and-iptables-configurations-persistent-in-debianubuntu.html
https://ishm.idv.tw/archives/556 使用 ipset 及 firewalld 做黑名單管理
https://lyt0112.pixnet.net/blog/post/218037040 利用 ipset 封禁大量 IP

Be the first to reply

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

請輸入下列驗證碼計算後阿拉伯數字 (Translate it, if not Taiwanese to post reply) *