外观
入侵检测部署与蜜罐诱捕实战
约 1982 字大约 7 分钟
网络安全技术入侵检测IDS/IPSSnort
2026-05-17
本课核心
IDS(入侵检测系统,发现异常并告警)负责“看见攻击”,IPS(入侵防御系统,检测后阻断)负责“拦下攻击”,蜜罐负责“诱导攻击者暴露行为”。本课用 Snort 3 离线分析 pcap,再用 Cowrie 蜜罐记录一次 SSH 弱口令尝试。
课堂红线
所有检测、爆破和蜜罐操作只允许在本机 Kali WSL 与课堂 Docker 容器中进行。不要监听校园网、不要诱捕真实公网攻击者、不要对非授权系统运行爆破工具。
故事引入:防火墙之后还要看见什么
防火墙能决定端口是否开放,但无法解释“某个合法端口上的请求是不是攻击”。例如 HTTP 80/18080 端口对外开放时,/?file=/etc/passwd 和 SQL 注入字符串都可能通过端口访问到服务。IDS 的价值就是把这些“看起来只是流量”的字节还原成安全事件。
🦹♂️ 攻击者
🔀 核心交换机
🖥️ 真实服务器
🛡️ IDS 设备
旁路监听,只看不拦
旁路监听,只看不拦
选择部署模式,点击开始演示...
理论基础:IDS、IPS 与蜜罐
| 技术 | 位置 | 动作 | 风险 |
|---|---|---|---|
| IDS | 旁路监听或离线 pcap | 告警、记录、取证 | 不能直接阻断攻击 |
| IPS | 串联在主链路 | 告警并丢包/阻断会话 | 误报会影响业务 |
| 蜜罐 | 诱饵系统 | 记录登录、命令、样本 | 必须隔离,不能连接真实资产 |
本课使用 Snort 3 的离线 pcap 检测方式:先用 tcpdump 抓到证据,再用 snort -r 读取 pcap。这样规则写错也不会影响网络链路,适合教学。
工具准备
当前 Kali WSL 已带有 snort、tcpdump、hydra、docker。Cowrie 不是系统命令,而是 Docker 镜像;本机没有预缓存时需要先拉取。Docker Hub 在本环境访问超时,因此使用可访问的镜像前缀。
snort --version | sed -n "1,8p"
command -v tcpdump
command -v hydra
command -v docker
# 仅当本机没有 Cowrie 镜像时执行
docker pull docker.1ms.run/cowrie/cowrie:latest真实输出:
,,_ -*> Snort++ <*-
o" )~ Version 3.12.1.0
'''' By Martin Roesch & The Snort Team
http://snort.org/contact#team
/usr/bin/tcpdump
/usr/bin/hydra
/usr/bin/docker输出解释: 当前环境是 Snort++ 3.x,不是旧版 Snort 2.x。因此本课命令使用 /etc/snort/snort.lua 和 -R local.rules,不再使用旧式 snort.conf。
实战一:编写 Snort 规则
rm -rf /tmp/lesson12
mkdir -p /tmp/lesson12/www
printf "lesson12 ids target\n" > /tmp/lesson12/www/index.html
cat > /tmp/lesson12/local.rules <<'EOF'
alert icmp any any -> any any (msg:"ICMP Ping Detected"; sid:1000001; rev:1;)
alert tcp any any -> any 18080 (msg:"ETC PASSWD Access Attempt"; content:"/etc/passwd"; sid:1000002; rev:1;)
alert tcp any any -> any 18080 (msg:"SQL Injection Attempt"; content:"OR%20"; sid:1000003; rev:1;)
alert tcp any any -> any 4444 (msg:"Possible Reverse Shell Port 4444"; sid:1000004; rev:1;)
EOF
cat /tmp/lesson12/local.rules真实输出:
alert icmp any any -> any any (msg:"ICMP Ping Detected"; sid:1000001; rev:1;)
alert tcp any any -> any 18080 (msg:"ETC PASSWD Access Attempt"; content:"/etc/passwd"; sid:1000002; rev:1;)
alert tcp any any -> any 18080 (msg:"SQL Injection Attempt"; content:"OR%20"; sid:1000003; rev:1;)
alert tcp any any -> any 4444 (msg:"Possible Reverse Shell Port 4444"; sid:1000004; rev:1;)输出解释: Snort 规则由规则头和规则选项组成。alert tcp any any -> any 18080 表示检测任意来源到 18080 端口的 TCP 流量;content:"/etc/passwd" 表示在载荷中匹配攻击特征;sid 是规则编号。SQL 注入请求经过 URL 编码后空格变成 %20,所以规则匹配 OR%20,而不是直接匹配空格。
匹配进度: 0 / 3
🛡️ Snort 防御规则
alerttcp any any -> any 18080 (msg:"WebShell Detect"; content:"whoami"; sid:10001; rev:1;)
📦 捕获的网络数据包
[头部] Protocol: TCP | Src: 1.2.3.4:5543 | Dst: 10.0.0.5:18080
[应用层载荷 (Payload)]
GET /shell.php?cmd=whoami HTTP/1.1
Host: 10.0.0.5
GET /shell.php?cmd=whoami HTTP/1.1
Host: 10.0.0.5
👉 等待分析。点击“下一步”开始逐层匹配。
实战二:生成攻击流量并保存 pcap
先启动本机 HTTP 靶机,再抓取两个攻击请求。WSL2 中本机 HTTP 流量实际出现在 loopback0,ICMP Ping 在 lo,所以分开抓取。
cd /tmp/lesson12/www
python3 -m http.server 18080 --bind 127.0.0.1 >/tmp/lesson12/http.log 2>&1 &
echo $! > /tmp/lesson12/http.pid
sudo tcpdump -i loopback0 -w /tmp/lesson12/http.pcap -c 42 "(tcp port 18080 or tcp port 4444)" &
echo $! > /tmp/lesson12/http-capture.pid
curl --noproxy "*" -s "http://127.0.0.1:18080/?file=/etc/passwd" >/dev/null
curl --noproxy "*" -s "http://127.0.0.1:18080/vulnerabilities/sqli/?id=1'%20OR%20'1'='1&Submit=Submit" >/dev/null
nc -zv 127.0.0.1 4444 >/tmp/lesson12/nc.log 2>&1 || true
wait "$(cat /tmp/lesson12/http-capture.pid)"
sudo tcpdump -i lo -w /tmp/lesson12/icmp.pcap -c 2 icmp &
echo $! > /tmp/lesson12/icmp-capture.pid
ping -c 1 127.0.0.1 >/tmp/lesson12/ping.log
wait "$(cat /tmp/lesson12/icmp-capture.pid)"查看 pcap 中的关键载荷:
tcpdump -A -nn -r /tmp/lesson12/http.pcap \
| grep -E "GET /|/etc/passwd|OR|Host:"真实输出:
GET /?file=/etc/passwd HTTP/1.1
Host: 127.0.0.1:18080
GET /?file=/etc/passwd HTTP/1.1
Host: 127.0.0.1:18080
GET /vulnerabilities/sqli/?id=1'%20OR%20'1'='1&Submit=Submit HTTP/1.1
Host: 127.0.0.1:18080
GET /vulnerabilities/sqli/?id=1'%20OR%20'1'='1&Submit=Submit HTTP/1.1
Host: 127.0.0.1:18080输出解释: 同一请求在 loopback0 上会出现出入方向的重复记录,这不影响检测。关键是 pcap 中确实存在 /etc/passwd 和 OR%20 两类攻击特征。
实战三:用 Snort 3 离线检测
snort -c /etc/snort/snort.lua \
-R /tmp/lesson12/local.rules \
-r /tmp/lesson12/http.pcap \
-A alert_fast -q
snort -c /etc/snort/snort.lua \
-R /tmp/lesson12/local.rules \
-r /tmp/lesson12/icmp.pcap \
-A alert_fast -q真实输出:
05/18-11:11:43.300670 [**] [1:1000002:1] "ETC PASSWD Access Attempt" [**] [Priority: 0] {TCP} 127.0.0.1:45048 -> 127.0.0.1:18080
05/18-11:11:43.310099 [**] [1:1000003:1] "SQL Injection Attempt" [**] [Priority: 0] {TCP} 127.0.0.1:45056 -> 127.0.0.1:18080
05/18-11:11:44.385144 [**] [1:1000001:1] "ICMP Ping Detected" [**] [Priority: 0] {ICMP} 127.0.0.1 -> 127.0.0.1
05/18-11:11:44.385153 [**] [1:1000001:1] "ICMP Ping Detected" [**] [Priority: 0] {ICMP} 127.0.0.1 -> 127.0.0.1输出解释:
| 字段 | 含义 |
|---|---|
05/18-11:11:43.300670 | 告警发生时间 |
[1:1000003:1] | GID:SID:Rev,表示生成器、规则编号和规则修订 |
"SQL Injection Attempt" | 规则中的 msg 告警消息 |
{TCP} | 触发告警的协议 |
127.0.0.1:45056 -> 127.0.0.1:18080 | 源地址端口到目标地址端口 |
ICMP 产生两条告警,是因为本机回环上同时看到了 echo request 和 echo reply。HTTP 告警说明 Snort 成功从 pcap 载荷中匹配到了 /etc/passwd 与 OR%20。
实战四:部署 Cowrie 蜜罐
Docker Hub 在本环境访问超时,因此这里使用已验证可拉取的镜像地址。
docker rm -f cowrie-honeypot 2>/dev/null || true
docker pull docker.1ms.run/cowrie/cowrie:latest
docker run -d --name cowrie-honeypot \
-p 2222:2222 \
docker.1ms.run/cowrie/cowrie:latest
sleep 8
docker ps --filter "name=cowrie" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
ss -tlnp | grep 2222真实输出:
NAMES STATUS PORTS
cowrie-honeypot Up 8 seconds 0.0.0.0:2222->2222/tcp, [::]:2222->2222/tcp, 2223/tcp
LISTEN 0 4096 0.0.0.0:2222 0.0.0.0:* users:(("docker-proxy",pid=2375,fd=7))
LISTEN 0 4096 [::]:2222 [::]:* users:(("docker-proxy",pid=2384,fd=7))输出解释: cowrie-honeypot 容器已经运行,宿主机 2222 端口被映射到容器 2222 端口。课堂只在本机访问这个端口,不对公网暴露。
实战五:模拟弱口令尝试并查看蜜罐日志
sshpass 当前环境未安装,本课改用 Kali 自带的 hydra 产生 SSH 弱口令尝试。
cat > /tmp/lesson12-passwords.txt <<'EOF'
admin
123456
password
root
toor
EOF
hydra -l root -P /tmp/lesson12-passwords.txt \
-s 2222 -t 1 -W 3 -f 127.0.0.1 ssh
docker logs --since 2m cowrie-honeypot 2>&1 \
| grep -E "New connection|login attempt|authenticated|connection lost" \
| sed -n "1,80p"真实输出(Hydra):
Hydra v9.6 (c) 2023 by van Hauser/THC & David Maciejak
[DATA] attacking ssh://127.0.0.1:2222/
[2222][ssh] host: 127.0.0.1 misc: (null) login: root password: admin
[STATUS] attack finished for 127.0.0.1 (valid pair found)
1 of 1 target successfully completed, 1 valid password found真实输出(Cowrie 日志节选):
2026-05-18T03:14:30+0000 [cowrie.ssh.factory.CowrieSSHFactory] New connection: 172.17.0.1:47570 (172.17.0.2:2222) [session: 39ff00776968]
2026-05-18T03:14:30+0000 [cowrie.ssh.userauth.HoneyPotSSHUserAuthServer#debug] b'root' trying auth b'none'
2026-05-18T03:14:30+0000 [HoneyPotSSHTransport,1,172.17.0.1] login attempt [b'root'/b'admin'] succeeded
2026-05-18T03:14:30+0000 [cowrie.ssh.userauth.HoneyPotSSHUserAuthServer#debug] b'root' authenticated with b'password'
2026-05-18T03:14:30+0000 [HoneyPotSSHTransport,1,172.17.0.1] avatar root logging out
2026-05-18T03:14:30+0000 [cowrie.ssh.transport.HoneyPotSSHTransport#info] connection lost输出解释: Hydra 认为 root/admin 是有效口令,但它进入的是 Cowrie 的伪装 SSH 服务,不是真实系统。日志中的 172.17.0.1 是 Docker 网桥侧看到的宿主机地址,说明连接经过容器网络。蜜罐记录了连接、用户名、密码、认证方式和会话结束,这些就是威胁情报。
🦹♂️ 攻击者终端 (以为是真实服务器)
🛡️ Cowrie 蜜罐控制台 (真实监控)
[System] Cowrie Honeypot is listening on port 2222...
课后任务
- 增加一条 Snort 规则,检测访问
/wp-login.php的 HTTP 请求,并用 pcap 证明它能触发。 - 把
OR%20规则改成检测UNION%20SELECT,解释为什么 URL 编码会影响规则内容。 - 让 Cowrie 运行 30 分钟,统计出现过的用户名、密码和客户端指纹。
- 对比 IDS、IPS、蜜罐在学校网络中的部署位置,并画一张简图。
实验环境快速恢复
kill "$(cat /tmp/lesson12/http.pid)" 2>/dev/null
docker rm -f cowrie-honeypot 2>/dev/null
rm -rf /tmp/lesson12
rm -f /tmp/lesson12-passwords.txt