# Rockwell WWS OT decoy: advanced

~60-90 minutes. CSP/RSLinx path, cellular gateway fiction, `.RSS` lure, intent triage, session graph, EPA inhibit (T0838), HMI vs PLC view (T0829).

!!! danger "Decoy plane only"
    Field overlay `scripts/field_trial/stacks/chn/overlays/rockwell-wws.env` must **never**
    contain CTI API keys. Ops Investigate / STIX export stay on the management plane.

## Topology (research)

| Host port | Container | Face |
|-----------|-----------|------|
| 502 | 502 | Modbus |
| 44818 | 44818 | EtherNet/IP |
| 2222 | 12222 | CSP/DF1 (unprivileged bind) |
| optional 8081 | gateway HTTP | Sierra/Moxa/Cradlepoint fiction |

Compose: `overlays/docker-compose.rockwell-wws.yml` + `rockwell-wws.env`.

## CSP + RSS lure (T1041)

```bash
export CYBERHALLUCINET_LISTEN_CSP=127.0.0.1:12222
export CYBERHALLUCINET_OT_RSS_LURE=1
```

PCCC out-of-range addresses return Contained status `0xF0` / extended `0x04`.
Protected typed logical read / HTTP `/backup/water_plant_main.rss` (with `--ot-plc-http`)
serves a synthetic project header and emits Class B `T1041` metadata (hash/size, no raw ladder SoR).

## Cellular gateway sidecar

Prefer a **separate** compose service for TCP fingerprint divergence:

```bash
export CYBERHALLUCINET_OT_GATEWAY_FACE=sierra_airlink
export CYBERHALLUCINET_LISTEN_GATEWAY_HTTP=127.0.0.1:8081
```

Default-cred login shows a **fake** port-forward table (`WAN:2222 → 192.168.1.10:2222`). No real DNAT.

## Intent triage + session graph

```bash
export CYBERHALLUCINET_OT_INTENT_TRIAGE=1
export CYBERHALLUCINET_OT_SESSION_GRAPH=1
```

- L1: ListIdentity / coil reads → aggregated metrics (not Critical Findings)
- L3: modem login / RSS download
- L4: EPA inhibit / dosing writes

Scores are **advisory only** (SEC-AI-001: they do not change wire bytes).

## EPA inhibit (T0838) and HMI lie (T0829)

Modbus discretes are read-only (FC2). Use a Contained writable alias instead:

- write **coil 5** (`WaterCoilEPAInhibit`) or **holding 15** (`WaterHoldEPAInhibit`) via Modbus/CSP
- plant latches inhibit; EPA discrete display stays Normal while chlorine is out of band
- telemetry tags `epa_alarm_inhibit` (L4 when intent triage is on)

MicroLogix HTTP may still show Chlorine 1.8 mg/L while holding 9 shows a low value : 
sophistication probe for attackers who trust HMI only.

## Counter-AI traps / Emulated modem SLM (optional)

```bash
export CYBERHALLUCINET_OT_COUNTER_AI_TRAPS=1   # always-on when set; not score-gated
export CYBERHALLUCINET_OT_GATEWAY_SLM=1        # requires --mode=ai + ai-broker; fail-closed static
```

## DNP3 / SCADA HMI (later faces)

```bash
export CYBERHALLUCINET_LISTEN_DNP3=127.0.0.1:20000
export CYBERHALLUCINET_OT_SCADA_HMI=ignition   # paths under /scada/ on listen-http
```

DNP3 public exposure is amp-gated (size/rate caps). SCADA faces are Contained fiction: **not** the Ops GUI.

## Purple-team checklist

- [ ] Pack off → no OT binds
- [ ] MicroLogix ListIdentity product codes
- [ ] Modbus↔process image consistency with ENIP/CSP
- [ ] RSS download → T1041 Class B event
- [ ] Modem login → fake forward table
- [ ] No CTI secrets on decoy overlay
- [ ] `make docs-check` clean after doc edits

Config matrix: [ot-wws-config](../reference/ot-wws-config.md).
