daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

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)