AlexisChaloulos/plcscout

GitHub: AlexisChaloulos/plcscout

通过只读监控 Modbus 设备运转时寄存器和位的变化,逆向恢复未公开文档的 PLC 地址映射关系并生成可共享的设备配置文件。

Stars: 0 | Forks: 0

# plcscout [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/AlexisChaloulos/plcscout/actions/workflows/ci.yml) [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/) [![License: Apache 2.0](https://img.shields.io/badge/license-Apache--2.0-green)](LICENSE) [![只读](https://img.shields.io/badge/PLC%20access-read--only-orange)](#) **通过观察设备运转时寄存器和位的变化,对未公开文档的 Modbus/PLC 设备进行逆向工程。** 工业控制器使用 Modbus 通信,但几乎从未有文档说明每个寄存器的含义——厂商图纸只会标注物理 I/O,而不会说明它在网络传输中的具体位置。 plcscout 通过经验恢复这种映射关系:扫描地址空间,观察设备执行操作时发生的变化,将未知的位与你*能够*识别的几个寄存器关联起来,并将发现记录在可移植的 **设备配置文件** 中。 两种受众,一套工具包: - **自动化/集成商** —— 了解一个你未参与调试的工厂,并为其构建实时操作员视图(参见 [可视化技能](skills/plcscout-visualize/))。 - **ICS/OT 安全** —— 被动地对未知的 Modbus 设备进行指纹识别和映射,用于资产盘点并建立行为基准。 ## 核心理念:设备配置文件 一切都围绕一个核心工件——[**设备配置文件**](schema/profile.md)。工具负责*生成*它;下游的任何内容(文档、仪表板、可视化技能)都*使用*它。 配置文件在**设计上就是可匿名化的**:它只包含技术发现——哪个寄存器起什么作用,以及相关证据——绝不包含主机、站点或客户名称。连接详细信息保存在被 git 忽略的 `connection.local.json` 文件中。这使得配置文件可以安全地共享,并且由 `scrub` 检查来强制执行这一点。 ``` discover ──▶ profile skeleton ──▶ watch / record ──▶ correlate ──▶ named profile │ report ◀───────────────┤ visualize skill ◀───────────────┘ ``` ## 安装 ``` pip install -e . # or: uv sync ``` 要求 Python 3.10+ 和 `pymodbus>=3.9`。 ## 快速开始 —— 合成演示(无需真实硬件) plcscout 内置了一个**模拟**设备,因此你可以在零真实世界数据的情况下端到端运行整个流程: ``` # 1. 生成一个合成的泵循环 capture,并将其作为一个 live Modbus 设备提供服务 python examples/synthetic/make_demo_capture.py python examples/synthetic/replay_server.py # listens on 127.0.0.1:5020 # 2. 将 plcscout 指向它 echo '{ "transport": "tcp", "host": "127.0.0.1", "port": 5020, "unit_id": 1 }' > connection.local.json # 3. 运行 flow plcscout-discover --max-reg 300 --out profiles/skeleton.json # map the address space plcscout-record examples/synthetic/demo.profile.json 30 captures/demo.capture.json plcscout-correlate examples/synthetic/demo.profile.json captures/demo.capture.json plcscout-report examples/synthetic/demo.profile.json > REGISTER_MAP.md plcscout-monitor examples/synthetic/demo.profile.json # live page at :8765 ``` `correlate` 会恢复植入的语义(“注入泵”与 1 号罐注满对应,“传输泵”与 1 号罐排入 2 号罐对应,依此类推)——这与你在真实设备上使用的操作完全相同。 ## 工具集 | 命令 | 功能 | |---|---| | `plcscout-discover` | 扫描地址空间;生成一个**配置文件骨架**,列出范围以及每个非零位置以供命名。 | | `plcscout-watch` | 实时查看当前发生的变化——按下一个控制按钮,查看哪个寄存器发生改变。 | | `plcscout-record` | 在一个周期内记录配置文件的信号,生成一份**采集数据**(时间序列)。 | | `plcscout-monitor` | 为配置文件提供**实时数值网页**——每个信号都显示其当前值、寄存器和置信度。这是你用来根据真实 HMI 检查配置文件的工具。 | | `plcscout-correlate` | 通过将未知的位与配置文件的**锚点**(你已经知道的寄存器)进行关联,来为其命名。 | | `plcscout-hunt` | 通过*行为*查找寄存器——一个实时计时器、一个枚举索引,或者你所能看到的某个值存放的位置。 | | `plcscout-report` | 将配置文件渲染为人类可读的 Markdown 寄存器映射表(已进行脱敏处理)。 | ## 在真实硬件上的预期表现 以下是通过以太网在 Schneider M340 上测得的数据,因为这些数字决定了工具的使用方式: - **一次 Modbus 读取的耗时在于往返延迟,而不是 payload。** 读取 1 个寄存器和读取 125 个寄存器都耗时约 33 毫秒。轮询速度取决于配置文件需要多少次*事务交互*,而不是它包含多少个值。 - **因此,在轮询之前请先优化你的配置文件。** 一个包含约 3000 个分散信号的原始骨架每次轮询需要约 3.6 秒——对于 `record` 来说还可以,但在 `watch` 中感觉不够实时。一个仅包含几十个信号的已命名配置文件可以在几毫秒内完成轮询。在你还在缩小范围时,使用 `watch --bits-only` 会有所帮助。 - **越过设备末端进行扫描是正常且低成本的。** `discover` 会对设备拒绝的跨度进行采样,然后才确定其未被映射,因此 0–12000 的扫描大约需要 20 秒,而详尽搜索则需要约 8 分钟。如果你想通过付出这个代价来排除隐藏在未映射区域中的小型映射孤岛,请传入 `--thorough` 参数。 ## 连接详细信息保持在本地 主机/IP/端口**绝不**包含在配置文件中。它是从 `connection.local.json`(被 git 忽略)或 `PLCSCOUT_HOST` / `PLCSCOUT_PORT` / `PLCSCOUT_UNIT` 环境变量中读取的。这就是隐私边界:配置文件可以发布;连接文件则不能。 ## 两种 UI **`plcscout-monitor`** —— 一个内置的**通用**实时数值页面。配置文件中的每个信号都显示其当前值、寄存器和置信度,因此你可以根据设备自身的 HMI 检查配置文件。适用于任何设备,无需额外设计工作: ![plcscout-monitor 显示实时数值,每个数值都标有寄存器和置信度](https://static.pigsec.cn/wp-content/uploads/repos/cas/19/19b7e3532eca552f7ff14ef01709da36c52f174bac2f04f5b8b882adabff2201.png) **[`plcscout-visualize` 技能](skills/plcscout-visualize/)** —— 为特定机器量身定制的**专属**仿真界面。通用的仿真界面无法完美适配特定工厂,因此这个 Claude 技能会读取配置文件(以及可选的采集数据),并根据你发现的信号生成一个自包含的 HTML 仪表板——将位掩码字解码为指示灯,将状态机转换为相位条,并根据阀门位推算出排放时间: ![合成泵站的生成仿真界面,正在回放录制的周期](https://static.pigsec.cn/wp-content/uploads/repos/cas/91/91521759e3666e3207a652470ef162e031af3908bf86a48cd66aca1f9e7f860d.png) 这个仿真界面中的任何内容都不是手动放置的:储罐来自配置文件中的液位锚点,指示灯来自其位掩码信号,相位条来自其状态机。将该技能指向不同的配置文件,就会得到不同的仿真界面。上面的示例已经提交到仓库——[`examples/synthetic/demo_mimic.html`](examples/synthetic/demo_mimic.html),可以通过 `python examples/synthetic/make_demo_mimic.py` 重新生成——因此你可以在浏览器中打开它,在没有 PLC 的情况下点击体验一个周期。 ## 路线图 Schema 是稳定的基础;以下附加功能不会破坏其结构:共享(已匿名化)配置文件的社区注册表;额外的输出目标(Grafana / Home Assistant / Node-RED 配置,异常规则导出);串行/UDP 传输;被动指纹数据库。 ## 贡献 请参见 [CONTRIBUTING.md](CONTRIBUTING.md)。有两条规则比其他规则更重要:**绝不提交真实世界的数据**(`examples/` 中的所有内容都是合成的),并且**工具保持只读状态**——plcscout 绝不会向设备写入数据。 ## 许可证 Apache License 2.0 —— 详见 [LICENSE](LICENSE) 和 [NOTICE](NOTICE)。 对于工业软件而言,选择 Apache-2.0 而不是 MIT 出于两个重要原因:它明确授予了专利权(如果任何人就专利提起诉讼,则撤销其专利权),并且它明确声明本软件**不提供任何形式的保证**——这对于针对实际工厂设备运行的工具来说至关重要。
标签:OT安全, PLC, Python, 工控系统, 无后门, 逆向分析, 逆向工具