Skip to content

feat: implement threat-informed detection cycle 1 - #23

Open
egrexsec wants to merge 1 commit into
feat/pt-2026-013-wmi-event-subscriptionfrom
feat/detection-cycle-1
Open

egrexsec wants to merge 1 commit into
feat/pt-2026-013-wmi-event-subscriptionfrom
feat/detection-cycle-1

Conversation

@egrexsec

@egrexsec egrexsec commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Summary

Implements Threat-Informed Detection Cycle 1 as a bounded CTI → hunt → detection → Atomic validation → campaign workflow.

  • adds completed hunts HUNT-2026-014..016
  • adds validated scenarios PT-2026-014 (T1105) and PT-2026-015 (T1218.005)
  • adds behavioral Sigma rules plus generated Splunk/Elastic outputs
  • adds 10 fixtures: exact/modified positives and three meaningful negatives per rule
  • adds a loopback-only benign HTA campaign with correlated evidence
  • adds sanitized live records, DFIR pivots, evidence summaries, coverage/status documentation, and contract tests

Live outcomes

  • T1105: pinned exact Atomic and modified Invoke-WebRequest positive detected; transfer hashes matched; three negatives stayed quiet.
  • T1218.005: endpoint protection prevented the pinned exact inline Atomic before child creation; modified and campaign mshta-child behavior detected; three negatives stayed quiet.
  • Campaign detections correlated three seconds apart; marker and transfer integrity verified.
  • First and idempotent second cleanup passes returned zero residue.

Safety deviation

A rejected remote-HTA candidate failed to honor the intended safe input override. Its default payload attempted an outbound external connection, and the connection failed. No connection was established, residue or sensor impact remained, and the rejected UUID/observable are intentionally excluded from public artifacts.

Validation

  • PowerShell parser: 14 Cycle 1 scripts
  • python3 playbook validate
  • python3 playbook sigma check: 0 errors / 0 issues
  • Sigma lint and conversion to Splunk/Elastic
  • 79/79 fixtures
  • prior live-record parsing
  • 22/22 unit tests
  • Markdown links
  • public-safety contract scan
  • Gitleaks full-history scan during independent review
  • independent pre-commit approval
  • independent exact-commit review: APPROVE for commit 03002918c96c650a0dafa71f5db6ef885ef5d9a5, tree adc755de5faa66a44abb91d3f69c966513aa5821

Dependency

This is intentionally a stacked PR based on #22 (PT-2026-013). After #22 merges, retarget/rebase this branch onto main before merging.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03002918c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

try{$p=Start-Process "$env:WINDIR\System32\mshta.exe" -ArgumentList ('"{0}"' -f $arg) -PassThru -ErrorAction Stop;[string]$p.Id|Set-Content (Join-Path $root 'process-ids-atomic.txt');if(-not$p.WaitForExit(20000)){try{$p.Kill()}catch{};throw 'timeout'};$started=$true;$exit=$p.ExitCode}catch{$started=$false;$exit=$null;$launchError=$_.Exception.Message}
Start-Sleep 2
$defender=@(Get-WinEvent -FilterHashtable @{LogName='Microsoft-Windows-Windows Defender/Operational';StartTime=$start} -ErrorAction SilentlyContinue|Where-Object {$_.Id -in 1116,1117 -and $_.Message -match 'mshta'})
$result=[pscustomobject]@{AtomicGuid=$guid;ProcessStarted=$started;ExitCode=$exit;PreventiveEvents=$defender.Count;Outcome=$(if(-not$started -and $defender.Count){'prevented'}elseif($started){'executed'}else{'failed-unconfirmed'});Completed=$true}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject unconfirmed Atomic outcomes

When Start-Process fails for a reason other than confirmed Defender prevention—such as a missing executable or unavailable event log—the catch sets $started false and the result becomes failed-unconfirmed, but this line still records Completed=true and the script exits successfully. An automation runner can therefore accept a failed positive validation as completed; return a nonzero status unless execution or prevention was actually confirmed.

Useful? React with 👍 / 👎.

@@ -0,0 +1 @@
$root='C:\Windows\Temp\dc1-t1218-005';$ids=@(Get-ChildItem (Join-Path $root 'process-ids-*.txt') -ErrorAction SilentlyContinue|Get-Content -ErrorAction SilentlyContinue|Where-Object {$_ -match '^\d+$'}|ForEach-Object {[int]$_});@(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue|Where-Object {$ids -contains [int]$_.ParentProcessId}|ForEach-Object {[int]$_.ProcessId})+$ids|Sort-Object -Unique|ForEach-Object {Stop-Process -Id $_ -Force -ErrorAction SilentlyContinue};Remove-Item $root -Recurse -Force -ErrorAction SilentlyContinue;$remaining=@(Get-ChildItem $root -Recurse -ErrorAction SilentlyContinue);[pscustomobject]@{RecordedProcessIds=$ids;Remaining=@($remaining|ForEach-Object FullName);Clean=($remaining.Count -eq 0)}|ConvertTo-Json -Compress

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify process termination before reporting clean

If Stop-Process fails—for example because a recorded process cannot be terminated—the error is suppressed and Clean is still calculated solely from files remaining beneath $root. Once the directory is removed, this reports Clean=true even while the process remains alive, undermining the scenario's required cleanup confirmation; re-query the recorded process IDs and include them in the clean predicate.

Useful? React with 👍 / 👎.

- order: 3
behavior: The HTA launches a bounded benign PowerShell child that writes a completion marker.
technique_id: T1059.001
expected_detection: existing-validated-powershell-coverage

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the unsupported stage-three detection expectation

The campaign's stage-three command only runs Set-Content, while the referenced existing T1059.001 rule in detections/sigma/windows/process_creation/suspicious_powershell_execution.yml requires both FromBase64String and Invoke-Expression/iex. Consequently this expected detection cannot fire for the implemented campaign behavior, so consumers may incorrectly treat script telemetry as validated detection coverage; reference a rule that matches this command or mark the stage as telemetry-only.

Useful? React with 👍 / 👎.

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.

1 participant