ADSCRIPT-011: Script Content Analysis
- Plataforma
- Active Directory
- Categoría
- AD Logon Scripts & Network Shares
- Severidad
- Medium
- Pilar de Zero Trust
- Applications & Workloads (peso 1)
- Fixtures de referencia
- 2
- Cobertura de ramas
- Observada: los fixtures prueban los veredictos que ejercitan
- Procedencia
- baseline
Qué comprueba
For every script enumerated by ADSCRIPT-003 (User.scriptPath, GPO User Logon and Logoff under \\<domain>\SYSVOL\<domain>\Policies\{GUID}\User\Scripts, GPO Computer Startup and Shutdown under the corresponding Machine\Scripts subtree, and the raw file listing of \\<domain>\NETLOGON), the check reads the file as text and matches the body against a pattern catalog grouped by intent. 1. Encoded payload decoding: matches for [Convert]::FromBase64String, FromBase64Binary, certutil -decode / -decodehex, certutil -urlcache -split -f (the canonical certutil download cradle), bitsadmin /transfer, the .NET System.Text.Encoding.UTF8.GetString chained off a base64 decode, and large embedded blobs (>200 contiguous chars of base64 alphabet, or >100 hex pairs) that are passed to Invoke-Expression, IEX, &, or .Invoke(). 2. Download cradles and remote loaders: Net.WebClient with .DownloadString or .DownloadFile, Invoke-WebRequest / iwr / curl / wget aliases piped into IEX, Start-BitsTransfer with a -Source argument outside the local network, msxml2.xmlhttp / WinHttp.WinHttpRequest objects, and the New-Object Net.Sockets.TCPClient reverse-shell template. 3. Command and string obfuscation: string concatenation patterns ("i"+"e"+"x", "Invoke" + "-Expression"), char-code arrays ([char]105 + [char]101 + [char]120), ASCII byte arrays piped through -join, format-string substitution ("{2}{0}{1}" -f ...), backtick-escaped tokens used to break signatures (i`e`x), and base-radix conversions ([Convert]::ToInt32(...,16)) that decode opcodes inline. These are the families catalogued by Daniel Bohannons Invoke-Obfuscation and reproduced in the Revoke-Obfuscation training set. 4. Anti-analysis and sandbox evasion: Start-Sleep, ping -n, or timeout.exe values above 30 seconds at the top of a script (T1497.003); registry probes against HKLM:\Software\Wow6432Node\Oracle\VirtualBox or VMware tools paths; WMI queries for Win32_ComputerSystem.Model matching "VMware|VirtualBox|Virtual"; environment checks for USERNAME = "sandbox|maltest|currentuser" and COMPUTERNAME patterns used by common sandboxing vendors; date or uptime gates that only execute on specific weekdays or after a system has been up for more than N minutes. 5. AMSI and logging tamper: System.Management.Automation.AmsiUtils references with reflection or SetValue, [Ref].Assembly.GetType("System.Management.Automation.Utils") patching, ScriptBlock logging registry writes under HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging, ETW provider unhooks (Set-EtwTraceProvider), Get-EventLog -Newest manipulation, and Clear-EventLog calls inside a logon script. 6. Credential and secret material left in plaintext: ConvertTo-SecureString -AsPlainText, net user <name> <password> /add, cmdkey /add /user /pass, runas /user with a literal /savecred prompt, and the legacy GPP cpassword XML signature (which is the same blob class as CVE-2014-1812 and is independently flagged in ADGPO checks). Results are emitted per script with the matched category, the matching regex, a line and column offset, and a 40-character context snippet so an analyst can triage without re-reading the entire file. The check is static and offline: scripts are read, not executed.
Por qué importa
A logon script is one of the highest leverage execution primitives in the Windows estate. The Group Policy client pulls the file from SYSVOL on every user logon and on every machine boot, runs it without user interaction, and surfaces nothing in the UI. There is no Mark-of-the-Web prompt, no SmartScreen reputation check, no Defender for Cloud Apps inline scan, and no per-execution AMSI confirmation that the body is what the administrator originally wrote. If an attacker has touched the script (either by writing to SYSVOL directly, by hijacking the scriptPath attribute on a user, or by editing the GPO that drops the file), the obfuscated body executes inside a trusted automation channel and inherits the trust posture of that channel. Pattern-matched indicators (a base64 blob piped to IEX, a Net.WebClient pointing at an external host, a Start-Sleep 600 at the top of a .ps1) are how the offensive tradecraft of the last decade shows up in static text. Invoke-Obfuscation, Invoke-CradleCrafter, Empire, PowerSploit, and most modern C2 stagers all produce text that lights up at least two of the categories above. The cost of a FAIL is high (forest-wide code execution distributed by SYSVOL replication), the cost of a false positive is low (the admin reads one script and approves it), and the cost of missing a real positive is the difference between a quarter-day cleanup and a domain rebuild. This is also the historical class of finding behind incidents where logon scripts were used to deploy ransomware to the entire user population at the next morning logon wave: a single tampered file under NETLOGON, replicated by DFSR to every DC, executed by every user.
Ruta de ataque
1. Initial access and foothold: the attacker authenticates as a low-privilege domain user (phishing, password spray, or a Kerberoast crack of a service account). 2. Write primitive: the attacker finds a writable script. The most common routes are (a) a NETLOGON or SYSVOL ACL that grants Modify to a non-Tier-0 group (ADSCRIPT-001, ADSCRIPT-002), (b) WriteProperty on a target user that lets the attacker repoint scriptPath at a file under their control (ADACL family), or (c) a GPO whose SYSVOL folder is writable due to delegation drift (ADGPO category). 3. Payload authoring: the attacker generates an obfuscated stager. Typical workflow is Invoke-Obfuscation TOKEN\ALL\1 followed by COMPRESS\1 and LAUNCHER\STDIN, which yields a one-liner that base64-decodes a gzip-compressed payload and pipes it to IEX. The payload itself is a Cobalt Strike, Sliver, Mythic, or Havoc beacon, or a credential-dumping stub built on Invoke-Mimikatz, SafetyKatz, or a fresh nanodump. 4. Plant: the attacker writes the obfuscated body into the target script file. If the original script was a benign one-line drive map, the attacker keeps the drive map intact and prepends or appends the malicious block so the script still appears to work to the user. 5. Distribution: DFSR replicates the modified file to every Domain Controller in the SYSVOL replication group within minutes. Every interactive logon across the forest now executes the obfuscated body. 6. Execution and harvesting: the body decodes, optionally sleeps long enough to defeat an interactive sandbox, checks for analysis indicators, then loads the beacon. Tier-1 and Tier-0 admins who log on to a workstation hand their token to the script. 7. Persistence and cleanup: the attacker frequently rewrites the file back to its original content after a successful beachhead on a target host, leaving only a transient SYSVOL modification timestamp and a single DFSR replication event. Without ADSCRIPT-011 content scanning or a SACL on the SYSVOL path, the only forensic evidence is the modification time and any process tree captured by a host EDR during the brief execution window.
Cómo lo evalúa Guerrilla
Guerrilla consumes the inventory produced by ADSCRIPT-003 (every User.scriptPath, every GPO script extension, every file in NETLOGON) and opens each file as text with Get-Content -Raw. The body is normalized: long runs of whitespace are collapsed, backtick line continuations are unfolded, and string concatenation operators are preserved verbatim so the original obfuscation is visible to the matchers. Each of the six categories above is implemented as a regex set with category, name, and severity weighting. Matches are scored: a single download-cradle match in a script that is otherwise a 200-line drive map is reported as Medium; multiple categories matching the same file (for example, a base64 blob plus a Start-Sleep plus an AMSI bypass) escalate to High and surface a per-file finding rather than a per-pattern finding. For each match the check records the script source (User.scriptPath, GPO Logon, GPO Startup, NETLOGON loose file), the resolved UNC path, the principal it runs as, the matched pattern, a line and column offset, and a 40-character context snippet. The script is never executed, never written, and never deobfuscated by the check itself; analysts triage the snippets and decide whether to detonate in a sandbox.
Valor recomendado
No obfuscated code, encoded payloads, download cradles, or anti-analysis techniques present in any logon scripts
Remediación
Analyze all scripts for suspicious patterns including base64 encoding (Convert-FromBase64, certutil -decode), download cradles (Invoke-WebRequest, Net.WebClient, BitsTransfer), obfuscation techniques (string concatenation, char codes, variable substitution to hide commands), and anti-analysis techniques (sleep timers, environment checks). Investigate and replace any scripts containing suspicious patterns.
Veredictos probados con fixtures
Cada veredicto de esta tabla está probado por un fixture de referencia en la suite de pruebas que valida el módulo. La tabla se deriva de la última ejecución en verde; no puede editarse a mano.
| Escenario | Veredicto esperado |
|---|---|
| clean | PASS |
| throttled | Not Assessed |
Mapeos a marcos de referencia
- NIST SP 800-53
- SI-3, SI-7, CM-3
- MITRE ATT&CK
- T1059, T1027, T1105