service-triggers.md (10658B)
1 --- 2 title: "Windows Service Triggers: Enumeration and Abuse" 3 section: "Windows" 4 sectionSlug: "windows-hardening" 5 sourcePath: "src/windows-hardening/windows-local-privilege-escalation/service-triggers.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/windows-local-privilege-escalation/service-triggers.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Windows Service Triggers: Enumeration and Abuse 14 15 Windows Service Triggers allow the Service Control Manager (SCM) to start/stop a service when a condition occurs (e.g., an IP address becomes available, a named pipe connection is attempted, an ETW event is published). Even when you lack SERVICE_START rights on a target service, you may still be able to start it by causing its trigger to fire.<sup>[[1]](#references)</sup> 16 17 This page focuses on attacker-friendly enumeration and low-friction ways to activate common triggers. 18 19 > Tip: Starting a privileged built-in service (e.g., RemoteRegistry, WebClient/WebDAV, EFS) can expose new RPC/named-pipe listeners and unlock further abuse chains. 20 21 ## Enumerating Service Triggers 22 23 - sc.exe (local) 24 - List a service's triggers: `sc.exe qtriggerinfo <ServiceName>` 25 - Registry (local) 26 - Triggers live under: `HKLM\SYSTEM\CurrentControlSet\Services\<ServiceName>\TriggerInfo` 27 - Dump recursively: `reg query HKLM\SYSTEM\CurrentControlSet\Services\<ServiceName>\TriggerInfo /s` 28 - Win32 API (local) 29 - Call QueryServiceConfig2 with SERVICE_CONFIG_TRIGGER_INFO (8) to retrieve SERVICE_TRIGGER_INFO. 30 - Docs: QueryServiceConfig2[W/A] and SERVICE_TRIGGER/SERVICE_TRIGGER_SPECIFIC_DATA<sup>[[2]](#references)</sup> 31 - RPC over MS‑SCMR (remote) 32 - The SCM can be queried remotely to fetch trigger info using MS‑SCMR. TrustedSec’s Titanis exposes this: `Scm.exe qtriggers`. 33 - Impacket defines the structures in msrpc MS-SCMR; you can implement a remote query using those.<sup>[[1]](#references)[[3]](#references)[[4]](#references)</sup> 34 - PowerShell (bulk enumeration) 35 - Quickly list every service exposing a `TriggerInfo` key: 36 ```powershell 37 Get-ChildItem 'HKLM:\SYSTEM\CurrentControlSet\Services' | 38 Where-Object { Test-Path "$($_.PSPath)\TriggerInfo" } | 39 ForEach-Object { sc.exe qtriggerinfo $_.PSChildName } 40 ``` 41 - PowerShell (programmatic) 42 - James Forshaw's `NtObjectManager` module exposes `Get-Win32ServiceTrigger` for parsing trigger metadata without scraping `sc.exe` output. 43 44 ## High-Value Trigger Types and How to Activate Them 45 46 ### Network Endpoint Triggers 47 48 These start a service when a client attempts to talk to an IPC endpoint. Useful to low-priv users because the SCM will auto-start the service before your client can actually connect.<sup>[[1]](#references)</sup> 49 50 - Named pipe trigger 51 - Behavior: A client connection attempt to \\.\pipe\<PipeName> causes the SCM to start the service so it can begin listening. 52 - Activation (PowerShell): 53 ```powershell 54 $pipe = new-object System.IO.Pipes.NamedPipeClientStream('.', 'PipeNameFromTrigger', [System.IO.Pipes.PipeDirection]::InOut) 55 try { $pipe.Connect(1000) } catch {} 56 $pipe.Dispose() 57 ``` 58 - Internals note: named-pipe triggers are backed by `npsvctrig.sys`, a filesystem minifilter that watches for opens against registered trigger pipe names. This is why the open attempt can start the service even before the service itself has created/listened on the pipe.<sup>[[5]](#references)</sup> 59 - See also: Named Pipe Client Impersonation for post-start abuse. 60 61 - RPC endpoint trigger (Endpoint Mapper) 62 - Behavior: Querying the Endpoint Mapper (EPM, TCP/135) for an interface UUID associated with a service causes the SCM to start it so it can register its endpoint. 63 - Activation (Impacket): 64 ```bash 65 # Queries local EPM; replace UUID with the service interface GUID 66 python3 rpcdump.py @127.0.0.1 -uuid <INTERFACE-UUID> 67 ``` 68 69 ### Custom (ETW) Triggers 70 71 A service can register a trigger bound to an ETW provider/event. If no additional filters (keyword/level/binary/string) are configured, any event from that provider will start the service.<sup>[[1]](#references)</sup> 72 73 - Example (WebClient/WebDAV): provider {22B6D684-FA63-4578-87C9-EFFCBE6643C7}<sup>[[6]](#references)</sup> 74 - List trigger: `sc.exe qtriggerinfo webclient` 75 - Verify provider is registered: `logman query providers | findstr /I 22b6d684-fa63-4578-87c9-effcbe6643c7` 76 - Emitting matching events typically requires code that logs to that provider; if no filters are present, any event suffices. 77 - Minimal C shape for firing the provider (when no additional ETW filters are configured): 78 ```c 79 GUID g = {0x22B6D684,0xFA63,0x4578,{0x87,0xC9,0xEF,0xFC,0xBE,0x66,0x43,0xC7}}; 80 REGHANDLE h; EVENT_DESCRIPTOR d; 81 EventRegister(&g, NULL, NULL, &h); 82 EventDescCreate(&d, 1, 0, 0, 4, 0, 0, 0); 83 EventWrite(h, &d, 0, NULL); 84 EventUnregister(h); 85 ``` 86 87 ### Group Policy Triggers 88 89 Subtypes: Machine/User. On domain-joined hosts where the corresponding policy exists, the trigger runs at boot. `gpupdate` alone won’t trigger without changes, but:<sup>[[1]](#references)</sup> 90 91 - Activation: `gpupdate /force` 92 - If the relevant policy type exists, this reliably causes the trigger to fire and start the service. 93 94 ### IP Address Available 95 96 Fires when the first IP is obtained (or last is lost). Often triggers at boot.<sup>[[1]](#references)</sup> 97 98 - Activation: Toggle connectivity to retrigger, e.g.: 99 ```cmd 100 netsh interface set interface name="Ethernet" admin=disabled 101 netsh interface set interface name="Ethernet" admin=enabled 102 ``` 103 104 ### Device Interface Arrival 105 106 Starts a service when a matching device interface arrives. If no data item is specified, any device matching the trigger subtype GUID will fire the trigger. Evaluated at boot and upon hot‑plug.<sup>[[1]](#references)</sup> 107 108 - Activation: Attach/insert a device (physical or virtual) that matches the class/hardware ID specified by the trigger subtype. 109 110 ### Domain Join State 111 112 Despite confusing MSDN wording, this evaluates domain state at boot:<sup>[[1]](#references)</sup> 113 - DOMAIN_JOIN_GUID → start the service if domain-joined 114 - DOMAIN_LEAVE_GUID → start the service only if NOT domain-joined 115 116 ### System State Change – WNF (undocumented) 117 118 Some services use undocumented WNF-based triggers (SERVICE_TRIGGER_TYPE 0x7). Activation requires publishing the relevant WNF state; specifics depend on the state name. Research background: Windows Notification Facility internals. 119 120 ### Aggregate Service Triggers (undocumented) 121 122 Observed on Windows 11 for some services (e.g., CDPSvc). The aggregated configuration is stored in: 123 124 - HKLM\SYSTEM\CurrentControlSet\Control\ServiceAggregatedEvents 125 126 A service’s Trigger value is a GUID; the subkey with that GUID defines the aggregated event. Triggering any constituent event starts the service.<sup>[[1]](#references)</sup> 127 128 ### Firewall Port Event (quirks and DoS risk) 129 130 A trigger scoped to a specific port/protocol has been observed to start on any firewall rule change (disable/delete/add), not just the specified port. Worse, configuring a port without a protocol can corrupt BFE startup across reboots, cascading into many service failures and breaking firewall management. Treat with extreme caution.<sup>[[1]](#references)</sup> 131 132 ## Practical Workflow 133 134 1) Enumerate triggers on interesting services (RemoteRegistry, WebClient, EFS, …): 135 - `sc.exe qtriggerinfo <Service>` 136 - `reg query HKLM\SYSTEM\CurrentControlSet\Services\<Service>\TriggerInfo /s` 137 138 2) If a Network Endpoint trigger exists: 139 - Named pipe → attempt a client open to \\.\pipe\<PipeName> 140 - RPC endpoint → perform an Endpoint Mapper lookup for the interface UUID 141 142 3) If an ETW trigger exists: 143 - Check provider and filters with `sc.exe qtriggerinfo`; if no filters, any event from that provider will start the service 144 145 4) For Group Policy/IP/Device/Domain triggers: 146 - Use environmental levers: `gpupdate /force`, toggle NICs, hot-plug devices, etc. 147 148 ## Related 149 150 - After starting a privileged service via a Named Pipe trigger, you may be able to impersonate it: 151 152 [Named Pipe Client Impersonation](/hacktricks/windows-hardening/windows-local-privilege-escalation/named-pipe-client-impersonation) 153 154 ## Quick command recap 155 156 - List triggers (local): `sc.exe qtriggerinfo <Service>` 157 - Registry view: `reg query HKLM\SYSTEM\CurrentControlSet\Services\<Service>\TriggerInfo /s` 158 - Win32 API: `QueryServiceConfig2(..., SERVICE_CONFIG_TRIGGER_INFO, ...)` 159 - RPC remote (Titanis): `Scm.exe qtriggers` 160 - ETW provider check (WebClient): `logman query providers | findstr /I 22b6d684-fa63-4578-87c9-effcbe6643c7` 161 162 ## Gotchas / Operator Notes 163 164 - Check the service start type first with `sc.exe qc <Service>`. If it is `DISABLED`, firing the trigger is not enough; you must first find a way to change the configuration. 165 - Trigger-start services may stop again after they become idle. If your follow-on action depends on a short-lived listener (RPC/named pipe/WebDAV), trigger and consume it immediately. 166 - `sc.exe qtriggerinfo` does not fully understand every undocumented trigger type. For aggregate triggers on newer Windows builds, confirm the backing GUID and constituent events in `HKLM\SYSTEM\CurrentControlSet\Control\ServiceAggregatedEvents`. 167 168 ## Detection and Hardening Notes 169 170 - Baseline and audit TriggerInfo across services. Also review HKLM\SYSTEM\CurrentControlSet\Control\ServiceAggregatedEvents for aggregate triggers. 171 - Monitor for suspicious EPM lookups for privileged service UUIDs and named-pipe connection attempts that precede service starts. 172 - Restrict who can modify service triggers; treat unexpected BFE failures after trigger changes as suspicious. 173 174 ## References 175 - [1] [There’s More than One Way to Trigger a Windows Service (TrustedSec)](https://trustedsec.com/blog/theres-more-than-one-way-to-trigger-a-windows-service) 176 - [2] [QueryServiceConfig2 function (Win32 API)](https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-queryserviceconfig2a) 177 - [3] [MS-SCMR: Service Control Manager Remote Protocol – QueryServiceConfig2](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/705b624a-13de-43cc-b8a2-99573da3635f) 178 - [4] [TrustedSec Titanis (SCM trigger enumeration)](https://github.com/trustedsec/Titanis) 179 - [5] [Reversing npsvctrig.sys - Named Pipe Service Triggers (Inbits)](https://inbits-sec.com/posts/npsvctrig-notes/) 180 - [6] [Starting WebClient Service Programmatically (Tyranid)](https://www.tiraniddo.dev/2015/03/starting-webclient-service.html)