158 endpoint detections are evadable or have logic gaps — most trace to hardcoded process_name instead of the existing process_* macros
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Área
- security
Línea de trabajo
Start with the SPL rules and process_* macros in the repository, then inspect the affected rule tests and their tests.attack_data. Use the linked evidence repository's scanner and replay harness to reproduce a detection miss and verify whether the proposed fix restores it. Done means addressing the confirmed gaps with regression coverage; the report spans 158 rules and several distinct fix patterns, so first narrow work to one class.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary
An audit of the endpoint ruleset found 158 production detections that an attacker can evade without changing their behaviour, or that fail on default modern Windows:
62 TTP · 67 Anomaly · 29 Hunting
Most trace to one root cause: a rule hardcodes Processes.process_name=X instead of using the process_X macro ESCU already ships — and a couple of those macros are themselves incomplete. The rest are case-sensitive match(), bypassable NOT exclusions, and command-line obfuscation (/↔-, quote insertion) the rules don't account for.
Method: a static scanner flags the pattern; a replay harness takes each rule's own attack_data, mutates it to the evasion, and re-runs it to confirm the detection miss and that the fix recovers. 14 rules are confirmed end-to-end in a live Splunk; the attack side is anchored to ArgFuscator's lab-validated models and to behaviour tested directly on Windows 11 and Server. Counts are
after excluding scanner false positives.
Breakdown by class
| # | Class | Rules | TTP | Anom | Hunt | Fix |
|---|---|---|---|---|---|---|
| 1 | Renamed binary (no original_file_name) |
89 | 36 | 37 | 16 | use process_* macro |
| 2 | Option-char substitution (/↔-) |
29 | 15 | 9 | 5 | match both prefixes |
| 3 | Sibling binary not covered | 13 | 5 | 1 | 7 | process_powershell / add sibling |
| 4 | Bypassable NOT exclusions (name/path/cmdline) |
33 | 14 | 15 | 4 | anchor / qualify the exclusion |
| 5 | process_net matches net1.exe only |
8 | 0 | 5 | 3 | macro += net.exe |
| 6 | Space-bound token (quote/char insertion) | 7 | 1 | 3 | 3 | normalize command line |
| 7 | Case-sensitive match() |
4 | 3 | 1 | 0 | add (?i) |
(Some rules appear in more than one class; 158 is the distinct total, 183 counting each class separately.)
proof: https://github.com/Diablo-research/splunk-escu-evidence/tree/main/escu-evasion-gaps
Don't let the number put you off — most of this is a small, mechanical fix
158 looks large, but the long tail is shallow:
- ~110 rules (classes 1, 3, 5) are fixed at the macro level — swap the
hardcodedprocess_name=Xfor theprocess_Xmacro ESCU already ships (plus
adding a missing sibling in three cases, and onenet.exeline for the
process_netmacro). These are mechanical, non-breaking changes that add
coverage without touching detection logic, so the false-positive risk is
near zero. Fixing one macro can close dozens of rules at once. - ~40 rules (classes 2, 6, 7) are a handful of shared patterns — match both
flag prefixes, add(?i), normalize the command line. Each can be solved once
(ideally a reusable macro, like Sigma'swindash) and applied across all of them. - Only class 4 (33 rules) needs per-rule thought, and even there the fix is
usually a one-token anchor on an existing exclusion.
In practice this is a few focused PRs, not 158 separate ones. I'm happy to open
them batched by class — I'd suggest leading with the macro family (classes 1/3/5),
then obfuscation (2/6), then exclusions/logic (4/7).
The root cause, in one example
ESCU already ships the correct pattern:
process_powershell:
(process_name=pwsh.exe OR process_name=powershell.exe
OR original_file_name=PowerShell.EXE OR original_file_name=pwsh.dll
OR original_file_name=powershell_ise.EXE OR process_name=powershell_ise.exe)
This defeats renaming (original_file_name) and the pwsh sibling. But
getadcomputer_with_powershell.yml hardcodes process_name="powershell.exe",
so it is evaded by both. process_wmic is the same story. Using the macro
closes classes 1 and 3 together.
Class 1 — Renamed binary (89)
original_file_name (PE version resource) doesn't change on rename and can't be forged for a signed Microsoft binary. Rules matching process_name only miss a renamed copy. Live proof (rule's own attack_data, process renamed to svc.exe, OriginalFileName intact):
| Rule | fires | renamed | +fix |
|---|---|---|---|
| Deleting Shadow Copies (vssadmin, T1490) | yes | 0 | yes |
| Excessive Usage of NSLOOKUP App | 407 | 0 | 407 |
| Excessive Usage Of Taskkill | 257 | 0 | 257 |
| RDP Client Launched with Admin Session | 10 | 0 | 10 |
| Wmic NonInteractive App Uninstallation | 16 | 0 | 16 |
Full list: results/rename_gap_89.csv. Top binaries: powershell(16), wmic(14), cmd(13), schtasks(11).
Class 2 — Option-char substitution (29)
Rule matches a switch in one prefix form (*/create* or *-enc*); the binary accepts the other. 24 affected binaries confirmed by ArgFuscator to accept both / and -. Live proof (prefix swapped):
| Rule | fires | swapped | +fix |
|---|---|---|---|
| DISM Remove Defender (T1562.001) | 2 | 0 | 2 |
| Certutil certificate extraction | 12 | 0 | 12 |
| Bcdedit Back To Normal Mode Boot | 2 | 0 | 2 |
Full list: results/flag_form_confirmed_final.csv. Incl. Auditpol tampering,
Schtasks family, Remote Process Instantiation via WMI/PowerShell.
Class 3 — Sibling binary (13)
Separate binary, same capability. Live proof: Jscript/Vbscript via Cscript↔Wscript (fires→0→fix). 10 PowerShell rules fixed by process_powershell; process_wscript exists but omits the cscript sibling and there is no
process_cscript.
Class 4 — Bypassable exclusions (33)
- by_name (8):
NOT Image="*\<name>"→ rename tool to the excluded name.
Fix: qualify withoriginal_file_name. - path_wildcard (14):
NOT Image="*\windows\*"(no drive anchor) → run from
C:\Users\Public\windows\…. Incl. CMLUA/CMSTPLUA UAC Bypass, Raw Access to
MBR/Disk, DLL Search-Order Hijacking. Fix: anchor to drive root. - cmdline (11):
NOT process="*<string>*"→ satisfy with a dummy argument.
Fix: anchor to the real field/position.
Class 5 — process_net matches net1.exe only (8) — coverage is OS-dependent
Whether net <verb> spawns net1.exe depends on the Windows version
(Win32_ProcessStartTrace):
| verb | Win11 25H2 | Server | rule |
|---|---|---|---|
| user (incl. /delete) | no net1 | net1 | User Deletion / Disabled |
| localgroup | no net1 | no net1 | Group Discovery |
| accounts | no net1 | net1 | Password Policy |
net localgroup spawns no net1 on either OS → Group Discovery is bypassed
everywhere; net user/accounts fire on Server but miss on Win11 → the same
rule's coverage flips with the OS. No evasion needed. One non-breaking macro
change (add net.exe) makes all 19 process_net rules fire uniformly.
Class 6 — Space-bound token (7)
* restore * matched with literal spaces; res""tore runs identically
(CommandLineToArgvW collapses "") but no longer contains the spaced token.
Lab-confirmed on Win11: reg qu""ery, netsh ad""vfirewall, sc.exe qu""ery,
schtasks /qu""ery all obeyed. Incl. Registry Entries Restored Via Reg, Proxy
Via Netsh. Fix: a command-line normalization macro (strip quotes, collapse
whitespace) — mirrors Sigma / Defender parse-command-line. Needs FP testing.
Class 7 — Case-sensitive match() (4)
match() without (?i) on case-insensitive Windows values: RunDLL Loading DLL
By Ordinal, Windows .Key File Creation, Windows RDP File Execution, WinDBG
Spawning AutoIt3. Fix: (?i). (SQLCMD was excluded — its flags are genuinely
case-sensitive.)
Method (reproducible)
Scanner flags the SPL pattern → pull the rule's tests.attack_data → mutate to
the evasion (rename / prefix swap / quote insert / sibling swap) → replay
original vs mutated → apply the fix to the mutated copy. Confirmed = fires on
original, 0 on mutated, recovers with fix. Attack side from ArgFuscator + direct
Windows 11/Server tests.
Full evidence — scanner, replay harness, mutated datasets, per-rule tables, and
live-Splunk screenshots; https://github.com/Diablo-research/splunk-escu-evidence/tree/main/escu-evasion-gaps
Data-source note
original_file_name is present on Sysmon EID 1 and EDR (CrowdStrike, Defender
for Endpoint). Windows Security 4688 lacks it, so on 4688-only telemetry Class 1
can't be closed this way, though some rules list 4688 as supported — a
maintainer call.
Scope / honesty
14 confirmed live; the rest share the same root cause and the replay/ArgFuscator
method. Scanner false positives were excluded on review (SQLCMD case-sensitivity,
drive-anchored path exclusions, cmd-intrinsic techniques, rules that already
cover PowerShell). Per-rule tables are in the evidence repo; I can confirm any
rule live on request. Happy to open a PR, batched by class or as one change.
- Lenguaje dominante
- Python
- Estrellas
- 1.7k
- Forks
- 507
- Merge medio
- 2 d 17 h
- PR fusionados (30 d)
- 35
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de splunk/security_content
-
bug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
splunk/security_content#4418 ·
Los mantenedores suelen responder en 1 día
-
[BUG] Windows New EventLog ChannelAccess Registry Value Set: second path has single backslashesAbiertobug
Dificultad 1/5 1-3 horas Aptitud para principiantes 78/100
splunk/security_content#4417 ·
Los mantenedores suelen responder en 1 día
-
[BUG]Linux Change File Owner To Root: detection bypass using "chown root: <file>"Posiblemente ocupada @thegreatmhn la tomó hace 1 día. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
splunk/security_content#4413 · 4 comentarios ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
splunk/security_content#4401 ·
Los mantenedores suelen responder en 1 día
-
enhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
splunk/security_content#4400 ·
Los mantenedores suelen responder en 1 día
Todos los issues de splunk/security_content
Issues similares
-
[Bug / Enhancement]: Improve teleop_robot CLI with configurable timeout, robust input validation, and clean ROS shutdownPosiblemente ocupada @muskan-creates352 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Los mantenedores suelen responder en 3 días
-
bug(pipelines): shortcode stripping deletes text between a {{< >}} shortcode and the next {{% %}}Posiblemente ocupada @Ashborne-lab la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
kubeflow/docs-agent#293 ·
Los mantenedores suelen responder en 3 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Imbad0202/academic-research-skills#1093 ·
Los mantenedores suelen responder en 1 día
-
Input: placeholder drawn in the text colour when the empty Input is focused but not yet editedAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
pierreaubert/gpui-toolkit#114 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Lightricks/LTX-2#336 · 1 comentario ·