Privilege Escalation · intermediate · ~12 min

Windows privesc: service misconfigurations

**What you will learn** - Explain why Windows services are a prime local privilege-escalation target because they usually run as `SYSTEM`. - Identify the three classic service misconfigurations: **unquoted service paths**, **weak service permissions**, and **writable service binaries/DLLs**. - Enumerate services safely in an authorized lab with `sc qc`, `accesschk.exe`, and `icacls`, and read the output to tell a misconfiguration from a safe configuration. - Apply the correct **remediation** for each: quoting paths, tightening service DACLs, and fixing NTFS file ACLs — then **verify** each fix actually blocks the escalation. - Choose the Windows event logs and monitoring signals that let a blue team detect service tampering, and know what must never be logged.

Overview

Security objective. The asset you are protecting is the SYSTEM (a.k.a. NT AUTHORITY\SYSTEM) integrity level on a Windows host — the highest local privilege. The threat is a local attacker who already has a low-privileged foothold (a standard user account, e.g. from phishing or a web-app shell) and wants to become SYSTEM without an exploit, just by abusing how a service is configured. By the end you will be able to detect these misconfigurations before an attacker does and prevent the escalation.

A Windows service is a background program managed by the Service Control Manager (SCM). Most services run under a highly privileged account — LocalSystem, LocalService, or NetworkService — because they need to touch hardware, the registry, or other users' data. That is exactly why they are dangerous: if a low-privileged user can influence what code a SYSTEM service runs, that code runs as SYSTEM.

This lesson builds directly on your prereqs. From Windows services you already know what a service is, that it has a binary path (binPath), a start type, and a service account, and that sc.exe and services.msc manage them. From Privilege escalation: the enumeration-first mindset you know the golden rule: enumerate before you act — you map the terrain (what services exist, who can change them, what files you can write) before touching anything. Here we apply that mindset to three specific, extremely common weaknesses and — most importantly — to fixing them.

Everything below is written for an authorized lab: your own Windows VM, a course-provided target, or a CTF box. Never run these techniques against a machine you do not own or have explicit written permission to test.

Why it matters

Service misconfigurations are consistently among the most common local privilege-escalation paths on Windows, and they need no memory-corruption exploit, no shellcode, and no zero-day — just built-in tools and a writable path. That makes them reliable for attackers and, crucially, cheap to fix for defenders.

In authorized professional work these skills matter on both sides of the table:

  • Penetration testers and red teams enumerate services during post-exploitation to demonstrate real impact: turning a limited user shell into full host compromise. A finding like "unquoted service path in VulnSvc allows any authenticated user to gain SYSTEM" is concrete, reproducible, and actionable.
  • Blue teams, sysadmins, and hardening engineers audit their own fleet for these same issues, because a single mis-installed third-party service can undermine an otherwise well-patched machine. Many enterprise breaches escalate through a vendor service that was installed with a lazy DACL or an unquoted path.
  • Detection engineers build alerts around service creation and reconfiguration events, because legitimate service changes are rare and predictable, making anomalies easy to spot.

Understanding why each misconfiguration escalates — not just how to trigger it — is what lets you write a correct fix and prove it works, which is the whole job.

Core concepts

Windows services run as SYSTEM and are controlled by the Service Control Manager (SCM). Three independent misconfigurations each let a low-privileged user control what a SYSTEM service executes. We teach each one, then the enumeration and remediation that ties them together.

Concept 1 — Unquoted service path

Definition. A service whose binary path contains spaces but is not wrapped in quotes, e.g. binPath = C:\Program Files\My App\service.exe.

Plain explanation. When the SCM launches a service, it parses the path left to right. Because a space normally separates a program from its arguments, an unquoted path with spaces is ambiguous. Windows tries each interpretation in order:

  1. C:\Program.exe
  2. C:\Program Files\My.exe
  3. C:\Program Files\My App\service.exe

How it works. The SCM runs the first file it finds. If a low-privileged user can create C:\Program.exe (the root of C:\ is sometimes writable by non-admins), the SCM runs *their* binary as SYSTEM on next service start.

When it applies / when not. Only when the path has a space and is unquoted and an earlier interpretation points to a directory the attacker can write to. A quoted path, or a path with no spaces, or one where every earlier directory is protected, is not exploitable.

Pitfall. Testers often flag every unquoted path as "critical." It is only exploitable if you can actually write to an earlier segment. Without a writable earlier directory it is a hygiene finding, not an escalation.

Concept 2 — Weak service permissions (weak service DACL)

Definition. A service object whose DACL (Discretionary Access Control List) grants a low-privileged user rights such as SERVICE_CHANGE_CONFIG (SC_MANAGER / WRITE on the service).

Plain explanation. Every service is a securable object with its own permissions, separate from the file on disk. If you hold SERVICE_CHANGE_CONFIG, you can rewrite the service's binPath to point at any program you like.

How it works. You reconfigure and restart the service:

sc config vulnsvc binPath= "C:\lab\payload.exe"
sc stop vulnsvc
sc start vulnsvc

On start, the SCM launches your program as the service account (SYSTEM). In a lab your payload.exe might simply add your user to the local Administrators group — never real malware.

When it applies / when not. Only when your specific user or a group you belong to (e.g. Authenticated Users, Everyone, INTERACTIVE) is granted config-changing rights. Read-only rights (SERVICE_QUERY_CONFIG) do not escalate.

Pitfall. Confusing service-object permissions with file permissions. They are different ACLs; a service can have a locked-down binary but a wide-open service DACL, and vice versa.

Concept 3 — Writable service binary or DLL (and DLL hijacking)

Definition. The service's .exe, or a DLL it loads, sits in a location the low-privileged user can overwrite (an NTFS ACL problem), or the service searches for a DLL in a directory the user can write to.

Plain explanation. If you can replace the file the SYSTEM service executes, the service runs your code next time it starts. DLL hijacking is the same idea one level down: if a service loads helper.dll by name and searches a writable directory first, you drop your own helper.dll there.

How it works. Overwrite the binary (or plant the DLL), then wait for or trigger a restart. The Windows DLL search order means a service that loads a library without an absolute path may pick up an attacker-planted DLL from its working directory or a writable PATH entry.

When it applies / when not. Only when the file or a search-path directory is writable by your user and you can cause a restart (reboot, scheduled restart, or you hold start/stop rights). Correct ACLs make this impossible.

Pitfall. Assuming "the file is in C:\Program Files, so it's safe." Installers sometimes loosen ACLs on their own subfolder. Always check the actual ACL, not the location.

Enumeration (the enumeration-first mindset applied)

You never guess — you enumerate:

  • sc qc <service> — shows BINARY_PATH_NAME (spot unquoted paths) and the service account.
  • accesschk.exe -uwcqv <user> * (Sysinternals) — lists services your user can modify (SERVICE_CHANGE_CONFIG, SERVICE_ALL_ACCESS). The -w flag limits output to write access.
  • icacls "C:\Path\to\service.exe" — shows NTFS permissions on the binary (look for (M)/(F)/(W) granted to your user or broad groups).
  • Automated collectors like WinPEAS or PowerUp roll all three up, but you must be able to read the raw output yourself.
THREAT MODEL — Windows service privilege escalation

  ASSET: NT AUTHORITY\SYSTEM integrity (full host control)

  +-------------------------------------------------------------+
  |  Windows host (authorized lab VM)                           |
  |                                                             |
  |   [Low-priv user shell]  <-- attacker foothold             |
  |          |                                                  |
  |   =======|=========== TRUST BOUNDARY ====================== |
  |          |   (standard user  -->  SYSTEM)                   |
  |          v                                                  |
  |   Entry points controlled by the SCM:                      |
  |     (1) Unquoted binPath   -> writable earlier dir          |
  |     (2) Weak service DACL  -> sc config binPath            |
  |     (3) Writable exe/DLL   -> overwrite / DLL hijack        |
  |          |                                                  |
  |          v                                                  |
  |   [Service Control Manager] --starts--> chosen code        |
  |          |                                                  |
  |          v                                                  |
  |   Runs as SYSTEM  ==> asset compromised                     |
  +-------------------------------------------------------------+

  Defender goal: keep every entry point closed so crossing the
  trust boundary is impossible, and log attempts that try.

Knowledge check.

  1. What asset is protected in this threat model, and what trust boundary must the attacker cross?
  2. An unquoted path exists but every earlier directory (C:\, C:\Program Files) denies write to standard users. Which insecure assumption is absent here, and why is the finding therefore not an escalation?
  3. Which single Windows event ID would most directly reveal an attacker running sc config to repoint a service's binPath (think about the earlier list of enumeration/remediation tools), and why is that event rare enough to alert on?

Syntax notes

The key commands are all built-in or Sysinternals tools; none of them are exploits by themselves — they are the same commands admins use to audit and fix services. Annotated, lab-safe:

sc qc <service>
#  ^  ^  ^
#  |  |  +-- service name (short name, not display name)
#  |  +----- "query config": prints BINARY_PATH_NAME, START_TYPE,
#  |          SERVICE_START_NAME (the account it runs as)
#  +-------- Service Control tool (built in)

accesschk.exe -uwcqv <username> *
#              | | | | |        ^ wildcard: check all services
#              | | | | +--- v: verbose (list granted rights)
#              | | | +----- q: omit banner
#              | | +------- c: treat name as a Windows service
#              | +--------- w: only objects with WRITE access
#              +----------- u: suppress errors
#  => lists services <username> can RECONFIGURE (the danger set)

icacls "C:\Program Files\My App\service.exe"
#  => prints NTFS ACL. Look for your user or a broad group with
#     (M) Modify, (F) Full, or (W) Write. Those are writable-binary hits.

Remediation commands (what you run as an admin to fix each issue):

# Fix 1 - quote an unquoted path:
sc config vulnsvc binPath= "\"C:\Program Files\My App\service.exe\""
#   note: a space is REQUIRED after 'binPath=' (sc.exe quirk)

# Fix 2 - reset a weak service DACL to a known-good SDDL:
sc sdset vulnsvc "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)"
#   grants full control to SYSTEM (SY) and Admins (BA); read/query only
#   to Interactive (IU) and Service (SU) users -> no CHANGE_CONFIG for them

# Fix 3 - remove a wide grant from a service binary's NTFS ACL:
icacls "C:\Program Files\My App\service.exe" /remove:g "Users"
icacls "C:\Program Files\My App\service.exe" /inheritance:e

Lesson

Windows services usually run as SYSTEM, so controlling what a service executes means SYSTEM. Three classic service misconfigurations:

1. Unquoted service path

A service binary path with spaces and no quotes:

C:\Program Files\My App\service.exe

Windows tries C:\Program.exe, then C:\Program Files\My.exe, etc. If you can write to an earlier location (e.g. C:\), your binary runs as SYSTEM. Fix: quote the path.

2. Weak service permissions

If your user has SERVICE_CHANGE_CONFIG on a service, you can repoint its binary:

sc config vulnsvc binPath= "C:\Users\you\evil.exe"

then restart it → SYSTEM. Audited with accesschk. Fix: correct service DACLs.

3. Writable service binary / DLL

If the service's .exe or a DLL it loads is writable by your user (an NTFS ACL problem), replace it. DLL hijacking also applies when a service loads a DLL from a writable directory in its search order. Fix: correct file ACLs; have services load DLLs from absolute, protected paths.

Enumeration

sc qc <svc>, accesschk.exe -uwcqv <user> *, and WinPEAS surface these. Each turns into SYSTEM via the service restarting.

Code examples

The safest way to learn this is the insecure -> secure -> verify loop on your own VM. Everything here is lab-only.

(1) WARNING: intentionally vulnerable — use only in a local, isolated, authorized lab. Do not deploy.

The snippet below creates a deliberately misconfigured service so you can study all three problems at once, then detect them. Run it as admin only inside a throwaway Windows VM with no network access.

# LAB SETUP (run as admin in an isolated VM). Creates a weak service.
# 1) Unquoted path WITH spaces:
sc.exe create VulnSvc binPath= "C:\Program Files\Lab App\svc.exe" start= demand

# 2) Weaken the service DACL so 'Authenticated Users' can reconfigure it
#    (this is the misconfiguration an installer might create by accident):
sc.exe sdset VulnSvc "D:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)"

# 3) Loosen NTFS ACL on the folder so standard users can write the binary:
icacls "C:\Program Files\Lab App" /grant "Authenticated Users:(OI)(CI)M"

Detect the problems (enumeration, from a standard-user shell)

C:\> sc qc VulnSvc
[SC] QueryServiceConfig SUCCESS
        BINARY_PATH_NAME   : C:\Program Files\Lab App\svc.exe   <-- UNQUOTED + spaces
        SERVICE_START_NAME : LocalSystem                        <-- runs as SYSTEM

C:\> accesschk.exe -uwcqv authusers VulnSvc
  RW VulnSvc
        SERVICE_CHANGE_CONFIG                                   <-- weak DACL: reconfigurable

C:\> icacls "C:\Program Files\Lab App"
  C:\Program Files\Lab App  Authenticated Users:(OI)(CI)(M)     <-- writable binary path

All three red flags confirmed by enumeration, not by attacking anything.

(2) SECURE — remediate each finding

# Run as admin.

# Fix 1: quote the binary path.
sc.exe config VulnSvc binPath= "\"C:\Program Files\Lab App\svc.exe\""

# Fix 2: reset the service DACL so only SYSTEM + Admins can change config;
#        normal users get read/query only.
sc.exe sdset VulnSvc "D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)"

# Fix 3: remove the over-broad write grant and re-enable inheritance from
#        the protected 'Program Files' parent.
icacls "C:\Program Files\Lab App" /remove:g "Authenticated Users"
icacls "C:\Program Files\Lab App" /inheritance:e

(3) VERIFY — prove the fixes reject bad input and accept good input

# Bad input is now REJECTED:

C:\> sc qc VulnSvc | findstr BINARY_PATH_NAME
        BINARY_PATH_NAME : "C:\Program Files\Lab App\svc.exe"   <-- quoted: no earlier-path hijack

C:\> accesschk.exe -uwcqv authusers VulnSvc
  No matching objects found.                                   <-- user can no longer reconfigure

C:\> icacls "C:\Program Files\Lab App"
  C:\Program Files\Lab App  BUILTIN\Users:(OI)(CI)(RX)          <-- read+execute only, no write

# Good input still WORKS: the service starts and runs normally as SYSTEM.
C:\> sc start VulnSvc
[SC] StartService SUCCESS

Expected outcome. After remediation, sc qc shows a quoted path, accesschk reports "No matching objects found" for a standard user, and icacls shows read/execute only — yet the service still starts and functions. That combination is the proof that the fixes closed the escalation without breaking the service.

Lab cleanup / reset

# Run as admin to fully remove the lab service and folder.
sc.exe stop VulnSvc
sc.exe delete VulnSvc
Remove-Item -Recurse -Force "C:\Program Files\Lab App"

Then revert the VM to a clean snapshot so no weakened ACLs linger.

Line by line

Walking the insecure -> secure -> verify loop step by step:

  1. sc.exe create VulnSvc binPath= "C:\Program Files\Lab App\svc.exe" — registers a service whose stored path has spaces and no inner quotes. The SCM will later parse this ambiguously.
  2. sc.exe sdset ... AU ... — rewrites the service's security descriptor (SDDL) so the AU (Authenticated Users) SID gets config-change rights. This is Concept 2's weak DACL, injected on purpose.
  3. icacls ... /grant "Authenticated Users:(OI)(CI)M" — grants Modify (M) on the folder to all authenticated users. (OI)(CI) make it inherit to files and subfolders, so the .exe is now writable — Concept 3.
  4. sc qc VulnSvc — enumeration output. The key line is BINARY_PATH_NAME with no surrounding quotes and a space after Program. SERVICE_START_NAME : LocalSystem confirms the payoff would be SYSTEM.
  5. accesschk -uwcqv authusers VulnSvc — prints SERVICE_CHANGE_CONFIG, proving a standard user could run sc config to repoint the binary. This is the evidence a tester records.
  6. icacls "...Lab App" — shows Authenticated Users:(M) on the path, confirming the writable-binary hit.

Now the fixes, and how each value changes:

Step Command Before After Why the escalation closes
Fix 1 sc config ... binPath= "\"...\"" C:\Program Files\... (unquoted) "C:\Program Files\..." (quoted) SCM no longer parses C:\Program.exe; only the real binary can run
Fix 2 sc sdset (no AU entry) AU has CHANGE_CONFIG AU absent; IU/SU read-only Standard users can't rewrite binPath
Fix 3 icacls /remove:g + /inheritance:e Authenticated Users:(M) Users:(RX) inherited Binary/DLL can't be overwritten; no hijack
  1. Verification re-runs the same three enumeration commands. Each now returns the safe form (quoted path, "No matching objects found", (RX)), while sc start VulnSvc still succeeds — the service works, the escalation does not. Re-running the attacker's enumeration as the defender's proof is the core discipline: a fix you cannot verify is not a fix.

Common mistakes

Real mistakes learners and even professionals make:

Wrong approach Why it's wrong Corrected approach How to recognise / prevent
Flagging every unquoted path as "critical SYSTEM escalation" Exploitability depends on a writable earlier directory; most unquoted paths under C:\Program Files are not writable by standard users Confirm write access with icacls C:\ and each earlier segment before rating it; otherwise it's a low/hygiene finding Test the assumption; severity = exploitability + impact, not pattern-match
Quoting the path but forgetting the special sc.exe syntax binPath= needs a space after the = and escaped inner quotes; a malformed command silently sets a broken path and the service won't start Use binPath= "\"C:\...\"" exactly, then sc qc to confirm Always re-query after any sc config change
Fixing the file ACL but ignoring the service DACL (or vice versa) They are two separate ACLs; a locked binary with a wide-open service DACL is still fully exploitable via sc config Remediate and verify all three vectors independently Keep a checklist: path quoting, service DACL, file/DLL ACL
Assuming an antivirus/scanner "pass" means the host is secure Scanners miss custom services and vendor ACL mistakes; a passing scan does not prove security Manually enumerate services and ACLs; treat scanners as one input, not proof Never claim a system is "completely secure"
Testing on a machine you don't own "just to check" Unauthorized access is illegal and unethical regardless of intent Only test on your VM, a lab, or a scope you have written authorization for Keep the authorization letter/scope handy before any test
Leaving the deliberately weak lab service installed The vulnerable VulnSvc is a real backdoor if the VM is ever exposed Run the cleanup/reset steps and revert to a clean snapshot Snapshot before, revert after

Debugging tips

When enumeration or a fix doesn't behave as expected:

  • accesschk.exe prints a EULA prompt or nothing. First run needs accesschk.exe /accepteula. If output is empty, you may be checking the wrong principal — try your actual username, "Authenticated Users", Everyone, and Users. Confirm your identity with whoami /groups.
  • sc config returns Access is denied. You don't hold SERVICE_CHANGE_CONFIG on that service — which, from a defender's view, is good. Re-check with accesschk -uwcqv <user> <svc>. From a tester's view, that vector simply isn't available.
  • The service won't start after you quoted the path. The most common cause is bad sc config quoting. Run sc qc <svc> and inspect BINARY_PATH_NAME character by character; the outer value must be quoted and the file must exist at that exact path. Check Get-WinEvent -LogName System for SCM error 7000/7009 (timeout/failure) or 7011.
  • icacls change seems to have no effect. Explicit ACEs and inheritance can conflict. After /remove:g, run icacls <path> again and confirm the broad group is gone; use /inheritance:e to re-enable inheritance from a protected parent, or /reset to restore inherited defaults.
  • You can't tell which account a service uses. sc qc <svc> shows SERVICE_START_NAME. LocalSystem, NT AUTHORITY\SYSTEM, .\LocalSystem all mean SYSTEM. LocalService/NetworkService are lower privilege and change the impact rating.

Questions to ask when a fix fails. Did I re-query after changing config? Am I testing as the low-privileged user, not as admin? Are all three vectors closed, or did I fix one and forget another? Does the service still start (did I break function while fixing security)?

Memory safety

Security & safety — detection and logging.

Because these escalations use legitimate administrative actions, detection depends on logging the actions and alerting on the ones that shouldn't happen.

What to log (and alert on):

  • Service installation and change — Windows Event ID 7045 (System log) for a new service installed, and 7040 for start-type changed. Legitimate service creation is rare on a workstation, so 7045 is a high-value alert. Enable the Security-log audit for service changes to get 4697 ("A service was installed by the system").
  • Process/command auditing — with command-line auditing on, Event ID 4688 captures sc.exe config, sc.exe sdset, and icacls invocations. Repointing a binPath shows up clearly here.
  • Each security-relevant event should record: timestamp (UTC), source account/SID and host, the resource (service name, binary path), the action and its result (success/denied), the security decision (config changed, ACL modified), and a correlation ID so the service change, the restart, and the resulting SYSTEM process can be tied together.
  • File-integrity monitoring on service binaries and their folders flags an overwritten .exe or a newly planted DLL.

What to NEVER log: passwords, tokens, session cookies, private keys, full credential blobs, or unnecessary PII. When capturing command lines, be aware some tools accept secrets as arguments — scrub or avoid logging those fields.

Which events signal abuse: a standard (non-admin) user account associated with a 7045/4697 service install; a binPath that changes to an unusual location (C:\Users\..., C:\Temp, %TEMP%); a service that stops and immediately restarts right after an sc config (correlate 7040/7045 with 4688); a new SYSTEM process whose parent is services.exe but whose image is in a user-writable path.

How false positives arise: legitimate software updates and installers create and reconfigure services and change ACLs; patch windows produce bursts of 7045/7040. Reduce noise by baselining known installers, correlating with change-management/maintenance windows, and alerting on service changes made by non-administrative or interactive user accounts rather than on service changes in general.

Real-world uses

Authorized real-world use case. During an internal penetration test with signed scope, a tester lands a low-privileged shell on a workstation via a phished user. Enumerating services, they find a third-party backup agent installed with an unquoted path under a folder the installer left writable by Authenticated Users. They document the finding — service name, sc qc output, icacls proof, and the SYSTEM service account — rate its severity from actual exploitability, and hand the client a remediation: quote the path, tighten the folder ACL, reset the service DACL, and a retest step. The client's blue team then adds a 7045/4688 alert so any future recurrence is caught.

Professional best-practice habits:

Habit Beginner Advanced
Validation / enumeration Run sc qc, accesschk, icacls and read the raw output Automate fleet-wide audits (PowerShell/GPO reporting), diff against a known-good baseline
Least privilege Never grant Authenticated Users/Everyone config or write on services Design service accounts as gMSA/virtual accounts with only required rights; avoid LocalSystem when a lower account works
Secure defaults Always quote binary paths; install under protected Program Files Ship installers that set correct DACLs/ACLs and pass a hardening lint before release
Logging / detection Confirm 7045/7040 are being collected Central SIEM rules correlating service change -> restart -> new SYSTEM process, tuned for installer noise
Error handling Re-query after every change to confirm it applied Fail-closed automation that refuses to leave a service half-reconfigured

Across both levels the discipline is the same: least privilege, secure defaults, verify every change, and log the security-relevant ones.

Practice tasks

All tasks are lab-only: use an isolated, snapshot-backed Windows VM (or an authorized course/CTF target) with no production data and, ideally, no network. Before starting any task, confirm the authorization checklist: (1) I own or have written permission for this machine; (2) it is isolated/snapshotted; (3) I will restore it afterward. Each task ends with a defensive conclusion: remediate and verify.

Beginner 1 — Read a service's configuration.

  • Objective: identify whether a given service is unquoted and what account it runs as.
  • Requirements: run sc qc <service> on three services of your choice.
  • Output: for each, note BINARY_PATH_NAME (quoted or not, spaces or not) and SERVICE_START_NAME.
  • Constraints: read-only; do not change anything.
  • Hints: a path is only potentially exploitable if it has a space and no quotes.
  • Concepts: unquoted service path, service account.
  • Defensive conclusion: for any unquoted-with-spaces path, write the exact sc config command that would quote it.

Beginner 2 — Map who can change a service.

  • Objective: determine whether your standard user can reconfigure any service.
  • Requirements: run accesschk.exe -uwcqv <youruser> * (accept the EULA first).
  • Output: list any services showing SERVICE_CHANGE_CONFIG or SERVICE_ALL_ACCESS.
  • Constraints: enumeration only; do not run sc config.
  • Hints: also check "Authenticated Users" and Everyone as the principal.
  • Concepts: weak service DACL, enumeration-first mindset.
  • Defensive conclusion: for one finding, write the sc sdset fix and explain which SID you removed.

Intermediate 1 — Build and detect the vulnerable lab service.

  • Objective: create the deliberately weak VulnSvc from the lesson, then detect all three problems purely by enumeration.
  • Requirements: run the lab-setup block as admin; then, from a standard-user shell, produce the three enumeration outputs.
  • Input/output: input = the setup commands; output = annotated sc qc, accesschk, icacls results with the red flags circled.
  • Constraints: do NOT create a payload binary or trigger the escalation; detection only.
  • Hints: icacls on the folder reveals inherited write access to the .exe.
  • Concepts: all three misconfigurations, enumeration.
  • Defensive conclusion: state which log event (7045/4697/4688) would have revealed the misconfigured install.

Intermediate 2 — Remediate and verify.

  • Objective: fix VulnSvc and prove each fix works.
  • Requirements: apply the three remediation commands, then re-run the three enumeration commands as a standard user.
  • Output: a before/after table showing unquoted->quoted, CHANGE_CONFIG->"No matching objects found", and (M)->(RX), plus a successful sc start.
  • Constraints: the service must still start after remediation.
  • Hints: re-query after every change; a fix you can't verify isn't a fix.
  • Concepts: mitigation verification, secure defaults.
  • Defensive conclusion: explain why the service still functioning as SYSTEM while the user can no longer influence it is the proof of success.

Challenge — Author a remediation finding with retest and detection.

  • Objective: write a professional finding for one real misconfiguration you created in the lab.
  • Requirements: produce a finding with title, severity justified by exploitability/access/impact (not automatically "critical"), affected component, preconditions, safe reproduction (enumeration only), evidence (sanitized command output), impact, likelihood, remediation, and a retest procedure. Add a detection section listing the exact event IDs and one SIEM alert idea.
  • Constraints: no real target names/IPs; use placeholders; no working payload.
  • Hints: severity for an unquoted path with a non-writable earlier directory is much lower than one with a writable directory — say why.
  • Concepts: reporting, severity rating, detection/logging.
  • Defensive conclusion: end with the verification evidence that would let a client mark the finding "remediated."

Summary

Main concepts. Windows services usually run as SYSTEM, so a low-privileged user who can influence what a service runs gains SYSTEM. Three independent misconfigurations do this: unquoted service paths (a writable earlier path segment gets executed), weak service permissions (SERVICE_CHANGE_CONFIG lets you sc config a new binPath), and writable service binaries/DLLs (overwrite the file or DLL-hijack). Service-object DACLs and NTFS file ACLs are separate and must both be checked.

Key commands. Enumerate with sc qc <svc> (path + account), accesschk.exe -uwcqv <user> * (who can reconfigure), and icacls <path> (writable binary/DLL). Remediate with sc config binPath= "\"...\"" (quote), sc sdset (fix service DACL), and icacls /remove:g + /inheritance:e (fix file ACL). Always re-run the enumeration commands afterward to verify.

Common mistakes. Rating every unquoted path critical without checking write access; fixing one ACL and forgetting the other; malformed sc config quoting; trusting a scanner "pass" as proof of security; leaving the weak lab service installed; and — never acceptable — testing systems you don't own.

What to remember. Enumerate before you act. Severity comes from real exploitability, not a pattern match. Every vulnerability needs a fix and a verification that the fix rejects the attack while the service still works. Log service installs/changes (7045, 7040, 4697, 4688), never log secrets, and alert on service changes made by non-admin users. Nothing is ever "completely secure" — but these three misconfigurations are cheap to close and easy to detect.