Passive discovery
Passive mode is the default and safest way to run cyprobe. It listens on a network interface (typically a SPAN / mirror port) and fingerprints OT protocols from observed traffic. Zero packets are injected into the network.
Basic usage
sudo cyprobe passive --interface eth0 --duration 300
This captures traffic on eth0 for 300 seconds (5 minutes), then writes results to stdout.
Key flags
| Flag | Default | Description |
|---|---|---|
--interface | (required) | Network interface to capture on |
--duration | 60 | Capture duration in seconds. 0 = run until Ctrl-C |
--format | text | Output format: text, json, sarif |
--output | - | Output file. - = stdout |
--bpf | none | BPF filter to narrow capture (e.g. port 502) |
--promisc | true | Enable promiscuous mode on the interface |
What it detects
For each supported protocol, the passive engine extracts:
| Protocol | Extracted fields |
|---|---|
| Modbus TCP | Unit ID, function codes observed, register ranges accessed |
| DNP3 | Source/destination addresses, object types |
| S7comm | Rack/slot, PDU type, function codes |
| OPC UA | Endpoint URL, security mode, policy URI |
| BACnet | Device ID, object name, vendor ID |
| EtherNet/IP | Vendor ID, device type, product name, serial |
| IEC 104 | ASDU type IDs, IOA ranges, cause of transmission |
| MQTT | Client ID, topic names, QoS levels, TLS in use |
Protocol fingerprinting
Cyprobe identifies protocols through a combination of:
- Port heuristics -- well-known OT ports (502, 102, 4840, etc.) as a first pass.
- Deep packet inspection -- protocol magic bytes and header structure validation. This catches OT traffic running on non-standard ports.
- Behavioral patterns -- request/response cadence and payload structure for protocols that lack unique magic bytes (e.g. Modbus).
Fingerprinting runs entirely in userspace with zero kernel modules.
Output formats
Text (default)
Human-readable table, one row per discovered asset:
ASSET INVENTORY (passive, 300s on eth0)
IP MAC PROTOCOL IDENTITY FIRST SEEN
192.168.1.10 00:1c:06:aa:bb:cc Modbus TCP Unit 1, FC 3/16 00:00:02
192.168.1.20 00:80:f4:11:22:33 S7comm Rack 0 Slot 2 00:00:05
192.168.1.30 00:0c:29:44:55:66 OPC UA opc.tcp://plc3:4840 00:00:08
JSON
Machine-readable array of asset objects:
sudo cyprobe passive --interface eth0 --duration 300 --format json > assets.json
Each object includes ip, mac, protocol, identity, first_seen, last_seen, packet_count, and protocol-specific metadata under details.
SARIF
SARIF 2.1.0 output for direct ingestion into the Cybrium platform or any SARIF-compatible tool:
sudo cyprobe passive --interface eth0 --duration 300 --format sarif > scan.sarif
Findings are emitted for each asset, with the rule ID indicating the protocol and the physicalLocation encoding the network address.
Continuous monitoring
For long-running passive capture, use --duration 0 and pipe output to a file with periodic rotation:
sudo cyprobe passive --interface eth0 --duration 0 --format json \
--output /var/log/cyprobe/assets.json
Cyprobe writes incremental updates to the output file as new assets are discovered. Use SIGHUP to force a flush and rotate.
Next step
- Active mode -- send safe protocol queries for deeper enumeration
- Rules -- evaluate discovered assets against posture checks