SSHintel 是一个使用 Python 和 Paramiko 构建的轻量级 SSH 蜜罐。它模拟一个假的 Linux shell,用于记录未经授权的访问尝试、捕获凭据,并在受控环境中分析攻击者的行为。
ls、cd、pwd、cat、echo、grep、find、tree、head、tail、wc、stat、ps、df、free、env、id、whoami 等)--tarpit 模式,通过延迟输出来拖慢攻击者SSHintel 不是一个完整的 Bash/Linux shell。它模拟了一组可信的常用命令子集,以收集攻击者遥测数据。命令通过一个轻量级注册表进行分发;添加一个命令只需添加一个小的处理函数。
pip install -r requirements.txt
注意: SSH 主机密钥会在首次运行时自动生成。无需手动生成密钥。
使用指定的端口、用户名和密码运行蜜罐:
python3 run.py serve --port 2222 --username user1 --password pass123
默认端口为
2222,主机为0.0.0.0。
蜜罐会在首次运行时自动生成 SSH 主机密钥,存放在 static/server.key(如果不存在)。无需手动生成密钥。
启用 tarpit 模式:
python3 run.py serve --port 2222 --username user1 --password pass123 --tarpit
禁用 SQLite 遥测(仅使用 JSONL):
python3 run.py serve --port 2222 --username user1 --password pass123 --no-db
SSHintel 可防止因大量并发连接或无限期保持的连接而导致资源耗尽。这些可通过 CLI 进行配置:
示例:
python3 run.py serve --port 2222 --username user1 --password pass123 \
--max-connections 25 --auth-timeout 30 --session-idle-timeout 300
当打开的连接过多时,额外的连接会立即被关闭,并会向 JSONL 日志写入一个 connection_rejected 安全事件(带有 reason: connection_limit)。停滞的认证会被记录为断开连接,带有 reason: auth_timeout;空闲的 shell 会以 reason: idle_timeout 结束。
Tarpit 模式有意缓慢地发送输出以保持攻击者的参与度,因此 tarpit 横幅循环不受空闲超时的影响 — 但 tarpit 会话确实计入连接限制。
SSHintel 包含一个本地 Web 仪表盘,用于可视化存储在 SQLite 中的安全遥测数据。
python3 run.py dashboard
然后在浏览器中打开 http://localhost:5000。
仪表盘默认从
data/sshintel.db的 SQLite 数据库读取数据。先启动蜜罐以便捕获遥测数据,然后启动仪表盘观察数据填充。
点击会话 ID(或导航至 /session/<session_id>)打开会话调查视图,该视图按时间顺序重建单个攻击:
$ command 视图,包含工作目录# 终端 1:启动蜜罐
python3 run.py serve --port 2222 --username user1 --password pass123
# 终端 2:启动仪表盘
python3 run.py dashboard
# 终端 3:模拟攻击者
ssh user1@localhost -p 2222
# (运行一些命令,然后退出)
然后打开 http://localhost:5000 查看捕获的活动。
仪表盘支持实时遥测 — 它每 2 秒轮询一次蜜罐并自动更新。新会话、命令和事件无需刷新页面即可实时显示。实时指示器(● Live)显示连接状态。
打开第二个终端并尝试连接:
ssh user1@localhost -p 2222
如果凭据匹配,您将进入模拟 shell。
要移除过期的 SSH 指纹:
notepad "%USERPROFILE%\.ssh\known_hosts"
删除包含
localhost或蜜罐 IP 的相关行。
creds_loggerfunnel_logger 记录log_files/events.jsonl — 每行一个有效的 JSON 对象每个 JSONL 事件都包含 UTC ISO-8601 格式的 timestamp、event_type、唯一的 session_id 和 source_ip。连接、认证尝试/结果、命令执行、tarpit 激活和断开连接都会作为结构化事件记录。
每个传入的 SSH 连接都被跟踪为一个独立的会话,具有自己的 session_id。会话记录源 IP、连接/断开时间、认证结果和连接持续时间,并且在该连接内生成的每个事件都携带相同的 session_id(因此认证尝试、命令和断开连接可以追溯到单个连接)。会话按连接隔离 — 并发客户端之间不共享任何状态。
每个会话还拥有自己独立的、内存中的假文件系统 — 模拟文件系统为每个连接全新创建,并在连接结束时清理。一个攻击者创建或更改的文件、目录和工作目录永远不会被同时连接的其他攻击者看到。整个文件系统在 Python 内存中模拟,永远不会触及真实的主机文件系统。
当前 event_type 值:connect、auth_attempt、auth_success、auth_failure、command、disconnect、connection_rejected、tarpit。
SSHintel/
├── honeypot/ # 核心蜜罐逻辑
│ ├── __init__.py
│ ├── main.py # 接受循环 + 连接限制
│ ├── handlers.py # SSH 传输设置 + 模拟 shell
│ ├── server.py # Paramiko 服务器接口(认证)
│ ├── session.py # 每连接会话跟踪
│ ├── fs.py # 内存假文件系统(每个会话隔离)
│ ├── shell.py # 假 shell:命令注册表 + 分发器
│ ├── limits.py # 线程安全的并发连接限制
│ ├── logger.py # JSONL 事件日志 + SQLite 桥接
│ └── telemetry_store.py # SQLite 遥测存储 + 查询层
│
├── dashboard/ # 本地 Web 仪表盘
│ ├── app.py # Flask 应用 + API 路由
│ ├── templates/
│ │ ├── index.html # 主仪表盘模板
│ │ └── session.html # 会话调查模板
│ └── static/
│ ├── style.css # 仪表盘样式
│ ├── dashboard.js # 主仪表盘 JS(实时更新)
│ └── session.js # 会话调查 JS
│
├── log_files/ # 运行时日志(git 忽略)
│ ├── creds_audits.log # 凭据尝试
│ ├── cmd_audits.log # 命令审计跟踪
│ └── events.jsonl # 结构化 JSONL 安全事件
│
├── data/ # SQLite 数据库(git 忽略)
│ └── sshintel.db
│
├── static/ # SSH 主机密钥(自动生成)
│ └── server.key
│
├── .github/workflows/ # CI 配置
│ └── tests.yml
│
├── Dockerfile
├── README.md
├── requirements.txt # 运行时依赖(paramiko、flask)
├── requirements-dev.txt # 测试依赖(pytest、pytest-cov)
└── run.py # CLI 入口点
如果您希望在容器化环境中运行蜜罐,可以使用附带的 Dockerfile。
docker build -t sshintel .
这将创建一个名为
sshintel的 Docker 镜像。
docker run -p 2222:2222 sshintel
这将:
static/server.key 自动生成 SSH 私钥(如果尚不存在)2222 上以默认凭据启动蜜罐:username: user1、password: pass123打开第二个终端并通过 SSH 连接:
ssh user1@localhost -p 2222
如果凭据匹配,您将进入模拟 shell。
停止容器:
docker ps # 查找容器 ID
docker stop <container_id>
移除镜像:
docker rmi sshintel
您也可以使用
docker save -o sshintel.tar sshintel导出镜像,之后使用docker load -i sshintel.tar加载。
本项目基于 MIT 许可证 授权。
| 标志 | 默认值 | 用途 |
|---|
--max-connections | 50 | 最大同时活动连接数;额外的连接将被拒绝并记录为 connection_rejected 事件 |
--auth-timeout | 60(秒) | 完成 SSH 握手/认证所允许的时间;停滞的客户端将被断开 |
--session-idle-timeout | 300(秒) | 已认证 shell 的空闲超时;空闲会话将被结束,但正在积极输入的攻击者永远不会被终止 |