backup: 2026-10-11 00:08
This commit is contained in:
@@ -13,3 +13,6 @@
|
||||
|
||||
** Subnodes
|
||||
- [[id:b8094a02-528a-4eeb-a021-4ffc7396f0f3][azos/emacs]] — Emacs-specific gotchas (async-shell-command/pty, org-babel lexical binding)
|
||||
- [[id:da416dd3-d7bb-4a81-83fb-a5543817b462][azos/mail]] — mu4e/mbsync/msmtp accounts, contexts, bookmarks
|
||||
- [[id:b72d2db1-f539-40b9-ade4-1253415049e2][azos/hardware-auth]] — YubiKey U2F login/sudo setup; lauretta's fingerprint reader is unsupported, why, and what would unblock it
|
||||
- [[id:939a9fa3-ddc8-4cc1-8130-771cc5de000f][azos/todos]] — open project TODOs
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
** Gotchas
|
||||
- =async-shell-command= spawns subprocesses with =TERM=dumb= and no real controlling tty (confirmed: no =INSIDE_EMACS=, pty exists but curses can't use it). Any gpg/pinentry prompt triggered from such a process (e.g. signed git commits) fails with "Inappropriate ioctl for device" once the pinentry PIN cache expires — pinentry-emacs mode silently isn't engaged either, since gpg only requests it when =INSIDE_EMACS= is set, which =async-shell-command= doesn't set (unlike =M-x shell=/comint, which does). Fix: run the command in a real pty via =vterm= instead (confirmed working — =vterm-term-environment-variable= is set to =xterm-256color=). Fixed in =azos/roam/backup= (=features/lauretta/emacs/config.org=) 2026-10-04.
|
||||
- A nix rebuild (=azos-lauretta-update=) only regenerates files on disk (e.g. =config.org=) — it never reloads anything into an already-running Emacs session. =setq=/=defvar= forms evaluated at startup (e.g. =mu4e-contexts=) stay stale until that exact top-level form is re-evaluated, e.g. via =emacsclient -e '(load-file "/tmp/x.el")'= on a file containing just that extracted sexp (match parens exactly — an off-by-one line range truncates the form and errors "End of file during parsing" instead of warning about staleness). Discovered via mu4e context drift, see [[id:da416dd3-d7bb-4a81-83fb-a5543817b462][azos/mail]] Gotchas for the full incident.
|
||||
- =org-babel= =emacs-lisp= source blocks evaluate with *dynamic* binding by default (=ob-emacs-lisp.el= defaults =:lexical= to ="no"=), and =config.org= sets no =:lexical= header anywhere (file-wide or per-block). This silently breaks closures in async code: a pattern like =(let ((output "")) (make-process :filter (lambda (_p chunk) (setq output ...)) :sentinel (lambda (_p _e) ... output ...)))= fails because the let-bound =output= unwinds before the async filter/sentinel callbacks run — they don't lexically close over it. The failure is silent: errors like "Symbol's value as variable is void: output" only appear in =*Messages*=, not as visible UI errors, and whatever the sentinel was supposed to set (e.g. =elfeed-feeds=) just stays =nil=. This hit the elfeed-protocol Nextcloud News auth block (fetches a =pass(1)= password asynchronously via =make-process= to avoid blocking Emacs's command loop and deadlocking with pinentry-emacs, then sets =elfeed-feeds= from the sentinel) — =elfeed-update= appeared to "do nothing" because of this exact bug. Fix/convention: for any async Emacs Lisp in this repo's org-babel blocks (process filters/sentinels, timers, callbacks) that needs to carry state across the async boundary, don't rely on closures over =let=-bound locals unless the block explicitly sets =:lexical yes=. Instead store state on the process object itself via =process-put=/=process-get= (works regardless of lexical/dynamic binding) — this is the pattern now used in the elfeed-protocol block. Fixed in =features/lauretta/emacs/config.org= (Elfeed Nextcloud News Sync section) 2026-10-05.
|
||||
|
||||
[[id:bf4dde56-0967-4374-94ed-771301e47c66][azos]]
|
||||
@@ -15,6 +15,16 @@ Backlink: [[id:bf4dde56-0967-4374-94ed-771301e47c66][azos]]
|
||||
EXWM feature: =azos-core/features/exwm/emacs/config.org= (literate), packaged via
|
||||
=_pkg.nix= (=azos-emacs-exwm=), enabled by =azos.suites.exwm.enable=.
|
||||
|
||||
The feature registers two independent flake modules:
|
||||
- =config.flake.modules.homeManager.exwm= — packages, =.xinitrc=/=.login.sh=,
|
||||
udiskie. Pure home-manager, no NixOS dependency — can be applied via
|
||||
standalone home-manager on a non-NixOS distro (e.g. nix-in-userspace on
|
||||
Fedora).
|
||||
- =config.flake.modules.nixos.exwm= + =nixos-base= — =services.xserver=,
|
||||
greetd/startx wiring, =services.udisks2=, system packages (tuigreet, xinit).
|
||||
NixOS-only; on a non-NixOS host this half must be replaced with
|
||||
distro-native equivalents (Fedora's own Xorg/display-manager/udisks2 setup).
|
||||
|
||||
Key custom keys:
|
||||
- =s-r= -> =exwm-reset= -> calls =exwm-input-grab-keyboard= (switches window to
|
||||
full "line-mode": Emacs captures all keys)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
:PROPERTIES:
|
||||
:ID: b72d2db1-f539-40b9-ade4-1253415049e2
|
||||
:END:
|
||||
|
||||
#+title: azos/hardware-auth
|
||||
#+filetags: :project: :knowledge: :hardware-auth:
|
||||
|
||||
** Architecture
|
||||
- lauretta (ThinkPad T480) uses YubiKey U2F/FIDO2 (=pam_u2f=) as a "sufficient" PAM factor ahead of password, for both =sudo= and =login= (which =greetd=/=tuigreet= substacks) — see =features/hardware-auth/default.nix=, commit 1d66194.
|
||||
- Default NixOS PAM rule ordering already tries u2f before pam_unix, both "sufficient" — no extra ordering config needed.
|
||||
- Per-user enrollment (not machine state): =pamu2fcfg > ~/.config/Yubico/u2f_keys=; must be redone on each new machine.
|
||||
|
||||
** Gotchas
|
||||
- lauretta's built-in fingerprint reader is a Synaptics Metallica MIS, USB ID =06cb:009a= — a match-on-chip sensor NOT supported by upstream libfprint (confirmed via openSUSE forum + a Launchpad bug for this exact device ID). =fprintd-enroll= fails with "GDBus.Error:net.reactivated.Fprint.Error.NoSuchDevice".
|
||||
- =nixos-hardware='s =lenovo/thinkpad/default.nix= (imported by the t480 profile) only has a generic commented-out =services.fprintd.enable = true;= — no model-specific workaround, and no other ThinkPad profile there handles this sensor either.
|
||||
- Raised upstream in nixos-hardware issue #521 ("[ThinkPad x270] Fingerprint reader does not work"). Commenter =ahbnr= (also has a T480) built custom packages for python-validity + open-fprintd + fprintd-clients, working via a manual =security.pam.services.sudo.text= override.
|
||||
- That became a maintained flake: https://github.com/ahbnr/nixos-06cb-009a-fingerprint-sensor (55 stars, targets 06cb:009a specifically, tested on T480).
|
||||
- BLOCKER: that flake's README says "With NixOS Unstable: Not supported" — only NixOS 24.11/23.11 stable. Our azos flake pins =nixpkgs-unstable= (=flake.nix:7=). Its issue tracker has an open "Update to 25.05" request (unresolved) and a closed issue about unstable builds failing with a patch error, confirming the incompatibility.
|
||||
- Decision (2026-10-09): keep fingerprint disabled/unimplemented, documented only as a code comment in =features/hardware-auth/default.nix=. Revisit if (a) the ahbnr flake gets ported to nixpkgs-unstable/a newer stable release, or (b) it's worth pinning a second stable nixpkgs input just for this one package set.
|
||||
|
||||
** Key Files
|
||||
- =features/hardware-auth/default.nix= — =azos.hardware-auth.enable=, wires up =security.pam.u2f=, option description documents the =pamu2fcfg= enrollment steps
|
||||
@@ -0,0 +1,34 @@
|
||||
:PROPERTIES:
|
||||
:ID: da416dd3-d7bb-4a81-83fb-a5543817b462
|
||||
:END:
|
||||
|
||||
#+title: azos/mail
|
||||
#+filetags: :project: :knowledge: :mail:
|
||||
|
||||
** Architecture
|
||||
- 3 accounts defined in =features/mail/default.nix=: =zakobar= (primary, aner@zakobar.com via privateemail.com IMAP/SMTP), =gmail= (anerisgreat@gmail.com), =bgu= (anerz@post.bgu.ac.il, gmail-flavor IMAP)
|
||||
- Sync stack: =mbsync= (isync) pulls IMAP → =~/Maildir=, =msmtp= sends, =mu= indexes for search/mu4e. Confirmed by live inspection (2026-10-08): generated =~/.config/isyncrc= and =~/.config/msmtp/config= are fully populated and actively syncing (recent =.mbsyncstate= timestamps); mu4e's =mu4e-get-mail-command= is literally =mbsync -a=.
|
||||
- lieer was declared (=services.lieer.enable=/=programs.lieer.enable=) but had zero real footprint (no =.gmailieer.json= anywhere, no systemd units) — vestigial, removed from =features/mail/default.nix=.
|
||||
- Credentials via =pass=: =mbsync/anerisgreat@gmail.com=, =mbsync/anerz@post.bgu.ac.il=, =privateemail.com= (zakobar account). All decrypt through the same GPG smartcard (yubikey) key.
|
||||
- Periodic sync: =systemd.user.timers.mbsync-timer= runs every 5 min (2 min after login, then every =OnUnitActiveSec=). Guarded by a =gpg --card-status= presence check in the =mbsyncSafe= wrapper script so a missing yubikey skips the sync silently instead of triggering a pinentry "insert card" prompt — =gpg --card-status= only queries the reader and never itself invokes pinentry, making it a safe non-interactive gate.
|
||||
- Mail client is mu4e in Emacs (=azos-core/features/station/emacs/config.org=), not notmuch (a =notmuch-hello= mode reference exists only in a linum-disable list, appears vestigial/unused)
|
||||
|
||||
** Conventions
|
||||
- mu4e contexts match by maildir prefix: =/zakobar=, =/gmail=, =/bgu=; each sets its own sent/drafts/trash/archive (archive = "All Mail" for gmail-flavor accounts)
|
||||
- No user-defined tagging system — "tags" in this setup means mu4e flags (unread/trashed/replied) and Gmail labels, which arrive as IMAP folders under =[Gmail]/= rather than mu4e-native tags
|
||||
- Bookmarks (saved searches) defined in config: Inbox (all 3 combined), Unread, Today, Week
|
||||
- Maildir shortcuts: =z=/=g=/=b= keys jump to each account's inbox
|
||||
- Mail opens in a dedicated singleton tab via =azos/mail/open= (bound under the "open" keymap)
|
||||
|
||||
** Gotchas
|
||||
- mbsync's =remove=/=expunge= home-manager options (per-account =mbsync.remove=/=mbsync.expunge=) default to ="none"= and were never set — =\Deleted= flags synced down from IMAP but never actually got removed/expunged on either side, so trashed messages lingered forever in the local Maildir and showed up (struck-through) in any mu4e bookmark that didn't explicitly filter =flag:trashed=. Fixed 2026-10-08 by setting =mbsync.remove = "both"=/=mbsync.expunge = "both"= in =features/mail/default.nix= default_account_params, for all 3 accounts. Caveat: for Gmail-flavor accounts (=gmail=/=bgu=), Gmail's IMAP quirk means expunging any folder other than =[Gmail]/Trash= just removes that one label — the message survives under other labels (e.g. All Mail). =zakobar= (plain IMAP, no label system) has no such safety net: expunge there is a real, permanent, unrecoverable delete.
|
||||
- BGU's Workspace account (=anerz@post.bgu.ac.il=) localizes/renames the Gmail "Trash" special-use label to =[Gmail]/Bin= instead of =[Gmail]/Trash= — caused mbsync error "channel bgu: far side box [Gmail]/Trash cannot be opened" plus a stale local =[Gmail]/Trash= maildir with orphaned messages. =mu4e-trash-folder= for the BGU context must be =/bgu/[Gmail]/Bin=. Fixed 2026-10-08 (merged stale local messages into Bin, updated context). Don't assume standard Gmail folder names for Workspace/edu accounts — verify via IMAP LIST per account.
|
||||
- mu4e's "Inbox" bookmark historically did NOT exclude =flag:trashed= (unlike Unread/Today/Week) — direct cause of visibly crossed-out mail in Inbox. =flag:trashed= only reflects the literal Maildir =T= flag; it does NOT mean "located in a Trash/Bin/Spam-named folder." Because of Gmail's multi-label model, a genuinely-unread message filed anywhere also has a duplicate unread copy under =[Gmail]/All Mail= (same Message-ID, separate local file) — this inflated Unread-bookmark counts by ~2x. Fixed 2026-10-08: all four bookmarks (config.org, =mu4e-bookmarks=, ~line 95) now share one =let=-bound exclusion string filtering =flag:trashed= plus the Trash/Bin/Spam/All-Mail/"Deleted Messages" maildirs per account.
|
||||
- Live Emacs session state and the on-disk literate config drift independently: a nix rebuild (=azos-lauretta-update=) only regenerates files on disk, it does NOT reload anything into an already-running Emacs — =mu4e-contexts=/=mu4e-bookmarks= etc. stay at whatever was last =load-file='d or evaluated at startup. After editing =config.org=, hot-reload the *specific* top-level form that changed via =emacsclient -e '(load-file "/tmp/x.el")'= (extract just that sexp with exact matching parens — off-by-one line ranges silently truncate the form and error "End of file during parsing"). Forgetting to reload =mu4e-contexts= after fixing =mu4e-trash-folder= briefly almost recreated the just-deleted stale =/bgu/[Gmail]/Trash= folder, because the live session's BGU context still pointed at the old path and mu4e prompted "create trash folder?" on trash-mark-apply.
|
||||
- Debugging mu4e live via =emacsclient -e=: =(with-current-buffer "*mu4e-headers*" mu4e--search-last-query)= shows the active search; =(gethash docid mu4e--mark-map)= on a buffer's message-at-point shows the exact pending mark+target before applying; =(mu4e-context-vars (mu4e-context-current))= shows live (not file) context vars. Caution: if Emacs is blocked on a blocking minibuffer prompt (e.g. a =y-or-n-p= "create folder?" confirmation), queued =emacsclient -e= calls will hang/timeout rather than error — that's a sign a prompt is open and needs a human to answer it, not a crash.
|
||||
- BGU mailing list =cs_msc@mlists.cs.bgu.ac.il= (List-Id: =cs_msc.mlists.cs.bgu.ac.il=) floods =/bgu/logistics-cs-msc= with announcement mail that's essentially never read (backlog since Jan 2024, ~330 messages). Intended fix is a Gmail filter in the BGU Workspace webclient (Settings → Filters and Blocked Addresses, matching =list:cs_msc.mlists.cs.bgu.ac.il=, action "mark as read", optionally applied retroactively to existing matches) — not a local/mu4e-side fix, since it's about delivery-time read-state for mail the user doesn't want to individually triage.
|
||||
|
||||
** Key Files
|
||||
- =features/mail/default.nix= — accounts, mbsync/msmtp/mu config, mu init activation script, mbsync-timer systemd service/timer
|
||||
- =azos-core/features/station/emacs/config.org= (search "mu4e") — mu4e contexts, bookmarks, shortcuts, signing blacklist logic
|
||||
- =azos-core/features/station/emacs/_pkg.nix= — mu4e package dependency
|
||||
@@ -0,0 +1,48 @@
|
||||
:PROPERTIES:
|
||||
:ID: 939a9fa3-ddc8-4cc1-8130-771cc5de000f
|
||||
:END:
|
||||
|
||||
#+title: azos/todos
|
||||
#+filetags: :project: :todo:
|
||||
|
||||
Backlink: [[id:bf4dde56-0967-4374-94ed-771301e47c66][azos]]
|
||||
|
||||
* TODO Decouple the exwm and station suites in azos-core
|
||||
|
||||
=azos-core/features/exwm/default.nix= sets =azos.suites.station.enable =
|
||||
lib.mkDefault true;= — already overridable at the suite level with a plain
|
||||
=azos.suites.station.enable = false;= in a machine config, no =mkForce=
|
||||
needed. But =features/exwm/emacs/_pkg.nix= hardcodes
|
||||
=pkgs.azos-emacs-station= in =packageRequires=, and
|
||||
=features/exwm/emacs/config.org= line 8 has an unconditional
|
||||
=(require 'azos-emacs-station)= — this forces =azos-emacs-station= (and its
|
||||
transitive package deps: mu4e, elfeed, elfeed-tube, pass, scad-mode,
|
||||
kubernetes, wttrin) to load regardless of the station suite toggle.
|
||||
|
||||
Grepped exwm's =config.org= for use of station-defined symbols
|
||||
(=azos/mail=, =mu4e=, =elfeed=, =wttrin=, =kubernetes-=, =azos/pass=) and
|
||||
found none — the require looks vestigial, not load-bearing.
|
||||
|
||||
Fix: remove the =require= line and the =packageRequires= entry.
|
||||
|
||||
Softer coupling to also resolve: exwm's =config.org= has quick-launch /
|
||||
window-swallow logic for chromium, qutebrowser, and gimp
|
||||
(=azos/exwm/chromium-p=, =azos/exwm/start-chromium=,
|
||||
=azos/exwm/start-qutebrowser=, the gimp instance-name check), but those
|
||||
*binaries* are installed by station's =browser.nix=/=gimp.nix=, not by
|
||||
exwm. Decide whether to pull those packages into exwm directly or accept
|
||||
them as dead keybindings when station is off.
|
||||
|
||||
Motivation: new Fedora machine will enable the exwm suite but not station.
|
||||
Full architecture notes already saved to [[id:c52036a9-25ec-4b8b-8b72-90fcd9ea65dd][azos/exwm]].
|
||||
|
||||
* TODO Audit non-azos-core features for portability to azos-core
|
||||
|
||||
Go over everything under =/home/aner/azos/features/= (attic, audio,
|
||||
binfmt, bluetooth, chess, claude, encryption, git-config, hardware-auth,
|
||||
headphones, hfsprogs, homey-alert, hyprland, kubernetes, lauretta,
|
||||
leetcode, mail, mpris-proxy, nextcloud, opencode, printing, qutebrowser,
|
||||
reaper, roam-backup, snx-rs, steam, virtualization, ytdl) and assess which
|
||||
are generic/reusable enough to port into =azos-core/features/= for use by
|
||||
the new Fedora machine project, versus which are genuinely
|
||||
lauretta/NixOS-machine-specific and should stay put.
|
||||
@@ -26,6 +26,8 @@ Self-study/knowledge project, not a codebase. See CLAUDE.md for the startup cont
|
||||
- [[ot-ics-security-ramp/glossary]] — quiz-ready term glossary
|
||||
- [[ot-ics-security-ramp/reading-list]] — curated standalone resources
|
||||
- [[ot-ics-security-ramp/todos]] — standing project TODOs
|
||||
- [[ot-ics-security-ramp/protocol-comparison]] — side-by-side ICS/OT protocol comparison tables
|
||||
- [[ot-ics-security-ramp/network-simulator-blueprint]] — research/decision notes for the network-simulator project (MiniCPS chosen)
|
||||
|
||||
[[id:f14796e1-9962-4a0f-a104-ef3c296d60b7][ot-ics-security-ramp/curriculum]]
|
||||
|
||||
@@ -34,3 +36,7 @@ Self-study/knowledge project, not a codebase. See CLAUDE.md for the startup cont
|
||||
[[id:b9c33bd7-da59-412e-9d25-04e47920d9b6][ot-ics-security-ramp/reading-list]]
|
||||
|
||||
[[id:3a365596-7744-43a1-9a2b-53d0dcc087cd][ot-ics-security-ramp/todos]]
|
||||
|
||||
[[id:3650801d-27a1-4119-9768-4a4dfb74606b][ot-ics-security-ramp/network-simulator-blueprint]]
|
||||
|
||||
[[id:d588e9b0-8ad8-4a26-a1ed-62f50957e4a4][ot-ics-security-ramp/protocol-comparison]]
|
||||
@@ -26,6 +26,8 @@ Hybrid approach, not one-size-fits-all:
|
||||
Covered so far (full definitions in [[ot-ics-security-ramp/glossary]]): IT-vs-OT / AIC triad; Purdue Model levels 0-5 + Level 3.5 DMZ; ICS protocols (Modbus, DNP3, IEC 61850/GOOSE, IEC 104, OPC-UA); canonical attack case studies (Stuxnet, Ukraine grid/Industroyer, TRITON/SIS, Metcalf sniper attack); OT vendor landscape (Dragos/Claroty/Nozomi "big three" plus Tenable.ot, MS Defender for IoT, Forescout, Armis, vendor-native); 2026 threat landscape from the Dragos Year in Review (KAMACITE/SYLVANITE/BAUXITE, MSP/GIS as supply-chain targets — see [[ot-ics-security-ramp/reading-list]]); NERC CIP compliance (NERC/FERC/BES scope, electric-only vs water/gas, CIP-002/005/007/008/010/013/014); OT/ICS hands-on lab tools (pymodbus, opendnp3, OpenPLC, GRFICS, Conpot, T-Pot, MiniCPS, ScadaBR).
|
||||
Not yet covered: IR/forensics (queued), general frameworks/compliance beyond NERC CIP (NIST CSF, ISO 27001, SOC 2, CIS Controls, STIX/TAXII), remaining defensive-stack acronyms (EDR/XDR/SIEM/SOAR/NDR/NGFW/IDS/IPS/DLP/ZTNA), cloud security beyond k8s (CSPM/CWPP/CIEM).
|
||||
|
||||
** Protocol Deep-Dive Session (2026-10-06)
|
||||
Completed the priority-redirect protocol session: SNMP (new — manager/agent, MIB/OID, GET/SET/TRAP, v1/v2c plaintext community strings vs. SNMPv3); Modbus (deeper — function codes, four data tables, Modbus Security/TLS retrofit, FrostyGoop case study); DNP3 (deeper — object-based types, unsolicited reporting, DNP3-SA HMAC challenge-response mechanics, Aggressive Mode replay flaw per Cremers et al.); GOOSE (deeper — pub-sub over raw Ethernet L2/multicast MAC, stNum/sqNum and how Industroyer forged them, SCD engineering files, IEC 62351-6, PRP/HSR, process-bus/station-bus segmentation risk); IEC 104 (deeper — ASDU/Information Object typing, port 2404, regional dominance vs. DNP3, IEC 62351-3/5); OPC-UA (deeper — object-oriented address space, X.509/Security Policies, horizontal cross-vendor-interop origin vs. vertical IT/cloud bridging vs. emerging field-level/TSN use). New terms (compensating controls, brownfield/greenfield, MES, etc.) and all new reading resources logged to [[ot-ics-security-ramp/glossary]] and [[ot-ics-security-ramp/reading-list]] as covered, per standing convention. Produced [[ot-ics-security-ramp/protocol-comparison]] as a standalone side-by-side reference across transport, data model, security posture, Purdue level, and known attacks.
|
||||
|
||||
** Status
|
||||
OT/ICS deep-dive in progress. Queued after protocols: IR/forensics, frameworks/compliance, defensive-stack acronyms, cloud security.
|
||||
Priority redirect (2026-10-06): Aner wants ICS/OT protocols in depth next — SNMP, Modbus, plus deeper coverage of already-introduced protocols (DNP3, IEC 61850/GOOSE, IEC 104, OPC-UA) — ahead of IR/forensics.
|
||||
Protocol deep-dive session complete (2026-10-06). Next up per original queue: IR/forensics, then frameworks/compliance (NIST CSF, ISO 27001, SOC 2, CIS Controls, STIX/TAXII), remaining defensive-stack acronyms, cloud security beyond k8s.
|
||||
|
||||
@@ -58,12 +58,23 @@ Running, quiz-ready glossary built up during Aner's cybersecurity terminology ra
|
||||
- Level 3.5 / DMZ — the firewalled buffer zone mediating any traffic between OT (Levels 0-3) and IT (Levels 4-5); the main real-world security boundary in practice.
|
||||
- Air-gapped — historically meant zero physical connectivity between OT and IT; in practice today almost nothing is truly air-gapped, so security work focuses on controlling the Level 3.5 boundary instead.
|
||||
- Passive monitoring — watching a copy of network traffic (via a tap/span port) rather than actively scanning/injecting packets, because active scans can crash fragile field devices never built to handle unexpected input.
|
||||
- Modbus — the oldest/most universal ICS protocol (1979); plaintext, no authentication; the canonical example of "ICS protocols have no security by design."
|
||||
- DNP3 (Distributed Network Protocol) — dominant protocol for North American electric/water utility master-station-to-RTU communication; has an optional auth extension (DNP3-SA) rarely enabled in practice.
|
||||
- SNMP (Simple Network Management Protocol) — general network-device management protocol (not ICS-native, but ubiquitous on the network infrastructure — switches, routers, firewalls, UPSs — surrounding OT, and sometimes on OT devices themselves). Manager/agent model: manager polls or configures an agent via GET/SET; agents can also proactively push a TRAP (e.g. "interface down") without being polled. UDP 161 (agent)/162 (trap). v1/v2c auth is a single plaintext "community string" sent in every request and directly comparable to a password check — no real security, and a successful GET/SET with the default `public`/`private` string can both enumerate a full device inventory and alter live configuration. SNMPv3 adds real user-based authentication and optional encryption, but — same brownfield pattern as DNP3-SA/Modbus Security — is often left disabled. See [[ot-ics-security-ramp/reading-list]] for the NSA/CISA SNMP abuse advisory, including the Russian FSB Center 16 campaign that exfiltrated critical-infrastructure router configs via SNMP.
|
||||
- MIB (Management Information Base) / OID (Object Identifier) — SNMP's data model: a standardized hierarchical tree (defined in ASN.1/SMI) of every manageable variable a device exposes, addressed by an OID (a dotted numeric path from root to leaf, e.g. `1.3.6.1.2.1.1.1.0` = sysDescr). MIB-II is the standard baseline branch nearly every SNMP device implements (interfaces, uptime, routing table); vendors extend into a reserved private-enterprise branch (`1.3.6.1.4.1.<vendor>...`) for proprietary variables. A "MIB walk" (enumerating every OID under a branch) is why read-only SNMP alone is a reconnaissance goldmine — one walk against MIB-II returns a device's full interface/routing/system inventory with no vendor-specific knowledge required. Mechanically, a walk isn't "ask the root for its children" — SNMP has no such operation. It's iterative: `GetNextRequest` returns the next OID in strict lexicographic order after the one you supply, so a walk loops GetNext → take the returned OID → GetNext again, until the result falls outside the starting branch (`GetBulkRequest` in v2c/v3 batches several "next" steps per round trip instead of one at a time). Every call still requires valid auth (community string in v1/v2c) — a walk succeeding against weak/default credentials isn't an auth bypass, it's auth trivially satisfied. A device's MIB only describes *itself* (its own interfaces/CPU/routing table), not devices it merely forwards traffic for — except via neighbor-discovery branches like Cisco's CDP-MIB or the vendor-neutral LLDP-MIB, which let a device report what's directly connected to each of its own ports, the closest SNMP gets to mapping adjacent devices one hop at a time.
|
||||
- ACL (Access Control List) — a rule set on a device/network boundary (router, switch, firewall) specifying which source addresses/ports/protocols may reach a given service. Not a per-protocol auth mechanism itself — it operates at the network layer, restricting *who can even attempt* a request (e.g. restricting which hosts may query a device's SNMP agent at all) independent of whatever credential/auth check the service itself performs. A common compensating control for protocols with weak native auth (SNMP, Modbus, DNP3): even if the protocol-level security is trivial to satisfy, an ACL can still block the request from ever arriving if the source isn't on the allowed list.
|
||||
- Modbus — the oldest/most universal ICS protocol (1979, Modicon); originally serial (RTU/ASCII), later Modbus TCP (port 502). Master/slave (client/server) request-response only, addressing four flat tables (coils, discrete inputs, holding registers, input registers) via function codes (FC01 read coils, FC03 read holding registers, FC05/FC06/FC16 writes). No authentication, no encryption, no sender-identity check — any client reaching port 502 can issue any function code; the canonical example of "ICS protocols have no security by design." Modbus Security (TLS retrofit, ~2018) exists but is rarely enabled in the field, same adoption story as DNP3-SA.
|
||||
- Modbus Plus (Modbus+) — a separate, proprietary Schneider Electric/Modicon network protocol, not the same wire format as standard Modbus RTU/ASCII/TCP. Token-passing (not master-slave) so multiple PLCs can initiate as peers; 1 Mbps over shielded twisted-pair with deterministic timing, proprietary HDLC-derived data link layer incompatible with standard Modbus framing (needs a bridge/gateway to talk to it). Mostly legacy now, superseded by Modbus TCP/IP. Same no-auth/no-encryption weakness as standard Modbus, just rarer in the wild so less commonly targeted/tooled-for.
|
||||
- Compensating controls / defense-in-depth — when a weakness can't be fixed at its source (e.g. an inherently insecure field protocol), layer protections around it instead (network segmentation, monitoring, access control). The practical justification for the Purdue Level 3.5 DMZ: Modbus/DNP3/GOOSE can't be secured on their own, so security gets pushed to the perimeter/network layer instead.
|
||||
- Brownfield vs. greenfield — brownfield = existing legacy installed equipment (the overwhelming majority of OT/ICS, often running protocols/hardware decades old); greenfield = new builds designed from scratch. OT field devices commonly have 20-30 year lifecycles, so replacing a protocol in the field usually means replacing working hardware, not just patching software — a major reason insecure legacy protocols persist.
|
||||
- DNP3 (Distributed Network Protocol) — dominant protocol for North American electric/water utility master-station-to-RTU communication. Richer than Modbus: object-based data types with built-in semantics (Binary/Analog Input/Output, Counters) rather than anonymous flat registers, plus unsolicited reporting (an outstation can push event-driven updates without being polled — useful over slow serial/radio links, but an extra unauthenticated inbound-trigger surface). Originally serial (Data Link Layer framing + per-block CRC → Transport Function reassembly → Application Layer data); DNP3 over TCP (port 20000) tunnels that same serial-era framing inside TCP rather than replacing it the way Modbus-TCP's MBAP header does.
|
||||
- DNP3-SA (Secure Authentication, IEEE 1815) — optional auth extension, rarely enabled in practice. Only protects *critical* function codes (control/operate/config-change), not routine polls/reads, as a deliberate latency tradeoff. Uses HMAC-based challenge-response rather than a static shared secret (like SNMP's community string, sent in cleartext and directly replayable): outstation sends a random nonce Challenge, master replies with an HMAC of that nonce under a pre-shared session key (the key itself never crosses the wire), outstation verifies by recomputing the same HMAC — a sniffed Challenge/Reply pair is useless for a different operation. Session keys rotate via a separate key-update exchange from longer-lived per-user-role "update keys," giving per-operator accountability a static secret can't. Full challenge-response costs a round trip per critical command, which is real overhead over slow serial/radio links — "Aggressive Mode" exists to cut that round trip by having the master proactively attach its HMAC without waiting for a fresh challenge, but formal analysis (Cremers et al. 2019; Coloured Petri Net modeling) found this reintroduces a replay flaw: a captured Aggressive Mode message can be replayed to execute reads/writes/application launches on the outstation without ever possessing the session key. Net effect: real deployment of DNP3-SA remains limited by both legacy device constraints and genuine real-time-latency requirements, so most operational DNP3 traffic today is still plaintext.
|
||||
- IEC 61850 — modern substation automation standard for electric utilities; includes GOOSE messages.
|
||||
- GOOSE (Generic Object Oriented Substation Event) — peer-to-peer protection-relay messages requiring single-digit-millisecond delivery, with essentially no authentication due to the speed requirement; a known attack surface (used in the 2016 Ukraine grid attack, Industroyer malware).
|
||||
- IEC 60870-5-104 ("IEC 104") — DNP3's rough European/Middle-East equivalent protocol.
|
||||
- OPC-UA — a newer IT/OT bridging protocol (e.g. historian-to-cloud) that, unlike the field-level protocols above, was built with authentication and encryption from the start.
|
||||
- GOOSE (Generic Object Oriented Substation Event) — publish-subscribe (not request-response) protection-relay messaging requiring single-digit-millisecond delivery, with essentially no authentication due to the speed requirement; a known attack surface (used in the 2016 Ukraine grid attack, Industroyer malware). Runs directly on raw Ethernet Layer 2 (EtherType 0x88B8) to a reserved multicast MAC range (01-0C-CD-01-xx-xx) — no IP, no TCP/UDP, so ordinary L3 routers can't route it (nothing to route on) though ordinary L2 switches handle it fine, just flooding to every port on the VLAN (no IGMP-style group pruning, since that's IP-layer). Reliability comes from repetition, not acknowledgment: publisher retransmits the same state at a fast-then-slowing interval; a State Number (stNum, increments only on real state changes) plus Sequence Number (sqNum, increments per retransmission) is what Industroyer forged — crafting a higher stNum than the legitimate relay to make a spoofed "breaker open" look like the newest valid state. All publish/subscribe wiring (which multicast address/dataset maps to which relay) is statically pre-engineered in a Substation Configuration Description (SCD) file loaded onto each IED at commissioning time, not negotiated at runtime — so once an attacker has that config (via traffic capture or a leaked SCD file), forged frames work indefinitely, no handshake to invalidate them.
|
||||
- IEC 62351-6 — the security extension for GOOSE/Sampled Values/MMS, adding a digital signature for authentication/integrity (not encryption — confidentiality isn't the goal on an assumed-physically-secured substation LAN). Low real-world adoption, and not just from brownfield inertia like Modbus/DNP3-SA: the original RSA-signature scheme is often too slow for the sub-4ms timing budget on older relay hardware, a genuine unresolved engineering tension rather than pure organizational inertia; later proposals shift to faster symmetric-key MAC schemes to try to fit the budget.
|
||||
- PRP / HSR (Parallel Redundancy Protocol / High-availability Seamless Redundancy, IEC 62439) — substation network resilience standards that send duplicate frames over two independent physical paths simultaneously, giving zero-recovery-time failover if one link/switch dies. Distinct from GOOSE's own retransmission-based reliability, which only covers random packet loss, not a dead physical path.
|
||||
- Process bus / station bus — the dedicated, VLAN-segmented (sometimes physically separate) Ethernet network a substation runs GOOSE/Sampled Values on, kept apart from general SCADA/IT traffic for two reasons: (1) latency contention — ordinary traffic queuing ahead of a time-critical trip message, (2) security — Ethernet doesn't distinguish IP packets from GOOSE frames on the wire, so any compromised host sharing that L2 segment can craft and inject raw GOOSE frames directly (exactly what Industroyer did), with no "GOOSE-specific access" required. Segmentation here is the control meant to keep an IP-side compromise from ever reaching that segment — in budget-constrained or poorly-designed substations this isolation is sometimes incomplete, a real rather than theoretical risk.
|
||||
- IEC 60870-5-104 ("IEC 104") — DNP3's rough equivalent dominant in Europe/Middle East/Asia/Africa (DNP3 dominates North America); if you see TCP port 2404 in a capture, it's almost certainly non-US utility telemetry. The IP-networked version of the older serial IEC 60870-5-101 (104-to-101 is roughly what Modbus-TCP is to Modbus-serial). Master-slave (controlling/controlled station), not pub-sub. Data carried as ASDUs (Application Service Data Units) containing typed Information Objects (Type Identification field marks e.g. single-point info, measured value, command) — gives semantic typing Modbus's flat registers lack, similar in spirit to DNP3's object model. No authentication/encryption/integrity in the base spec, same as Modbus/DNP3-without-SA; IEC 62351-3/5 defines a TLS security retrofit, same low-adoption brownfield story as everything else.
|
||||
- OPC-UA — platform-independent successor to the original OPC (built on Windows-only COM/DCOM, a firewall nightmare); own binary protocol on TCP port 4840 or an HTTPS binding. Unlike field protocols' flat/typed-but-static registers, exposes a genuine object-oriented, self-describing address space (Nodes: variables, methods, types, relationships) a client can browse/discover at runtime. Real built-in security, not retrofitted: X.509 certs for mutual client/server auth, configurable Security Policies (None/Sign/SignAndEncrypt) with a defined cipher-suite-like profile stack (Basic256Sha256 etc.) — though "Security Policy: None" is a valid, sometimes-used setting that defeats all of it. Primary/original use case is horizontal: cross-vendor interoperability between different Level 2/3 systems (SCADA-to-historian, historian-to-MES, HMI-to-SCADA) — solving the "every vendor has a proprietary driver" problem OPC was founded to fix. Increasingly also vertical: Level 2/3 (historian/SCADA) up to Level 4/5 IT/cloud/analytics, crossing the DMZ. At the leading edge, pushed down to the field level too — modern PLCs (Siemens S7-1500, Beckhoff, Rockwell) often ship a native OPC-UA server directly on the controller, and OPC-UA over TSN (Time-Sensitive Networking) is an emerging effort toward real-time field-level use, a long-horizon candidate to someday displace protocols like Modbus or GOOSE. Doesn't retroactively secure the field-level protocols underneath it — it secures the bridge/interop layer it operates at, nothing lower.
|
||||
- MES (Manufacturing Execution System) — Purdue Level 3 software managing/tracking production on the plant floor in real time (work orders, batch tracking, quality, OEE) — sits between the Historian/SCADA (Level 2/3, process data) and ERP (Level 4, business/planning data). A common OPC-UA peer: SCADA/historian-to-MES and MES-to-ERP are typical OPC-UA interoperability links.
|
||||
- S7 — Siemens' proprietary ICS protocol for communicating with SIMATIC PLCs (S7-300/1200/1500 etc.), port 102/TCP; like Modbus/DNP3, a frequent target for ICS network scanning.
|
||||
- CODESYS — the IEC 61131-3 engineering/runtime environment (port 11740/TCP) underlying many different vendors' PLCs, including WAGO's — a shared software base means a CODESYS vulnerability can cross vendor lines.
|
||||
- VFD (Variable Frequency Drive) — a device that controls motor speed by varying the frequency/voltage of its power supply; common ICS target (pumps, fans, compressors) alongside PLCs.
|
||||
@@ -81,7 +92,7 @@ Covered 2026-10-05 in response to "how do I build a fake OT network to play with
|
||||
- GRFICS (Graphical Realism Framework for Industrial Control Simulations) — Georgia Tech project providing a full prebuilt virtual plant (simulated chemical process + HMI + PLC logic + documented attack scenarios) as VMs, built explicitly for cybersecurity teaching/research. Closest thing to an "accepted standard" fake OT environment to attack.
|
||||
- Conpot — low-interaction ICS honeypot, defaults to impersonating a Siemens S7-300 PLC; speaks Modbus, S7comm, BACnet, SNMP, HTTP simultaneously. Good for observing what scanning/exploitation traffic looks like against a fake device; not meant for realistic control logic.
|
||||
- T-Pot — docker-compose bundle of Conpot plus a dozen other honeypots (IT + OT), with a Kibana dashboard of all captured attack traffic. Useful for the "SOC watching attacks land" view rather than the device-builder view.
|
||||
- MiniCPS — Mininet-based framework for simulating networks of multiple PLCs/RTUs with physical process models; used in academic SWaT/WADI-style water-treatment-plant research. Heavier/academic, overkill unless specifically doing network-topology-level ICS research.
|
||||
- MiniCPS — Mininet-based (network namespaces + virtual Ethernet, not Docker containers) framework for simulating ICS networks at scale; topology and PLC devices defined in real Python (Mininet Topo subclass; PLC subclass with pre_loop()/main_loop()), not a config file. Ships the actual SWaT (Secure Water Treatment) testbed scenario alongside a minimal toy example — most academically credentialed of the open-source ICS simulators. No bundled attacker/traffic-observer tooling; MIT licensed, actively maintained. Chosen (2026-10-06) as the foundation for the planned network-simulator project specifically for its lightweight namespace-based scaling over Docker-per-device isolation — see [[ot-ics-security-ramp/network-simulator-blueprint]] for the full comparison against ICSSIM/ICS-SimLab.
|
||||
- ScadaBR — open-source HMI/SCADA software, commonly paired with OpenPLC to get a realistic-looking operator dashboard on top of real PLC logic.
|
||||
|
||||
** OT Attack Case Studies
|
||||
@@ -89,6 +100,7 @@ Covered 2026-10-05 in response to "how do I build a fake OT network to play with
|
||||
- Ukraine grid attacks (2015, 2016) — first confirmed cyberattacks to cause a power outage. 2015: Sandworm (Russian GRU-linked) phished into utility IT, pivoted to OT, manually opened substation breakers via SCADA HMI (~230,000 people lost power). 2016: follow-up used Industroyer malware, the first malware built to natively speak ICS protocols (including IEC 61850 GOOSE) to automate breaker control at scale instead of manual HMI clicks.
|
||||
- TRITON / TRISIS (2017) — targeted a Saudi petrochemical plant's Safety Instrumented System (SIS) — the independent emergency-shutdown layer that exists to prevent physical catastrophe (explosion, toxic release). Reprogrammed Schneider Electric SIS controllers; a bug in the attacker's own code accidentally triggered a shutdown, likely preventing serious harm. The case study proving OT attacks carry real physical/safety risk, not just theoretical danger.
|
||||
- SIS (Safety Instrumented System) — an independent hardware/software layer that triggers automatic emergency shutdown if a process becomes physically dangerous, separate from the normal control system.
|
||||
- FrostyGoop (2024) — malware that injected Modbus TCP commands directly against district-heating ICS controllers in Ukraine, disabling heating to apartment buildings during winter; notable as a protocol-native attack requiring no exploit, just valid-looking Modbus writes to the right registers (same "no authentication to distinguish attacker from legitimate master" pattern as the 2015 Ukraine grid breaker attack). Predecessor VPNFilter (2018) only sniffed/exfiltrated Modbus TCP traffic rather than injecting commands.
|
||||
- Metcalf sniper attack (2013) — attackers shot up a PG&E transmission substation in California, knocking out 17 transformers. Physical, not cyber, but the case study behind NERC CIP-014 (mandating physical security planning for critical substations) — cited to make the point that critical-infrastructure risk isn't purely digital.
|
||||
- Private-APN CHP plant incident (Poland, 29 Dec 2025; CERT Polska follow-up report) — attacker pivoted from a compromised wind-farm FortiGate VPN/firewall, through a Teltonika cellular router's SSH tunnel, across a DSO private APN lacking client isolation, into a WAGO PFC200 gateway PLC reachable via default web-admin credentials, then via a further SSH tunnel into an unrelated CHP plant's OT network — stopping Siemens S7-300/1200/1500 PLCs and shutting down a steam turbine and water treatment system. First known real-world attack to use a private APN as a lateral-movement path between otherwise-unconnected facilities; the attacker also destroyed the WAGO device's partition table as anti-forensics.
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
:PROPERTIES:
|
||||
:ID: 3650801d-27a1-4119-9768-4a4dfb74606b
|
||||
:END:
|
||||
|
||||
#+title: ot-ics-security-ramp/network-simulator-blueprint
|
||||
#+filetags: :project: :knowledge: :cybersecurity: :network-simulator:
|
||||
|
||||
Research/blueprint notes for the "network simulator project" TODO in [[ot-ics-security-ramp/todos]] (targeted for the week after 2026-10-06). Goal: an auto-network-creation tool to generate ICS/OT networks for educational attack/defense practice, building on the hands-on lab tools already catalogued in [[ot-ics-security-ramp/glossary]].
|
||||
|
||||
** Decision (2026-10-06)
|
||||
Foundation: **MiniCPS** (https://github.com/scy-phy/minicps), chosen over ICSSIM and ICS-SimLab.
|
||||
Why: core requirement is simulating at *scale* (many devices/topology size), not per-device isolation. MiniCPS is Mininet-based — devices are lightweight Linux network-namespace processes with virtual Ethernet links, not full Docker containers, so it scales to much larger topologies per host than the Docker-per-device model ICSSIM/ICS-SimLab both use. Per-device filesystem/cgroup isolation (Docker's main advantage) isn't a requirement here.
|
||||
Tradeoffs accepted: topology/devices defined in real Python code (Mininet `Topo` subclass, PLC base-class subclasses with `pre_loop()`/`main_loop()`), not a declarative config file like ICS-SimLab's JSON; no bundled attacker-script tooling or traffic-observer component (unlike ICSSIM) — these will need to be built/ported separately. MIT licensed, actively maintained (commits into 2026), real SWaT/WADI testbed examples included (`examples/swat-s1`) alongside a minimal `examples/toy`.
|
||||
|
||||
** Options Considered
|
||||
|
||||
*** MiniCPS (chosen) — https://github.com/scy-phy/minicps
|
||||
- Mininet-based: network namespaces + veth links, not containers. Lightweight, scales well.
|
||||
- Topology/devices defined in Python (Topo subclass; PLC subclass with pre_loop/main_loop, tag tuples mapping sensor/actuator names to memory addresses).
|
||||
- Most academically credentialed: built by SUTD SCy-Phy group, includes real SWaT (Secure Water Treatment) testbed scenario, not just synthetic demos.
|
||||
- No bundled attacker scripts or observer/flow-logging component — security research relies on running standard Linux tools (tcpdump/scapy/arpspoof) directly against namespaced hosts.
|
||||
- MIT license. Actively maintained (last commit 2026-06-16); older readthedocs install notes mention "Python 2.X" — likely stale given recent pyproject.toml modernization, but unverified — check directly before relying on it.
|
||||
|
||||
*** ICSSIM — https://github.com/AlirezaDehlaghi/ICSSIM
|
||||
- Docker-based, one container per device (PLC/HMI/Attacker/HIL), MIT licensed.
|
||||
- No topology constraints — fully custom via code, three published example scenarios (smart grid, water bottling, IED network) are just demos, not limits.
|
||||
- Tier 1-2 (HIL-PLC "wiring") faked via shared memory; Tier 2-3 (PLC-HMI) is a real Docker bridge network with genuine Modbus-TCP/Modbus-RTU(via socat) packets.
|
||||
- Ships an Attack Generator: mostly thin shell scripts wrapping standard tools (nmap/ping/scapy/ettercap for recon/MITM/replay — portable to any Docker network with zero changes) plus two Python agent classes needing protocol-aware glue (CommandInjectionAgent, DDosAgent).
|
||||
- "Observer" component described in the paper not found in ICSSIM's own src/ — likely actually the separate companion repo **ICSFlow** (https://github.com/AlirezaDehlaghi/ICSFlow, MIT), which sniffs a live interface or PCAP, aggregates to flow records, and labels them from ICSSIM's `logs/attack-logs/` format, a pre-trained ML model, or packet metadata. Since it just sniffs an interface, ICSFlow should work against MiniCPS's traffic too with no porting needed (minus the auto-labeling, which assumes ICSSIM's specific log format).
|
||||
|
||||
*** ICS-SimLab — https://github.com/JaxsonBrownie/ICS-SimLab
|
||||
- Docker-based, one container per device, MIT licensed (corrected 2026-10-06 — an earlier search had wrongly suggested CC BY 4.0).
|
||||
- Models Purdue Levels 0-2 only (Sensor/Actuator/HIL, PLC, HMI) — no SCADA/historian/Level 3+, no attacker component at all.
|
||||
- Config is declarative JSON (`configuration.json` + a `logic/` directory of Python for HIL process behavior) — devices get name/network/registers(Modbus coils/discrete/holding/input)/connections/monitors/controllers. Arbitrary custom topologies supported, not locked to the three shipped demos (smart grid, water bottling, IED network).
|
||||
- Distinctive design: physical process state centralized in a single SQLite3 DB — sensors read from it, actuators write to it, HIL modules evolve it per custom logic. Simpler/more inspectable than shared-memory IPC, less "realistic" to real hardwired I/O.
|
||||
- Supports both Modbus-TCP (Docker network) and Modbus-RTU (virtual serial via socat).
|
||||
- Paper accepted at First International Workshop on Secure ICS and Industrial IoT (2025).
|
||||
|
||||
*** tymyrddin/ics-access-simlab — https://codeberg.org/tymyrddin/ics-access-simlab (reference only, not selected)
|
||||
- Different project despite similar name to ICS-SimLab above (different author).
|
||||
- Network-topology/segmentation simulator, not a device simulator: 5-zone Purdue-mapped network (internet/enterprise/operational/control/DMZ) with real FRR routers + deny-by-default iptables between zones, built on containerlab + Linux bridges.
|
||||
- Design philosophy: vulnerabilities are intrinsic to how the topology/firewall rules are built, not toggled flags; built for red-team/CTF lateral-movement practice, not protocol-level device research.
|
||||
- License: **Polyform Noncommercial** — not OSI-approved open source; free for learning/research/defense, requires a commercial license for paid training/consultancy/corporate use. Could be complementary (network/segmentation layer) to a device simulator like MiniCPS/ICSSIM for the Control-zone contents, but the license rules it out if this ever needs to be used commercially.
|
||||
|
||||
** Open Questions / Next Steps
|
||||
- Attacker tooling for MiniCPS: nothing bundled: plan to either write directly against namespaced hosts (tcpdump/scapy/arpspoof, same as any Linux host) or port ICSSIM's shell-script wrappers (scan-nmap.sh etc. need no protocol awareness, so should port with minimal change).
|
||||
- Traffic observation: evaluate pointing ICSFlow directly at a MiniCPS-generated network's interface — likely works unmodified for raw flow capture; auto-labeling would need either replicating ICSSIM's attack-log format or using ICSFlow's other labeling modes.
|
||||
- Verify current Python version support in MiniCPS before building on it (stale Python 2.X mention in docs vs. recent pyproject.toml modernization).
|
||||
- Not yet scoped: how "auto-generation" of topology/devices (the actual point of this project) will work on top of MiniCPS's Python Topo-class API — likely a generator that programmatically emits Topo subclasses + PLC device scripts from a higher-level spec, analogous to what ICS-SimLab's JSON config does declaratively.
|
||||
@@ -0,0 +1,68 @@
|
||||
:PROPERTIES:
|
||||
:ID: d588e9b0-8ad8-4a26-a1ed-62f50957e4a4
|
||||
:END:
|
||||
|
||||
#+title: ot-ics-security-ramp/protocol-comparison
|
||||
#+filetags: :project: :knowledge: :cybersecurity: :protocols: :reference:
|
||||
|
||||
Side-by-side quick-reference comparing the ICS/OT protocols covered in [[ot-ics-security-ramp/curriculum]] (deep-dive session 2026-10-06). Full prose definitions live in [[ot-ics-security-ramp/glossary]] — this node is for comparison at a glance, not canonical definitions.
|
||||
|
||||
** Transport / Addressing
|
||||
|
||||
| Protocol | Transport | Port/Layer | Topology |
|
||||
|----------+---------------------------------------------------+-------------------------------------+--------------------------------------------|
|
||||
| Modbus | Serial (RTU/ASCII) or TCP | TCP 502 | Master/slave (req-resp) |
|
||||
| DNP3 | Serial or TCP (tunnels serial framing inside TCP) | TCP 20000 | Master/outstation (req-resp + unsolicited) |
|
||||
| IEC 104 | TCP (IP version of serial IEC 101) | TCP 2404 | Controlling/controlled station (req-resp) |
|
||||
| GOOSE | Raw Ethernet, no IP/TCP/UDP at all | L2, EtherType 0x88B8, multicast MAC | Publish-subscribe |
|
||||
| OPC-UA | Own binary protocol, or HTTPS | TCP 4840 or HTTPS | Client/server, cross-vendor interop |
|
||||
| SNMP | UDP | UDP 161 (agent), 162 (trap) | Manager/agent (poll + trap push) |
|
||||
|
||||
** Data Model
|
||||
|
||||
| Protocol | Data model |
|
||||
|----------+-------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Modbus | Flat, untyped: coils / discrete inputs / holding registers / input registers, addressed by number only — no semantic meaning in the wire format |
|
||||
| DNP3 | Object-based with real semantics: Binary/Analog Input/Output, Counters |
|
||||
| IEC 104 | ASDUs containing typed Information Objects (Type Identification field: single-point info, measured value, command, ...) |
|
||||
| GOOSE | Dataset of pre-engineered values per GOOSE Control Block, identified by stNum/sqNum for state/retransmission tracking |
|
||||
| OPC-UA | Full object-oriented address space: Nodes (variables, methods, types, relationships), self-describing and browsable at runtime |
|
||||
| SNMP | MIB tree of named values addressed by OIDs (dotted-numeric path) |
|
||||
|
||||
** Security Posture
|
||||
|
||||
| Protocol | Built-in security | Retrofit extension | Real-world adoption of retrofit |
|
||||
|----------+--------------------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------------------------------------------------------------|
|
||||
| Modbus | None | Modbus Security (TLS, ~2018) | Rare |
|
||||
| DNP3 | None | DNP3-SA (IEEE 1815, HMAC challenge-response) | Rare; Aggressive Mode has a known replay flaw |
|
||||
| IEC 104 | None | IEC 62351-3/5 (TLS) | Rare |
|
||||
| GOOSE | None (sub-4ms budget leaves no room) | IEC 62351-6 (digital signature) | Very rare — genuine timing-vs-security tension, not just inertia |
|
||||
| OPC-UA | Real, from the start: X.509 mutual auth, Sign/SignAndEncrypt modes | N/A — native | "Security Policy: None" is valid and often left set anyway; ~80% of exposed servers found in plaintext (2026 scan data) |
|
||||
| SNMP | v1/v2c: plaintext community string only (no real auth) | SNMPv3 (real auth + encryption) | Often not enabled; v1/v2c still common |
|
||||
|
||||
** Purdue Level / Typical Role
|
||||
|
||||
| Protocol | Typical Purdue level | Typical use |
|
||||
|----------+-----------------------------------------------------------------------+-----------------------------------------------------------------------------|
|
||||
| Modbus | Level 0-1 | PLC/RTU to field I/O, SCADA polling |
|
||||
| DNP3 | Level 1-2 | Utility master station to RTU, esp. electric/water, North America |
|
||||
| IEC 104 | Level 1-2 | Utility master station to RTU, Europe/Middle East/Asia/Africa |
|
||||
| GOOSE | Level 0-1 | Peer-to-peer protection-relay coordination within a substation |
|
||||
| OPC-UA | Level 2-4 (increasingly pushed to Level 1 on modern PLCs) | Cross-vendor interop (SCADA-historian-MES), and Level 2/3-to-cloud bridging |
|
||||
| SNMP | Network infrastructure (switches/routers/firewalls around all levels) | Device health monitoring, not process control |
|
||||
|
||||
** Known Real-World Attacks
|
||||
|
||||
| Protocol | Case study |
|
||||
|----------+------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Modbus | FrostyGoop (2024) — injected Modbus TCP commands to disable district heating, Ukraine |
|
||||
| DNP3 | No single named malware yet exploiting DNP3 directly at scale; risk is mainly from it being unauthenticated by default |
|
||||
| IEC 104 | No single named malware yet exploiting IEC 104 directly at scale; same unauthenticated-by-default risk |
|
||||
| GOOSE | Industroyer (2016) — forged GOOSE stNum to spoof breaker-open state, Ukraine grid |
|
||||
| OPC-UA | No single named malware yet; risk driven by internet-exposed misconfigurations (Security Policy: None) rather than a protocol flaw |
|
||||
| SNMP | Russian FSB Center 16 — exfiltrated critical-infrastructure router configs via SNMP + Cisco Smart Install |
|
||||
|
||||
** Regional / Vendor Notes
|
||||
- DNP3 dominates North America; IEC 104 dominates Europe/Middle East/Asia/Africa — functionally parallel protocols serving the same utility master-to-RTU role in different regions.
|
||||
- OPC-UA's founding purpose was horizontal cross-vendor interoperability (replacing the Windows-only COM/DCOM-based original OPC); vertical IT/cloud bridging and field-level PLC-native deployment are both newer extensions of that original role.
|
||||
- SNMP isn't an ICS-native protocol at all — it rides alongside the other protocols on the same network infrastructure (switches, routers, sometimes OT devices themselves, as Conpot's multi-protocol emulation reflects).
|
||||
@@ -10,3 +10,9 @@ Curated, high-quality cybersecurity resources Aner has found worth reading (and
|
||||
** OT/ICS Security
|
||||
- [[https://www.sans.org/blog/top-takeaways-from-the-dragos-ot-cybersecurity-report-2026][SANS: Top Takeaways from the Dragos OT Cybersecurity Report 2026]] — free, ungated, substantial summary of Dragos's annual OT threat report. Covers 8 key 2026 OT threat shifts (adversaries staging environments months ahead, targeting HMIs/VFDs/meters/gateways to map process dependencies, initial-access-as-a-service mirroring IT ransomware ecosystems, disruption without ICS-specific payloads, engineering firms/integrators/MSPs as supply-chain targets, hacktivist groups going destructive) and names three threat groups: KAMACITE, SYLVANITE, BAUXITE. Recommended by Aner (2026-09-29) as genuinely good reading — worth recommending to others, not just personal reference. Read 2026-10-06.
|
||||
- [[https://www.dragos.com/ot-cybersecurity-year-in-review][Dragos 2026 OT Cybersecurity Year in Review]] (full 91-page report + exec summary) — the primary source the SANS writeup above is based on. Gated behind a lead-gen form requiring a phone number; the SANS summary covers the substance without it. Aner decided (2026-10-06) not to read the full report — the SANS summary is sufficient.
|
||||
|
||||
** Protocol / Network Deep-Dives
|
||||
- [[https://media.defense.gov/2026/Jul/09/2003959459/-1/-1/0/CSI_REDUCING_RISK_OF_SNMP_ABUSE.PDF][NSA/CISA CSI: Reducing the Risk of SNMP Abuse]] (2026-07-09) — joint US government cybersecurity advisory on SNMP abuse specifically in critical-infrastructure contexts. Covers v1/v2c plaintext community-string exposure, GET-based network/device-inventory reconnaissance, SET-based config tampering, and cites the Russian FSB Center 16 campaign that exfiltrated router configs (VPN configs, SCADA-network routing, credentials) from critical-infrastructure perimeter routers via SNMP + Cisco Smart Install — a real-world OT-relevant case study. Read 2026-10-09.
|
||||
- [[https://redbotsecurity.com/examining-the-modbus-protocol/][RedBot Security: Examining the Modbus Protocol Through an Offensive-Security Lens]] — offensive/pentester-oriented deep-dive on Modbus TCP: function-code abuse, lack of auth/encryption/integrity, replay/MITM/DoS/command-injection patterns. Complements the FrostyGoop (2024) case study — malware that injected Modbus TCP commands to disable heating in Ukrainian apartment buildings, the modern successor to VPNFilter's 2018 Modbus traffic sniffing. Queued for review 2026-10-06.
|
||||
- [[https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7926645/][Vulnerability and Impact Analysis of the IEC 61850 GOOSE Protocol in the Smart Grid]] (open-access journal paper) — experimental analysis of GOOSE pub-sub weaknesses, showing an attacker with substation-network familiarity can falsify messages affecting real physical grid operation; covers why many vendor IEDs still ship without IEC 62351-6 encryption/signing since the overhead can exceed the end-to-end latency budget. Queued for review 2026-10-06.
|
||||
- [[https://claroty.com/team82/research/opc-ua-deep-dive-a-complete-guide-to-the-opc-ua-attack-surface][Claroty Team82: OPC UA Deep Dive — A Complete Guide to the OPC UA Attack Surface]] — comprehensive attack-surface writeup from an OT security vendor's research team; relevant given current data (2026) showing over half of internet-exposed OPC-UA servers allow unauthenticated access and ~80% transmit in plaintext despite the protocol's built-in security options existing — "Security Policy: None" being valid and widely left set. Queued for review 2026-10-06.
|
||||
|
||||
@@ -8,4 +8,6 @@
|
||||
Standing TODOs for [[ot-ics-security-ramp]].
|
||||
|
||||
* TODO Continue cyber curriculum per [[ot-ics-security-ramp/curriculum]] — next up: IR/forensics, then frameworks/compliance (NIST CSF, ISO 27001, SOC 2, CIS Controls, STIX/TAXII), remaining defensive-stack acronyms, cloud security
|
||||
* TODO Learn ICS/OT protocols in depth — SNMP, Modbus, and others (DNP3, IEC 61850/GOOSE, IEC 104, OPC-UA already covered per [[ot-ics-security-ramp/curriculum]])
|
||||
* DONE Learn ICS/OT protocols in depth — SNMP, Modbus, and others (DNP3, IEC 61850/GOOSE, IEC 104, OPC-UA already covered per [[ot-ics-security-ramp/curriculum]])
|
||||
* TODO Build a network simulator project (targeted for next week, not this week) — foundation decided 2026-10-06: MiniCPS (Mininet-based, chosen for scale over ICSSIM/ICS-SimLab's Docker-per-device isolation). Full comparison and open questions in [[ot-ics-security-ramp/network-simulator-blueprint]].
|
||||
* DONE Make a standalone ICS/OT protocol comparison reference — done 2026-10-06 as an org table node, [[ot-ics-security-ramp/protocol-comparison]]. If a rendered PDF/HTML version is wanted later, revisit format then.
|
||||
|
||||
+5
-2
@@ -5,8 +5,11 @@
|
||||
#+title: workplate
|
||||
#+filetags: :workplate: :planning:
|
||||
|
||||
* Today (2026-10-06 Tue)
|
||||
** TODO [half-day] (ot-ics-security-ramp) ICS/OT protocol deep-dive — SNMP, Modbus, and refresher on DNP3/IEC 61850 GOOSE/IEC 104/OPC-UA
|
||||
* Today (2026-10-07 Wed)
|
||||
** TODO [quick] (ot-ics-security-ramp) Review GOOSE vulnerability/impact-analysis paper (see reading-list)
|
||||
** TODO [quick] (ot-ics-security-ramp) Review Claroty Team82 OPC UA attack-surface deep dive (see reading-list)
|
||||
** TODO [quick] (ot-ics-security-ramp) Curriculum refresher before IR/forensics — quick re-read of curriculum/glossary status
|
||||
** TODO [half-day] (ot-ics-security-ramp) Continue cyber curriculum — IR/forensics
|
||||
|
||||
* This Week (2026-10-05 to 2026-10-11)
|
||||
** TODO [few-hours] (just-talking) Review LangGraph (per manager's instructions)
|
||||
|
||||
Reference in New Issue
Block a user