liam2h/honeypot

GitHub: liam2h/honeypot

一个基于 Paramiko 的低交互 SSH 蜜罐,通过模拟 SSH 服务捕获撞库凭据并生成可视化报告,附带本地攻击模拟器用于验证。

Stars: 0 | Forks: 0

# SSH 蜜罐 这是一个虚假的 SSH 服务器,没有任何真实用户应该连接到它,它还附带了一些工具,能将它接收到的连接转化为你在面试中可以说出口的东西。 它会进行监听,记录提供的凭据,并且总是拒绝。它不会对外连接、扫描、探测或进行报复。这里的所有操作都在 localhost 上运行。 ## 什么是蜜罐,以及为什么数据是可信的 蜜罐是一个诱饵。它看起来像是一个值得攻击的服务,但其背后空无一物。没有人发布它的地址,没有人在上面拥有账户,也没有人有理由登录。 最后一点是全部的诀窍所在。在普通服务器上,一次失败的登录可能是你自己输错了密码,可能是同事登错了主机,也可能是配置错误的备份脚本。你必须过滤掉这些噪音,然后才能对攻击者做出判断。而在蜜罐上,没有需要过滤的噪音:**每一个连接要么是恶意的,要么是自动化的,因为任何人都没有合法的理由出现在那里。** 这就是它的专业术语含义:蜜罐具有近乎为零的误报率。 因此,当这个东西记录了 400 次尝试 `root` / `123456` 时,那就是 400 个攻击者在尝试 `root` / `123456`。不需要解读,也没有需要争论的假设。数据在构建之初就是干净的。 第二件值得了解的事是:这是一个**低交互**蜜罐。它仅支持足够的 SSH 协议以到达登录提示符阶段,收集凭据,然后拒绝它们。这里没有 shell,没有伪造的文件系统,也没有运行命令的方法。一个**高交互**蜜罐会给攻击者提供一个真实(或令人信服地伪造)的系统供其操作,这会产生更丰富的数据——比如他们投放了什么恶意软件,运行了什么命令——代价是在你的网络上拥有一个真实的、可被攻击的系统。低交互能让你获得凭据和指纹数据,且几乎没有风险。对于一个你打算让其保持运行的项目集作品来说,这是正确的权衡。 ## 在本地运行 你需要 Python 3.9+。 ``` cd honeypot # 一次性设置 python -m venv .venv .venv/Scripts/activate # Windows; source .venv/bin/activate on Linux/macOS pip install -r requirements.txt # terminal 1 -- 启动 honeypot (Ctrl-C 停止) python honeypot.py # terminal 2 -- 攻击它 python simulate_attack.py # terminal 2 -- 查看捕获内容 python analyse.py ``` `analyse.py` 会打印一份摘要并写入 `report.html`。直接在浏览器中打开该文件即可——它是一个独立的单文件,不需要网络连接。 使用以下命令运行测试: ``` python test_honeypot.py ``` 首次运行时,`honeypot.py` 会生成 `host_key`(服务器的 SSH 身份标识)和 `honeypot.db`。这两者都被 gitignore 忽略了:它们是数据,而不是源代码。 ### 你应该看到的内容 ``` 2026-07-27 18:56:43 127.0.0.11:52107 root / 123456 (SSH-2.0-libssh2_1.9.0) via password 2026-07-27 18:56:43 127.0.0.11:52108 admin / admin (SSH-2.0-libssh2_1.9.0) via password ``` 模拟器在大约五秒钟内会产生大约 380 次尝试。 ## 各个文件的作用 | 文件 | 用途 | | --- | --- | | `honeypot.py` | 服务器。接受 SSH 连接,记录凭据,总是拒绝。 | | `simulate_attack.py` | 虚假攻击者。针对蜜罐驱动真实的 SSH 连接,让你可以证明它有效。 | | `analyse.py` | 读取数据库,打印摘要,写入 `report.html`。 | | `test_honeypot.py` | 普通的 `assert` 测试。不使用框架。 | | `requirements.txt` | 锁定版本的依赖项(`paramiko` 及其引入的依赖)。 | ### `honeypot.py` 手动实现 SSH 并不是一项理智的工作量,所以这里使用了 [paramiko](https://www.paramiko.org/)——标准的 Python SSH 库——的*服务器*模式。Paramiko 处理握手、密钥交换和加密;这个文件提供了决定登录是否成功的部分。这个决定永远是“拒绝”。 服务器将自己声明为 `SSH-2.0-OpenSSH_8.4p1 Debian-5+deb11u3`。一个声明自己是蜜罐的蜜罐什么也收集不到,所以它声称自己是一台无聊的、常见的 Debian 机器。 每次尝试都会记录以下内容: - **时间戳** -- 采用 UTC 和 ISO 8601 格式,因此跨机器的排序和比较可以直接进行 - **源 IP 和端口** - **提供的用户名和密码** - **客户端版本字符串** -- 客户端在任何内容被加密之前就会声明它是什么软件。这是其自行报告的,因此是可伪造的,而这正是它有用的原因:机器人很少费力去令人信服地伪造它,因此 `SSH-2.0-libssh2_1.9.0` 或 `SSH-2.0-Go` 是一个强烈的信号,表明你看到的是自动化程序,而不是真人 - **认证方法** -- `password` 或 `publickey`。对于密钥尝试,没有密码,因此密钥的指纹会替代填入该列:同样的问题,“他们提供了什么?” **攻击者发送的所有内容都是恶意输入。** 为此存在三道防线,并在源代码中进行了注释,以免它们以后被“简化”掉: 1. `clip()` 将每个受攻击者控制的字段截断为 256 个字符,并去除 NUL 字节。截断可以防止多兆字节的用户名使数据库变得臃肿。NUL 字节很重要,因为它们会在任何通过 C 字符串读取 SQLite 的程序中无声地截断字符串——存储的值看起来毫无害处,而真实的 payload 实际上已经被削减了。 2. 每次插入都是**参数化**的(`VALUES (?, ?, ?...)`)。攻击者编写密码;如果它被格式化进 SQL 文本中,一个密码 `'; DROP TABLE attempts;--` 就会完全按照它字面的意思执行。为此有一个专门的测试。 3. `handle()` 将整个单连接生命周期封装在 `try/except` 中,并且每个阶段都有超时机制。畸形数据包和半开连接在这里是*正常*情况,而不是异常——一个糟糕的对等体绝不能让监听器崩溃。 任何受攻击者控制的内容都不会被传递给 shell、子进程或会被执行的格式化字符串。 每个连接都由独立的线程处理,因此蜜罐可以同时应对多个攻击者。 ### 存储 有两种格式,这是有意为之的: - **SQLite** (`honeypot.db`) -- 一张 `attempts` 表,在分析器进行分组的列(`username`、`password`、`src_ip`、`ts`)上建立索引。适合用于查询。 - **JSON Lines** (`attempts.jsonl`) -- 每行一个 JSON 对象,采用追加方式。这是真实日志管道所消费的格式(Splunk、Elastic、Loki、Vector 都原生支持提取它),并且它是后续检测规则项目的天然输入。 ### `simulate_attack.py` 没有攻击者你就无法验证这一切是否有效,而等待真正的攻击者意味着需要部署,这是一个独立的决策。所以这个脚本*就是*攻击者。 它通过**真实的 SSH 连接和真实的代码路径**进行连接——没有任何东西被直接写入数据库。它重放以下内容: - 来自五个不同攻击者配置文件的撞库爆发,并行执行 - 一种低速慢速的滴注:每次连接使用一个凭据,间隔进行,就像耐心的攻击者为了保持在速率限制之下所做的 - 真实世界的凭据列表(`root`/`root`,`admin`/`admin`,`pi`/`raspberry`) - 多样化的客户端版本字符串,这样指纹明细中就有内容可看 - 一次公钥尝试,以便该路径也能被执行到 每个“攻击者”将其客户端 socket 绑定到不同的回环地址(`127.0.0.11`、`127.0.0.12`、...)。在 Linux、macOS 和 Windows 上,整个 `127.0.0.0/8` 范围都是本地的,因此这会在数据中产生真正不同的源 IP,而没有单个数据包离开这台机器。 一个值得了解的细节,因为它影响了代码的设计:**SSH 不允许客户端在连接中途更改用户名。** 如果你尝试这样做,服务器会断开会话。因此,每次连接使用一个用户名并循环密码,而使用新的用户名意味着建立新的连接——这就是为什么真实的蜜罐记录的连接数比你从尝试次数推测出的要多得多的原因。 ### `analyse.py` 运行聚合查询并报告: - 最热门的用户名、密码和源 IP - 最热门的凭据*对*(密钥认证行被排除在外——密钥指纹不是任何人输入的密码) - 按 UTC 小时分桶的尝试 - 客户端版本字符串明细 - 所有内容的独立计数 HTML 报告将其条形图绘制为用 Python 生成的内联 SVG。没有图表库,没有 CDN,完全没有 JavaScript——因此该文件可以离线工作,并且没有供应链。每个标签在写入时都经过了 HTML 转义,因为这些标签是攻击者提供的字符串,像 `