LocalSystem on a Load-Balanced Production Node
You have a foothold on APP-07 as the low-privileged domain account svc_report, recovered from a world-readable configuration file. APP-07 is one of three Windows Server 2019 nodes behind a load balancer, processing live orders. A next-generation EDR agent is installed in prevention mode and the SOC is staffed 24/7.
Enumeration shows: svc_report holds SeImpersonatePrivilege via the IIS application pool identity; an unquoted service path for "Acme Backup Agent" running as LocalSystem, with an install directory you have not yet checked permissions on; and a scheduled task that runs every four hours and can be modified by the account. Patch Tuesday is in five days and the app pool recycles nightly at 03:00.
It is Wednesday afternoon. The change window is Sunday 02:00 to 04:00. The client's constraints are explicit: no new accounts, no changes to production data, and nothing that survives their cleanup.
1. Select the privilege escalation path and justify the choice against reliability, footprint and detection.
Read the worked answer
Three candidate paths, judged on the client's constraints first and technical elegance last.
- Unquoted service path. Only viable if
icaclsshows write permission somewhere inC:\Program Files\Acme Backup Agent\or the path segments before it. In practice the install directory is usually protected, and exploiting it needs a service restart, which on a live order-processing node is a self-inflicted outage. Verify permissions before spending time; do not assume. - SeImpersonate (Potato-family). The account genuinely holds the privilege, and a coerce-and-impersonate chain yields LocalSystem without a reboot. But token-coercion techniques need a trigger that makes a privileged process connect to you - a scheduled task, the spooler, DCOM - and several classic CLSIDs were removed on Server 2019, so a variant must be validated on a lab image of the same build first. The stock tooling is heavily signatured, so EDR prevention will likely block the default binaries; a compiled or script-based variant lowers that risk but raises the skill and time cost.
- Modifiable scheduled task. Being able to change a task does not by itself give you the run-as identity you need - but it is a clean way to create the privileged trigger for the impersonation chain, and it reverts easily.
Decision: validate the Potato variant offline, then use the task as the trigger, provided the account context gives LocalSystem and the EDR test on the lab image passes. Fall back to the unquoted path only if permissions allow and the app pool recycle at 03:00 can carry the restart instead of a manual one.
2. The client forbids new accounts and persistence. How do you demonstrate LocalSystem-level compromise while honouring that?
Read the worked answer
Separate proof of privilege from maintenance of access. A local administrator account you create is persistence: it is exactly what the constraint forbids, and it also becomes a credential the client must remember to delete.
Instead, prove the escalation in a way that is self-evidencing and self-reverting:
- Execute a single command as LocalSystem that returns identity and is impossible to confuse with the low-privileged account:
whoami /privandwhoami /groupsshowing SYSTEM and the full privilege set, captured with a UTC timestamp and the host name. - Demonstrate consequential access without modifying anything: read a file only SYSTEM can read (the SAM hive copy or a protected config), hash it, and record the hash - do not dump credentials, do not crack anything, do not touch order data.
- Where the client wants proof of administrative reach, show a read-only operation such as listing an administrative share, not a write.
Then remove every artefact in the same session: the compiled payload, the temporary directory, any task modification reverted to its original definition. Log what was created, where, and when it was deleted, and offer the client the list so their cleanup can be verified. "Nothing survives cleanup" is only credible if you can enumerate what briefly existed, and the report needs that same list.
3. It is Wednesday and the only sanctioned window is Sunday 02:00 to 04:00. Do you wait, and how do you coordinate?
Read the worked answer
The decision is a risk trade between a technical failure mode and an operational one, and the client owns the operational half.
- Why waiting is the default. A failed impersonation attempt can hang a worker process; the app pool recycling nightly at 03:00 is a natural cover and a natural recovery point. Testing at Wednesday 14:00 risks an order-processing outage on one of three nodes, at peak load, in front of a SOC that will open an incident about the very activity you are authorised to perform.
- Why waiting is not automatic. Sunday 04:00 is the hard stop, and only one attempt fits if something goes wrong. That argues for rehearsing the full chain on a lab image of the same build this week, so the Sunday attempt is the second time you have run it, not the first.
- Coordination. Tell the SOC duty manager and the application owner in advance: host, time window, expected EDR alerts on that host, the account you will use, and the rollback (recycle the app pool, revert the task, delete the artefacts). Agree a phone number and a stop signal. Ask them to confirm no change freeze is pending.
- If the window is refused, record it and test with an on-call engineer present under an explicit written approval, or defer the escalation to a follow-on phase. An unattended, unauthorised attempt on live order processing is the failure that ends the engagement.