CTDC study materials
CTDC study resources

1,100 PowerShell Alerts a Day, Five Days Before Change Freeze

CTDC · Put your knowledge to work in context.

All case studies

1,100 PowerShell Alerts a Day, Five Days Before Change Freeze

A new SIEM rule, 'Suspicious PowerShell Execution', alerts whenever a process command line contains -enc, -EncodedCommand, -nop, or -w hidden. It fires about 1,100 times a day across 12,000 endpoints. A two-week sample breaks down as: 61% parent ccmexec.exe (SCCM software deployment), 14% a signed monitoring agent, 9% a scheduled task owned by the server team running a signed script, 6% developers in Visual Studio and VS Code, and 10% everything else. Of 40 alerts that analysts investigated fully, none were malicious and two were closed as 'unknown'. Script Block Logging (event 4104) is enabled on servers but not workstations. AMSI is on by default across the estate. EDR provides full command-line and parent-process telemetry on every endpoint. A change freeze starts in five days; SCCM cannot be modified and the server team's scheduled task cannot be disabled until next quarter. Leadership wants the rule quiet but refuses to lose coverage of 'real' encoded PowerShell.

1. Critique the rule and design a v2 using only telemetry you already have.

Read the worked answer

Why v1 fails: it matches flags, not behaviour. -EncodedCommand and -w hidden are used by SCCM, monitoring agents, and installers by design, so the rule's base rate is hopeless - 1,100 alerts, zero confirmed malicious, and the two 'unknown' closures are where a real intrusion would hide. Worse, flag matching is trivially avoided: an attacker can encode at the script level, use -Command with a base64 string built in-script, or drop the flags entirely.

v2 should score context around PowerShell execution, combining signals that are individually common but jointly rare:

  • Parent process: Office applications, browsers, mshta, wscript, installers running from temp, or a service host spawning PowerShell. This is the single highest-value field and you already have it from EDR.
  • User and host context: interactive user on a server, a service account with an interactive session, or PowerShell running as SYSTEM on a workstation.
  • Rarity: parent-child pair or command-line shape never seen in the estate before, or seen on fewer than three hosts in 30 days. Compute this from your own 30–90 days of EDR data rather than a static list.
  • Post-execution behaviour: outbound network connection from powershell.exe to a non-corporate destination, or child processes such as net, nltest, whoami, rundll32.
  • Script content where available: 4104 on servers gives the decoded block; look for IEX, DownloadString, FromBase64String, Net.WebClient, and AMSI bypass strings.

Detections should key on behaviour families (T1059.001 execution from an unusual parent, download-and-execute, encoded payload plus network egress) rather than on one flag. Keep a low-severity record of every encoded invocation for hunting without alerting on it.

2. How would you handle the three dominant benign sources without creating a blind spot, and what is the specific risk of each approach?

Read the worked answer

SCCM (61%). The tempting fix - suppress everything under ccmexec.exe - is the most dangerous, because SCCM is also an execution and lateral-movement path: application deployment can be abused, and process injection into ccmexec inherits the parent name. Narrow it instead: suppress only command lines matching the deployment tooling's known templates on hosts in the SCCM collection, with a ticket reference and a 90-day expiry; keep alerting when ccmexec spawns PowerShell that then makes an outbound connection to a non-corporate address, writes to a user-writable directory, or loads an unsigned module. That preserves the abuse case while removing the routine deployment noise.

Signed monitoring agent (14%). Suppress on binary signature plus install path plus the specific script hash, not on process name alone. An agent that updates its scripts will break the suppression and should - a silent, unbounded hash allowlist rots. Risk: a compromised or spoofed agent binary path. Mitigate by alerting on any change to the agent's install directory contents.

Server team scheduled task (9%). Suppress by task name plus parent process plus host group, with the change record linked. Risk: the task definition can be edited by anyone with server-team rights and then runs unmonitored. Add a detection on modification of that task's XML.

Developers (6%). Do not suppress; downgrade. Developer hosts are a real initial-access target and encoded commands there are unusual enough to keep at low severity.

Governance matters as much as logic: every suppression carries an owner, a justification, an expiry, and appears in a weekly report. Alert on changes to the suppression list itself.

3. How do you validate v2 before and after deployment, and what do you report given the five-day freeze?

Read the worked answer

Before deployment - backtest. Replay 90 days of EDR and SIEM telemetry through the v2 logic offline. Produce three numbers: total alerts per day, distinct hosts alerted, and the parent-child distribution. If the volume stays above roughly 20–30 per day, the scoring weights are wrong, not the concept.

Precision sample. Take 50 v2 alerts from the backtest and have two analysts label them independently (true positive, benign-true, unknown). Disagreement between them is itself a finding - it means the alert lacks context and needs more fields surfaced in the ticket.

Coverage test - the part that protects you from over-tuning. Assemble a small atomic test set and run it in a lab or approved test host: encoded command from a Word macro, IEX (New-Object Net.WebClient).DownloadString(...), PowerShell spawned by mshta, and PowerShell making an outbound connection to a test listener. Confirm v2 fires on each and record the time to alert. Then run the benign set - an SCCM deployment, the monitoring agent, the server team task - and confirm v2 stays quiet. This is the evidence that 'quiet' did not mean 'blind'.

Report to leadership: expected reduction from ~1,100 to a target of 10–20 alerts/day, with precision measured rather than assumed; coverage demonstrated against the test set; and an explicit residual risk register - the SCCM suppression is a genuine blind spot for deployment abuse, mitigated by the egress-condition alert but not eliminated. Propose that workstations get Script Block Logging via GPO as the next step after the freeze, since it converts flag-matching into content inspection on the hosts where it matters most.