给 ImmortalWrt 装个“捕鼠夹”:一键部署自动蜜罐防火墙 (NFTables版)
前情提要:开放7088端口是为方便自己在外看iptv电视的,无奈太多吊毛扫描到了自己看不说还分享出去,全国各地的叼毛都来连。与其被动挨打,不如主动出击。
思路由作者本人构想,细节完成全靠AI!
今天分享一个AI制作的 ImmortalWrt 专用蜜罐防火墙脚本。它的逻辑非常简单粗暴:谁敢碰我的诱捕端口,我就直接把它的 IP 拉黑。
🛡️ 脚本功能亮点
- 全自动诱捕:监听指定端口(默认 TCP/UDP 7088),一旦有人扫描或尝试连接,立即触发报警。
- 秒级封禁:Python 后台脚本实时监控日志,发现非法探测 IP 毫秒级拉黑。
- NFTables 原生支持:专为新版 OpenWrt (Firewall4) 设计,无需安装 iptables,性能更高。
- 白名单保护:自动识别内网 IP,支持手动添加白名单,防止把自己锁在门外。
- 一键管理:提供类似老毛子固件的终端管理菜单,支持启动、停止、查看日志、管理黑白名单。
- 无残留卸载:脚本自带“自毁”功能,不想用了可以一键彻底卸载,不留垃圾。
⚠️ 部署前必读(非常重要)
在执行脚本之前,必须关闭 OpenWrt 的“网络加速”功能。
因为开启硬件/软件分流后,流量会绕过 CPU 直接转发,导致防火墙无法抓取到诱捕包,脚本将失效。
- 进入路由器后台 -> 网络 -> 防火墙。
- 找到 “路由/NAT 分流” 或 “Turbo ACC 网络加速”。
- 取消勾选 “软件流量分流” 和 “硬件流量分流”。
- 点击 保存并应用。
🚀 一键部署命令
无需手动创建文件,连接 SSH 后,复制下面整段命令并回车,即可自动完成环境安装、脚本写入、服务配置和防火墙规则注入。
cat << 'INSTALL_EOF' > /tmp/install_honeypot.sh
#!/bin/bash
# ================= 变量定义 =================
PY_FILE="/root/main.py"
SVC_FILE="/etc/init.d/autoban"
MGR_FILE="/root/manager.sh"
BAN_LIST="/etc/ban_blacklist.txt"
WHITE_LIST="/etc/ban_whitelist.txt"
PORT_FILE="/etc/ban_port.conf"
LINK_BIN="/usr/bin/ban"
# 默认端口
DEFAULT_PORT="7088"
echo "-----------------------------------------------"
echo "正在安装 蜜罐防火墙 (全功能最终版)..."
echo "特性: 自动断连 / 本机豁免 / 自动刷新 / 历史日志"
echo "-----------------------------------------------"
# 0. 初始化配置
if [[ ! -f "$PORT_FILE" ]]; then
echo "$DEFAULT_PORT" > "$PORT_FILE"
fi
[[ ! -f "$BAN_LIST" ]] && touch "$BAN_LIST"
[[ ! -f "$WHITE_LIST" ]] && touch "$WHITE_LIST"
# 1. 安装依赖 (关键:包含 conntrack)
echo "[1/6] 安装系统依赖..."
opkg update
for pkg in python3 bash nano conntrack; do
if ! opkg list-installed | grep -q "^$pkg"; then
echo "安装 $pkg ..."
opkg install "$pkg"
fi
done
# 2. 写入核心 Python 脚本
echo "[2/6] 部署核心防护引擎..."
cat << 'EOF' > "$PY_FILE"
import subprocess, re, os, sys, time, threading
BLACKLIST_FILE = "/etc/ban_blacklist.txt"
WHITELIST_FILE = "/etc/ban_whitelist.txt"
PORT_FILE = "/etc/ban_port.conf"
LOG_PREFIX = "BAN_ME"
def get_target_port():
try:
if os.path.exists(PORT_FILE):
with open(PORT_FILE, 'r') as f:
return f.read().strip()
except: pass
return "7088"
TARGET_PORT = get_target_port()
def load_set(filepath):
if not os.path.exists(filepath): return set()
try:
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
return set(line.strip() for line in f if line.strip())
except: return set()
# === 获取本机所有 IP (防自杀) ===
def get_self_ips():
ips = set()
try:
cmd = "ip -4 addr | grep 'inet ' | awk '{print $2}' | cut -d/ -f1"
res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=True)
if res.stdout:
for line in res.stdout.splitlines():
ip = line.strip()
if ip: ips.add(ip)
except: pass
return ips
def is_whitelisted(ip):
# 1. 基础内网段
if ip.startswith("192.168.") or ip.startswith("10.") or ip.startswith("127."): return True
# 2. 用户自定义白名单
if ip in load_set(WHITELIST_FILE): return True
# 3. 本机 IP (动态)
if ip in get_self_ips(): return True
return False
# 核心封禁动作
def execute_ban(ip):
# 删除旧规则(防报错) -> 插入新规则 -> 切断连接
subprocess.run(f"nft delete rule inet fw4 input ip saddr {ip} drop", shell=True, stderr=subprocess.DEVNULL)
subprocess.run(f"nft insert rule inet fw4 input ip saddr {ip} drop", shell=True, stderr=subprocess.DEVNULL)
subprocess.run(f"conntrack -D -s {ip}", shell=True, stderr=subprocess.DEVNULL)
def block_ip(ip, current_blacklist):
if is_whitelisted(ip): return
if ip not in current_blacklist:
print(f"🚫 [封禁] 捕获 IP: {ip}")
if ip not in load_set(BLACKLIST_FILE):
try:
with open(BLACKLIST_FILE, 'a') as f: f.write(f"{ip}\n")
except: pass
current_blacklist.add(ip)
# 只要触发就强制执行封禁动作,确保规则生效
execute_ban(ip)
def scan_active_connections(current_blacklist):
try:
port = get_target_port()
cmd = f"netstat -nt | grep ':{port}'"
res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, text=True)
if res.stdout:
for line in res.stdout.splitlines():
parts = line.split()
for p in parts:
if ":" in p and p.count('.') == 3:
ip = p.split(':')[0]
if ip not in ["0.0.0.0", "127.0.0.1"]:
block_ip(ip, current_blacklist)
except: pass
def periodic_scan(current_blacklist):
while True:
scan_active_connections(current_blacklist)
time.sleep(30)
def monitor_logs(current_blacklist):
print(f"正在启动日志监控 (端口 {TARGET_PORT})...")
proc = subprocess.Popen(['logread', '-f'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
pat = re.compile(r'SRC=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
while True:
line = proc.stdout.readline()
if not line: break
if LOG_PREFIX in line:
m = pat.search(line)
if m: block_ip(m.group(1), current_blacklist)
if __name__ == "__main__":
sys.stdout.reconfigure(line_buffering=True)
print("正在初始化规则...")
current_blacklist = load_set(BLACKLIST_FILE)
count = 0
for ip in current_blacklist:
if not is_whitelisted(ip):
execute_ban(ip)
count += 1
print(f"✅ 已恢复 {count} 条历史封禁规则")
t = threading.Thread(target=periodic_scan, args=(current_blacklist,), daemon=True)
t.start()
try: monitor_logs(current_blacklist)
except KeyboardInterrupt: pass
EOF
chmod +x "$PY_FILE"
# 3. 写入系统服务
echo "[3/6] 配置系统守护进程..."
cat << 'EOF' > "$SVC_FILE"
#!/bin/sh /etc/rc.common
START=99
USE_PROCD=1
SCRIPT_PATH="/root/main.py"
PYTHON_BIN="/usr/bin/python3"
start_service() {
procd_open_instance
procd_set_param command "$PYTHON_BIN" "$SCRIPT_PATH"
procd_set_param respawn 3600 5 0
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
EOF
chmod +x "$SVC_FILE"
/etc/init.d/autoban enable
# 4. 写入管理菜单 (集成所有管理功能)
echo "[4/6] 生成智能管理菜单..."
cat << 'EOF' > "$MGR_FILE"
#!/bin/bash
SERVICE="autoban"
FILE_B="/etc/ban_blacklist.txt"
FILE_W="/etc/ban_whitelist.txt"
PORT_FILE="/etc/ban_port.conf"
[[ ! -f "$FILE_B" ]] && touch "$FILE_B"
[[ ! -f "$FILE_W" ]] && touch "$FILE_W"
[[ ! -f "$PORT_FILE" ]] && echo "7088" > "$PORT_FILE"
do_svc() { /etc/init.d/$SERVICE $1; sleep 1; }
get_st() { if pgrep -f "main.py">/dev/null; then echo -e "\033[32m运行中\033[0m"; else echo -e "\033[31m已停止\033[0m"; fi; }
get_port() { cat "$PORT_FILE"; }
# 全量刷新:重启防火墙+重启服务
full_reload() {
echo "-----------------------------------"
echo "🔄 正在重载系统防火墙 (应用修改)..."
/etc/init.d/firewall restart >/dev/null 2>&1
echo "🔄 正在重启蜜罐服务..."
/etc/init.d/$SERVICE restart >/dev/null 2>&1
echo "✅ 状态已刷新。"
sleep 1
}
change_port() {
local old_port=$(get_port)
echo "当前蜜罐端口: $old_port"
read -p "请输入新的端口号 (1-65535): " new_port
if [[ "$new_port" =~ ^[0-9]+$ ]] && [ "$new_port" -ge 1 ] && [ "$new_port" -le 65535 ]; then
echo "$new_port" > "$PORT_FILE"
uci set firewall.honeypot_tcp.dest_port="$new_port"
uci set firewall.honeypot_udp.dest_port="$new_port"
uci commit firewall
full_reload
echo "✅ 端口已修改为 $new_port"
read -p "按回车继续..."
else
echo "❌ 无效的端口号!"
sleep 1
fi
}
manage_list_ui() {
local file=$1
local name=$2
while true; do
clear
echo "=== $name 管理 (自动刷新防火墙) ==="
if [[ ! -s "$file" ]]; then echo "(列表为空)"; else awk '{print NR". " $0}' "$file"; fi
echo "----------------------------"
echo "1. 添加 IP"
echo "2. 删除 IP (按序号)"
echo "3. 手动编辑 (Nano)"
echo "0. 返回"
echo "----------------------------"
read -p "请选择: " opt
case $opt in
1) read -p "输入IP: " nip; [[ -n "$nip" ]] && { echo "$nip" >> "$file"; full_reload; };;
2) read -p "输入序号: " num; [[ "$num" =~ ^[0-9]+$ ]] && { sed -i "${num}d" "$file"; full_reload; };;
3) nano "$file"; full_reload;;
0) break;;
esac
done
}
# 优化的日志查看:先看历史,再看实时
view_logs() {
clear
echo "=== 拦截日志查看器 ==="
echo "正在读取最近 20 条历史记录..."
echo "----------------------------------------------------"
logread | grep -E "BAN_ME|python3" | tail -n 20
echo "----------------------------------------------------"
echo "📜 以上是历史记录 | 📡 以下是实时监控 (Ctrl+C 退出)"
echo "----------------------------------------------------"
trap 'return' SIGINT
logread -f | grep -E "python3|BAN_ME"
trap - SIGINT
}
uninstall_all() {
read -p "确认卸载请输入 'yes': " c
if [[ "$c" == "yes" ]]; then
/etc/init.d/$SERVICE stop
/etc/init.d/$SERVICE disable
rm -f /etc/init.d/$SERVICE /root/main.py /root/manager.sh /usr/bin/ban
uci delete firewall.honeypot_tcp
uci delete firewall.honeypot_udp
uci commit firewall
/etc/init.d/firewall restart
echo "已卸载"
exit 0
fi
}
while true; do
clear
echo "=== 蜜罐防火墙 (端口: $(get_port)) ==="
echo "状态: $(get_st)"
echo "---------------------------"
echo "1. 启动服务"
echo "2. 停止服务"
echo "3. 重启服务"
echo "4. 查看日志 (历史+实时)"
echo "5. 黑名单管理 (自动刷新)"
echo "6. 白名单管理 (自动刷新)"
echo "7. 修改端口"
echo "9. 卸载"
echo "0. 退出"
read -p "选项: " c
case $c in
1) do_svc start ;;
2) do_svc stop ;;
3) do_svc restart ;;
4) view_logs ;;
5) manage_list_ui "$FILE_B" "黑名单" ;;
6) manage_list_ui "$FILE_W" "白名单" ;;
7) change_port ;;
9) uninstall_all ;;
0) exit ;;
esac
done
EOF
chmod +x "$MGR_FILE"
ln -sf "$MGR_FILE" "$LINK_BIN"
# 5. 防火墙配置
echo "[5/6] 配置防火墙规则..."
CURRENT_PORT=$(cat "$PORT_FILE")
uci delete firewall.honeypot_tcp 2>/dev/null
uci delete firewall.honeypot_udp 2>/dev/null
uci set firewall.honeypot_tcp=rule
uci set firewall.honeypot_tcp.name='Honeypot-TCP'
uci set firewall.honeypot_tcp.src='wan'
uci set firewall.honeypot_tcp.proto='tcp'
uci set firewall.honeypot_tcp.dest_port="$CURRENT_PORT"
uci set firewall.honeypot_tcp.target='LOG'
uci set firewall.honeypot_tcp.log_prefix='BAN_ME: '
uci set firewall.honeypot_udp=rule
uci set firewall.honeypot_udp.name='Honeypot-UDP'
uci set firewall.honeypot_udp.src='wan'
uci set firewall.honeypot_udp.proto='udp'
uci set firewall.honeypot_udp.dest_port="$CURRENT_PORT"
uci set firewall.honeypot_udp.target='LOG'
uci set firewall.honeypot_udp.log_prefix='BAN_ME: '
uci commit firewall
/etc/init.d/firewall restart
# 6. 启动服务
echo "[6/6] 启动防护服务..."
/etc/init.d/autoban restart
echo "-----------------------------------------------"
echo "✅ 安装成功!输入 ban 即可管理。"
echo "-----------------------------------------------"
INSTALL_EOF
# 执行安装
bash /tmp/install_honeypot.sh && rm -f /tmp/install_honeypot.sh🎮 使用说明
- 呼出菜单:在 SSH 终端输入 ban 即可进入管理界面。
- 验证效果:
- 关闭手机 WiFi,使用 4G/5G 流量。
- 在手机浏览器访问
http://你的公网IP:7088。 - 在电脑 SSH 终端输入
ban-> 选择4. 查看实时日志。 - 你应该会看到 IP 被自动拉黑的提示。
- 如何解封自己?如果因为误操作导致自己无法连接 SSH,请重启路由器(拔电源),然后连接内网(192.168.x.x)进入后台,在 ban 菜单中编辑黑名单删除自己的 IP。
⚙️ 技术原理 (How it works)
这个系统由三个部分协同工作:
- 诱捕 (Trap):利用
nftables在路由器的 input 链头部插入一条规则,任何访问 7088 端口的 TCP/UDP 流量都会被标记BAN_ME:并记录到系统日志。 - 监控 (Monitor):后台运行的 Python 脚本通过
logread -f实时读取系统日志,使用正则匹配BAN_ME:关键词。 - 执行 (Action):一旦匹配到 IP,脚本会立即调用
nft insert ... drop命令将该 IP 封禁,并将其写入永久黑名单文件。