Detect Boot or Logon Initialization Scripts in Elastic Security
Adversaries may use scripts automatically executed at boot or logon initialization to establish persistence. On Windows, logon scripts can be set via the UserInitMprLogonScript registry value under HKCU\Environment, or via Group Policy. On Linux and macOS, adversaries target RC scripts (/etc/rc.d/, /etc/init.d/, /etc/rc.local), systemd unit files, login hooks, and startup items. These mechanisms execute with elevated privileges and survive reboots, making them effective persistence mechanisms. Threat groups including APT41, APT29, Rocke, and UNC3886 have all leveraged initialization script abuse, targeting both enterprise endpoints and network appliances.
MITRE ATT&CK
- Tactic
- Persistence Privilege Escalation
- Canonical reference
- https://attack.mitre.org/techniques/T1037/
Elastic Detection Query
any where
(
// Branch 1: Windows registry-based logon script persistence
(event.category == "registry" and event.type in ("creation", "change") and
registry.path : ("*\\Environment\\UserInitMprLogonScript*", "*UserInitMprLogonScript*"))
or
// Branch 2: Script file written to Windows Group Policy / SYSVOL / netlogon paths
(event.category == "file" and event.type in ("creation", "change") and
file.path : ("*\\GroupPolicy\\*", "*\\SYSVOL\\*", "*\\netlogon\\*") and
file.extension in ("bat", "cmd", "vbs", "ps1", "js", "wsf"))
or
// Branch 3: Linux init script file creation or modification
(event.category == "file" and event.type in ("creation", "change") and
file.path : ("/etc/rc.d/*", "/etc/init.d/*", "/etc/rc.local", "/etc/init/*",
"/etc/rc0.d/*", "/etc/rc1.d/*", "/etc/rc2.d/*", "/etc/rc3.d/*",
"/etc/rc4.d/*", "/etc/rc5.d/*", "/etc/rc6.d/*"))
or
// Branch 4: macOS login hook configured via defaults write
(event.category == "process" and event.type == "start" and
process.name == "defaults" and
process.args : ("*LoginHook*", "*LogoutHook*"))
) Detects T1037 Boot or Logon Initialization Script persistence across Windows, Linux, and macOS. Covers four detection branches: (1) Windows registry modification of UserInitMprLogonScript under HKCU\Environment, (2) script file writes into GroupPolicy/SYSVOL/netlogon directories, (3) file creation or modification in Linux RC/init.d paths, and (4) macOS login hook configuration via the 'defaults write' command. Uses Elastic Common Schema event categories for cross-platform coverage.
Data Sources
Required Tables
False Positives & Tuning
- Legitimate IT administrators setting domain logon scripts via Group Policy Object (GPO) management consoles — UserInitMprLogonScript modifications from known admin hosts should be baselined and excluded.
- Configuration management platforms (Ansible, Puppet, Chef, SaltStack) that modify /etc/init.d/ or /etc/rc.d/ scripts as part of automated service deployments on Linux systems.
- macOS MDM solutions such as Jamf Pro or Mosyle that configure login hooks or logout hooks for endpoint management, software deployment, or compliance enforcement.
Other platforms for T1037
Testing Methodology
Validate this detection against 4 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.
- Test 1 Windows Logon Script via UserInitMprLogonScript Registry
Expected signal: Sysmon Event ID 13 (Registry Value Set): TargetObject=HKCU\Environment\UserInitMprLogonScript, Details=%TEMP%\argus-test-logon.bat, Image=reg.exe. Sysmon Event ID 11 (File Create): TargetFilename=%TEMP%\argus-test-logon.bat. DeviceRegistryEvents in MDE will show ActionType=RegistryValueSet with RegistryValueName=UserInitMprLogonScript.
- Test 2 Linux RC Script Persistence via init.d
Expected signal: Linux auditd SYSCALL=openat/write with name=/etc/init.d/argus-test and exe=bash or exe=tee. Syslog entries for update-rc.d execution. If auditd rule -w /etc/init.d -p wa -k init_script_write is in place, ausearch will return the creation event with auid, uid, pid, and full command context. File creation timestamp visible via stat /etc/init.d/argus-test.
- Test 3 macOS Login Hook Configuration
Expected signal: Sysmon for macOS Event ID 1 (Process Create): Image=defaults, CommandLine contains 'write com.apple.loginwindow LoginHook'. File create event for /tmp/argus-loginhook.sh. MDE DeviceProcessEvents will show FileName=defaults with ProcessCommandLine referencing LoginHook. On execution at next login: launchd spawning the hook script as parent.
- Test 4 Windows Network Logon Script via Group Policy INI
Expected signal: Sysmon Event ID 11 (File Create): TargetFilename in %SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\ with .bat extension. DeviceFileEvents ActionType=FileCreated for both the script and scripts.ini. Security Event ID 4688 (cmd.exe executing mkdir and echo). On next logon: userinit.exe spawning the script from the GroupPolicy Scripts directory.
References (9)
- https://attack.mitre.org/techniques/T1037/
- https://www.anomali.com/blog/rocke-evolves-its-arsenal-with-a-new-malware-family-written-in-golang
- https://www.mandiant.com/resources/blog/unc3524-eye-spy-email
- https://www.mandiant.com/resources/blog/esxi-hypervisors-malware-persistence
- https://support.apple.com/guide/deployment/use-login-and-logout-hooks-dep07b92494/web
- https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb742376(v=technet.10)
- https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1037/T1037.md
- https://github.com/SigmaHQ/sigma/tree/master/rules/linux/file_event
- https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4688
Response Playbook
Triage
- Identify the detection branch that fired — Windows registry logon script, Group Policy file drop, Linux init.d modification, or macOS login hook — each has distinct triage steps
- For Windows UserInitMprLogonScript: examine the RegistryValueData to see what script or binary is configured to run. Is the path to a known-good script or an unusual location (temp dir, user profile, appdata)?
- Correlate the modification time with user activity — was the registry/file change made interactively by a logged-on user, or by a background process/service with no corresponding user session?
- Identify the initiating process: was the change made by cmd.exe, powershell.exe, a browser process, a macro-enabled Office document, or a service account? Parent process matters — malware typically drops these from post-exploitation shells
- For Linux init.d modifications: check file ownership (root vs non-root), permissions (ls -la), and content (cat or strings on binary) of the newly created init script. Malicious scripts often contain base64-encoded payloads or curl/wget commands
- Check whether the script or binary pointed to by the initialization entry already exists on disk. A registry key pointing to a non-existent file may indicate an incomplete deployment or a dropped-and-deleted staging artifact
- Review recent user logon activity (Event ID 4624) to determine if the script has already executed — if the system has been rebooted or a user has logged on since the script was configured, execution may have already occurred
Containment
- If active malicious script execution is confirmed: isolate the endpoint immediately using EDR network isolation before the next boot/logon cycle triggers re-execution
- Remove or disable the persistence entry: on Windows, delete the UserInitMprLogonScript registry value (reg delete HKCU\Environment /v UserInitMprLogonScript /f); on Linux, remove the malicious init script and run update-rc.d <script> remove or systemctl disable
- Preserve the malicious script/binary before deletion by copying to an evidence share — do not delete without capturing a hash and copy for forensic analysis
- If the logon script references a network share (UNC path), block access to that share immediately and investigate whether other systems have already executed the script
- Reset credentials for any accounts that have logged on since the script was planted — logon scripts run in user context and may have harvested credentials or established persistence under that account
- Scan all other endpoints in the environment for the same persistence entry, particularly if the script was deployed via Group Policy (SYSVOL/NETLOGON paths indicate policy-wide distribution)
Evidence Collection
- Windows Registry export: reg export HKCU\Environment C:\evidence\UserInitMprLogonScript.reg — captures the full registry key with timestamp
- Sysmon Event ID 13 logs from the Microsoft-Windows-Sysmon/Operational channel — contains RegistryKey, TargetObject, Details (new value), and InitiatingProcess fields
- File system copy of the malicious script with hash: Get-FileHash <script_path> -Algorithm SHA256 | Export-Csv C:\evidence\script_hash.csv
- Windows Security Event ID 4688 or Sysmon Event ID 1 — process creation events from the time window around script installation to identify the delivery mechanism
- For Linux: /var/log/auth.log and /var/log/secure for su/sudo activity around the time of file creation; auditd logs (ausearch -f /etc/init.d/) for complete audit trail
- Group Policy processing logs (Event ID 4006 from Microsoft-Windows-GroupPolicy/Operational) to determine if policy-distributed scripts were involved
- macOS: com.apple.loginwindow plist from /var/db/com.apple.xpc.launchd/ and results of 'defaults read com.apple.loginwindow LoginHook' to capture hook configuration
- Memory acquisition if script has already executed — use EDR memory capture or WinPmem to look for injected code or C2 implants loaded via the init script
Escalation Criteria
- !The init script contains or fetches a second-stage payload (base64 encoded content, curl/wget to external IP, certutil download)
- !The persistence mechanism has already executed — evidence includes network connections from script runtime, new processes, or modified files created at boot/logon time
- !The script was planted via Group Policy (SYSVOL/NETLOGON path) — this indicates domain-level compromise and potential mass lateral movement across all domain members
- !Script runs as SYSTEM or root — initialization scripts running with privileged context enable privilege escalation if combined with writable paths
- !Multiple endpoints share the same malicious init script entry — indicates automated deployment via C2, worm-like propagation, or compromised GPO
- !The technique matches known threat group TTPs: APT41 (hidden shell scripts in /etc/rc.d/init.d/), Rocke (cryptominer persistence via init.d), UNC3886 (FortiManager /etc/init.d/localnet tampering)
Investigation Guide
Related Techniques
Forensic Artifacts
- >
Windows Registry: HKCU\Environment\UserInitMprLogonScript — per-user logon script value; HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\UserInit — system-wide user init configuration - >
Windows File System: %SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\ and Logoff\ — local GPO script directories; \\<domain>\SYSVOL\<domain>\Policies\<GUID>\User\Scripts\scripts.ini — domain GPO script assignments - >
Windows Event Log: Microsoft-Windows-GroupPolicy/Operational Event ID 4006 (script processing), Event ID 4007 (script processing failed) — show script execution timing and failures - >
Linux File System: /etc/init.d/<script>, /etc/rc.local, /etc/rc.d/rc<N>.d/S<XX><script> symlinks — persistence locations; check modification timestamps with stat and ls -la --full-time - >
Linux Audit Log: /var/log/audit/audit.log — auditd records for SYSCALL write/open/rename on init paths; parse with aureport -f or ausearch -f /etc/init.d/ - >
macOS Plist: /var/db/com.apple.xpc.launchd/ — contains login hook state; com.apple.loginwindow plist under /Library/Preferences/; results of 'defaults read com.apple.loginwindow LoginHook' - >
macOS File System: /Library/StartupItems/ and /System/Library/StartupItems/ — legacy startup item bundles containing StartupParameters.plist and executable scripts - >
Network Devices: startup-config file (show startup-config on Cisco IOS) — UNC3886 targeted /etc/init.d/localnet in FortiManager rootfs.gz; check for unexpected commands in initialization sequences
Tuning Guidance
The highest false positive source for Windows logon script detection is legitimate IT administration — helpdesk teams and sysadmins frequently configure UserInitMprLogonScript for drive mapping or environment setup. Build an allowlist of approved initiating processes (gpupdate.exe, gpedit.msc, specific admin tools) and known script paths (e.g., \\domain\SYSVOL\). For Linux, the primary noise source is package manager activity — filter by InitiatingProcessFileName to exclude dpkg, rpm, apt, yum, dnf, and their wrapper scripts. Consider adding auditd rules specifically for /etc/init.d/ write access (key=init_script_write) to get structured audit events with auid tracking rather than relying on syslog pattern matching. For macOS, LoginHook alerts will almost exclusively be MDM-related in managed environments — coordinate with your MDM team to enumerate expected LoginHook values. If your environment has a known-clean baseline for init script contents, consider implementing file integrity monitoring (FIM) on /etc/init.d/ and /etc/rc.d/ paths to alert on any modification regardless of the creating process, rather than relying solely on process-based detection. For network devices (FortiManager, FortiAnalyzer), baseline the startup config and alert on any modification — UNC3886's technique of modifying /etc/init.d/localnet within rootfs.gz archives requires firmware-level analysis outside standard SIEM telemetry.
Hunting Queries
Hunt for any historical or recurring modifications to the UserInitMprLogonScript registry value over the past 30 days. Aggregates by account and initiating process to surface automated or scripted deployments. A single account setting this value across multiple devices is a strong lateral movement indicator.
DeviceRegistryEvents
| where Timestamp > ago(30d)
| where RegistryValueName =~ "UserInitMprLogonScript"
| summarize Count=count(), UniqueDevices=dcount(DeviceName), FirstSeen=min(Timestamp), LastSeen=max(Timestamp), ScriptValues=make_set(RegistryValueData) by AccountName, InitiatingProcessFileName
| order by Count desc index=wineventlog sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=13
TargetObject="*UserInitMprLogonScript*"
| stats count as Count, dc(host) as UniqueDevices, earliest(_time) as FirstSeen, latest(_time) as LastSeen, values(Details) as ScriptValues by User, Image
| sort - Count Hunt for non-package-manager processes writing to Linux init script directories over the past 30 days. Package managers (dpkg, rpm, yum, apt) are expected to write here; other processes writing to these paths warrant investigation. Covers Rocke, VIRTUALPITA, RotaJakiro, and APT41 init.d persistence patterns.
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated", "FileModified")
| where FolderPath has_any ("/etc/init.d/", "/etc/rc.d/", "/etc/rc.local", "/etc/init/")
| where InitiatingProcessFileName !in~ ("dpkg", "rpm", "yum", "apt", "apt-get", "dnf", "installer", "packagekit")
| summarize FileCount=count(), UniqueFiles=make_set(FileName), Devices=dcount(DeviceName) by InitiatingProcessFileName, InitiatingProcessCommandLine
| where FileCount > 0
| order by FileCount desc index=linux sourcetype=linux_auditd
(name="/etc/init.d/*" OR name="/etc/rc.d/*" OR name="/etc/rc.local" OR name="/etc/init/*")
(syscall=write OR syscall=open OR syscall=rename OR syscall=creat)
| where NOT match(exe, "(dpkg|rpm|yum|apt|dnf|installer|packagekit)")
| stats count as WriteCount, values(name) as Files, dc(host) as Devices by exe, auid
| sort - WriteCount Hunt for processes spawned directly by OS initialization parents (userinit.exe, winlogon.exe, launchd, init, systemd) that reference known init script paths in their command lines. This identifies scripts already configured and actively executing at boot/logon, rather than just the configuration step.
let InitScriptExecPatterns = dynamic(["/etc/init.d/", "/etc/rc.local", "UserInitMprLogonScript",
"LoginHook", "StartupItems"]);
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any (InitScriptExecPatterns)
or FolderPath has_any ("/etc/init.d/", "/Library/StartupItems/")
| where InitiatingProcessFileName in~ ("launchd", "init", "systemd", "rc", "userinit.exe", "winlogon.exe")
| project Timestamp, DeviceName, AccountName, FileName, FolderPath, ProcessCommandLine,
InitiatingProcessFileName, InitiatingProcessCommandLine, ProcessId
| sort by Timestamp desc index=wineventlog OR index=linux sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" OR sourcetype=syslog EventCode=1
| where (match(CommandLine, "(?i)(/etc/init\.d/|/etc/rc\.local|UserInitMprLogonScript|LoginHook)"))
OR (match(ParentImage, "(?i)(userinit\.exe|winlogon\.exe|launchd|init|systemd)"))
| table _time, host, User, Image, CommandLine, ParentImage, ParentCommandLine
| sort - _time Atomic Red Team Tests
Sets the UserInitMprLogonScript registry value under HKCU\Environment to point to a benign script. This is the Windows per-user logon script mechanism — the configured script executes at every user logon via userinit.exe. This technique requires only user-level privileges and survives reboots.
Command
reg add "HKCU\Environment" /v UserInitMprLogonScript /t REG_SZ /d "%TEMP%\argus-test-logon.bat" /f
echo @echo off > %TEMP%\argus-test-logon.bat
echo echo Argus logon script test >> %TEMP%\argus-test-logon.bat Cleanup
reg delete "HKCU\Environment" /v UserInitMprLogonScript /f
del /f %TEMP%\argus-test-logon.bat Expected Telemetry
Sysmon Event ID 13 (Registry Value Set): TargetObject=HKCU\Environment\UserInitMprLogonScript, Details=%TEMP%\argus-test-logon.bat, Image=reg.exe. Sysmon Event ID 11 (File Create): TargetFilename=%TEMP%\argus-test-logon.bat. DeviceRegistryEvents in MDE will show ActionType=RegistryValueSet with RegistryValueName=UserInitMprLogonScript.
Expected Detection
KQL WindowsLogonScript branch fires: RegistryValueName matches UserInitMprLogonScript. SPL EventCode=13 branch fires on TargetObject match. DetectionBranch=Windows-LogonScript-Registry.
Creates a benign shell script in /etc/init.d/ and registers it with update-rc.d to execute at runlevel startup. This technique is used by Rocke (cryptominer persistence), VIRTUALPITA (vCenter persistence), and RotaJakiro (Linux backdoor). Requires root privileges.
Command
sudo bash -c 'cat > /etc/init.d/argus-test << EOF
#!/bin/bash
### BEGIN INIT INFO
# Provides: argus-test
# Required-Start: \$remote_fs \$syslog
# Required-Stop: \$remote_fs \$syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Argus persistence test
### END INIT INFO
echo "Argus test executed at \$(date)" >> /tmp/argus-init-test.log
export PATH=\$PATH
EOF
chmod +x /etc/init.d/argus-test'
sudo update-rc.d argus-test defaults Cleanup
sudo update-rc.d argus-test remove
sudo rm -f /etc/init.d/argus-test
rm -f /tmp/argus-init-test.log Expected Telemetry
Linux auditd SYSCALL=openat/write with name=/etc/init.d/argus-test and exe=bash or exe=tee. Syslog entries for update-rc.d execution. If auditd rule -w /etc/init.d -p wa -k init_script_write is in place, ausearch will return the creation event with auid, uid, pid, and full command context. File creation timestamp visible via stat /etc/init.d/argus-test.
Expected Detection
SPL linux_auditd branch fires on syscall write to /etc/init.d/ path. KQL LinuxInitScript branch fires if MDE Linux agent is deployed and monitors /etc/init.d/ via DeviceFileEvents.
Configures a macOS Login Hook using the 'defaults write' command targeting com.apple.loginwindow. Login hooks execute as root at user login and persist across reboots. This technique was used by various macOS malware families for persistence. Requires administrator privileges.
Command
cat > /tmp/argus-loginhook.sh << 'EOF'
#!/bin/bash
echo "Argus LoginHook test at $(date)" >> /tmp/argus-loginhook.log
EOF
chmod +x /tmp/argus-loginhook.sh
sudo defaults write com.apple.loginwindow LoginHook /tmp/argus-loginhook.sh Cleanup
sudo defaults delete com.apple.loginwindow LoginHook
rm -f /tmp/argus-loginhook.sh /tmp/argus-loginhook.log Expected Telemetry
Sysmon for macOS Event ID 1 (Process Create): Image=defaults, CommandLine contains 'write com.apple.loginwindow LoginHook'. File create event for /tmp/argus-loginhook.sh. MDE DeviceProcessEvents will show FileName=defaults with ProcessCommandLine referencing LoginHook. On execution at next login: launchd spawning the hook script as parent.
Expected Detection
KQL MacOSLoginHook branch fires on FileName=defaults with ProcessCommandLine has LoginHook. SPL macOS branch fires on Image=*/defaults CommandLine=*LoginHook*. DetectionBranch=macOS-LoginHook-Configured.
Simulates a network logon script deployment by writing a script reference to the local Group Policy scripts.ini file — the same mechanism used when a domain GPO configures logon scripts distributed via SYSVOL. This represents T1037.003 (Network Logon Script) behavior in a local context.
Command
mkdir -p "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon"
echo @echo off > "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\argus-gpo-test.bat"
echo echo Argus GPO logon script test >> "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\argus-gpo-test.bat"
(echo [Logon] & echo 0CmdLine=argus-gpo-test.bat & echo 0Parameters=) > "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\scripts.ini" Cleanup
del /f "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\argus-gpo-test.bat"
del /f "%SYSTEMROOT%\System32\GroupPolicy\User\Scripts\scripts.ini" Expected Telemetry
Sysmon Event ID 11 (File Create): TargetFilename in %SYSTEMROOT%\System32\GroupPolicy\User\Scripts\Logon\ with .bat extension. DeviceFileEvents ActionType=FileCreated for both the script and scripts.ini. Security Event ID 4688 (cmd.exe executing mkdir and echo). On next logon: userinit.exe spawning the script from the GroupPolicy Scripts directory.
Expected Detection
KQL WindowsStartupFile branch fires on FolderPath has GroupPolicy and FileName has .bat. SPL EventCode=11 branch fires on TargetFilename matching \\GroupPolicy\\.*\.bat pattern. DetectionBranch=Windows-StartupScript-FileCreate.