Skip to content

fix(intel-driven): UnDefend SYSTEM-context + RedSun/BlueHammer EICAR quarantine-check timing#55

Open
ubercylon8 wants to merge 1 commit into
mainfrom
fix/defender-evasion-test-reporting-bugs
Open

fix(intel-driven): UnDefend SYSTEM-context + RedSun/BlueHammer EICAR quarantine-check timing#55
ubercylon8 wants to merge 1 commit into
mainfrom
fix/defender-evasion-test-reporting-bugs

Conversation

@ubercylon8
Copy link
Copy Markdown
Owner

Summary

Two observation-logic bugs introduced in the 2026-04-24 Defender-evasion test batch caused incorrect exit-code reporting. The tests still exercise the same Win32 API primitives — only the result-evaluation logic is fixed.

Bug 1 — UnDefend Stage 3 SYSTEM-context prerequisite gap
NotifyServiceStatusChangeW on WinDefend requires SYSTEM context (or SeServiceLogonRight). When the stage ran as a non-elevated user, the access-denied return from the API was misclassified by classifyError() as StageBlocked (exit 126) — a false positive that inflated the overall exit-code roll-up. The stage should have skipped cleanly.

Bug 2 — RedSun/BlueHammer EICAR quarantine-check timing window
Both stages dropped EICAR, slept 3 seconds, then did a single os.Stat to check quarantine. Defender's quarantine action fires ~5 seconds after the drop, so the stage process exited before quarantine completed and reported 101 UNPROTECTED. System event log 1116/1117 confirmed Defender actually caught the file in the lab run.

Files changed

Test File Fix
UnDefend (6a2351ac) stage-T1562.001-svcnotify.go Add isSystemContext() guard at stage entry; skip cleanly (exit 0 + LogStageEnd skipped) when not SYSTEM
RedSun (0d7e7571) stage-T1211.go Replace single 3s sleep + os.Stat with 10×1s retry loop (10s total window)
BlueHammer (5e59dd6a) stage-T1211-cfapi.go Same 10×1s retry loop fix as RedSun

Why these fixes matter

These are observation-logic fixes, not primitive-behavior changes. Both tests continue to exercise identical Win32 APIs (NotifyServiceStatusChangeW, CfRegisterSyncRoot, CfConnectSyncRoot) and the same EICAR drop sequence. What changed is that the stages now accurately report whether protection fired — eliminating false 101/126 results that misled the EDR posture assessment in ProjectAchilles.

Template audit

sample_tests/multistage_template/ was grepped for EICAR-adjacent os.Stat calls. The template is clean — no EICAR drop code present. The short-window pattern originated in the test implementations directly, not the template, so no template update is needed.

Build verification

All three modified stage binaries compiled clean (GOOS=windows GOARCH=amd64, zero errors):

stage-T1562.001-svcnotify.go  →  3.7M  OK
stage-T1211.go (RedSun)       →  3.5M  OK
stage-T1211-cfapi.go          →  3.7M  OK

Build command used (mirrors build_all.sh step 1):

GOOS=windows GOARCH=amd64 go build -o <out>.exe \
  <stage>.go test_logger.go test_logger_windows.go org_resolver.go

Deployment note

Re-deploying to a lab endpoint is recommended but not blocking for merge. The fixes are small and surgically reviewable statically:

  • The SYSTEM-context guard is a straightforward whoami-based check consistent with the pattern already used in stage-T1547.001.go (commit 0a749b39).
  • The retry loop replaces a single time.Sleep(3s) + os.Stat with ten 1-second ticks — no behavioral change on a protected host, accurate result on one where Defender is slow to quarantine.

Relevant lab-run commits for context: 574bffa (UnDefend), 36fd52a (RedSun), 0ab4dba (BlueHammer).

https://claude.ai/code/session_01TZYUvsgmEBiQqyVzffjrcr


Generated by Claude Code

… EICAR quarantine timing

Bug 1 (UnDefend stage-T1562.001-svcnotify.go): NotifyServiceStatusChangeW on
WinDefend requires SYSTEM context. Running under a non-elevated user caused an
access-denied return that classifyError() mapped to StageBlocked (126) — a false
positive that inflated the overall exit-code roll-up. Fix: detect non-SYSTEM at
stage start, log 'prerequisite-not-met', call LogStageEnd skipped, exit 0 so the
orchestrator treats the stage as skipped rather than errored.

Bug 2 (RedSun stage-T1211.go, BlueHammer stage-T1211-cfapi.go): EICAR quarantine
check used a single os.Stat after a 3s sleep. Defender's quarantine action fires
~5s after the drop, so the stage process exited before the quarantine completed,
reporting 101 UNPROTECTED even when Defender caught the file (confirmed by System
log events 1116/1117). Fix: replace single-shot probe with a 10x1s retry loop
(10s total window) per CLAUDE.md bug-prevention rule #3.

These are observation-logic fixes only — the tests exercise identical Win32 API
primitives and EICAR drops as before; they now report results accurately.

Build verified (GOOS=windows GOARCH=amd64, zero compile errors):
  - stage-T1562.001-svcnotify.go: 3.7M OK
  - stage-T1211.go (RedSun):      3.5M OK
  - stage-T1211-cfapi.go:         3.7M OK

sample_tests/multistage_template/ audited: no EICAR-adjacent os.Stat calls
present; template is clean and does not need updating.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

https://claude.ai/code/session_01TZYUvsgmEBiQqyVzffjrcr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants