Uncategorized

A very common technique in ransomware scenarios is the deployment of Scheduled Tasks via Group Policy object.

So I thought I’d start to post some content around this. To start with I was looking locally to enable the following:

“Show me all the command lines used in scheduled tasks on Windows with PowerShell”

So I knocked up this really simple proof of concept (there are other ways to write this obvs)

$tasknames = Get-ScheduledTask -TaskName * | Get-ScheduledTaskInfo | Sort-Object -Property LastRunTime -Descending

foreach($task in $tasknames){
$task
$actions = Get-ScheduledTask -TaskName $task.TaskName | select -ExpandProperty Actions
$actions
$actions.Arguments
$actions.Execute

if($actions.Execute -like "*powershell*"){
write-host "PowerShell Detected" -ForegroundColor Red
}

if($actions.Execute -like "*cmd*"){
write-host "PowerShell Detected" -ForegroundColor Red
}

if($actions.Execute -like "*certutil*"){
write-host "PowerShell Detected" -ForegroundColor Red
}

if($actions.Execute -like "*bitsadmin*"){
write-host "PowerShell Detected" -ForegroundColor Red
}

if($actions.Execute -like "*vssadmin*"){
write-host "PowerShell Detected" -ForegroundColor Red
}

}

What we are looking at here is for commandline which run a range of commands which include strings like:

  • Powershell
  • cmd
  • VSSADMIN
  • CERTUTIL

Just as examples right!

So maybe let’s zoom out a bit!

Let’s assume the threat actor has obtained Domain Administrator rights (or they have found a GPO that users can edit that is scoped to the whole domain).

They then create a new Group Policy Object (GPO) that creates a scheduled task on the target servers/PC devices.

They then run a command to expedite group policy updates: e.g. (there’s way more than one way to do this part!)

powershell.exe -Command "Get-ADComputer -filter * -Searchbase '%s' | foreach{ Invoke-GPUpdate -computer $_.name -force -RandomDelayInMinutes 0}"

So we have few places to hunt:

So I’m working backwards here, we also have to remember this might have been used for persistence or other actions (deploy implants/RATs/Miners etc.). You may want to do some funky on the command line and look for “strange” exe names:

$Execute = @()

$tasknames = Get-ScheduledTask -TaskName * | Get-ScheduledTaskInfo | Sort-Object -Property LastRunTime -Descending

foreach($task in $tasknames){

$actions = Get-ScheduledTask -TaskName $task.TaskName | select -ExpandProperty Actions
$Execute += $actions.Execute

}

$Execute | Group-Object

This might need some tidy up, remember you can nest commands so this can get funky!

What about the Logs

When we create a scheduled task what do we see in the logs?

  • By default, nothing in the system or application log.
  • The Task Scheduler Operational Log is disabled by default

Now if we have “Audit Object Access : Other Object Access Events” Auditing SUCCESS then we would get the following event id in the Security log:

4698

But that’s NOT enabled by default on say Windows 11.

We tested this by creating a new scheduled task

$taskname = "Demo Service2"
$taskdescription = "Demo Service to get Service List"
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -command "Get-Service"'
$trigger =  New-ScheduledTaskTrigger -AtStartup -RandomDelay (New-TimeSpan -minutes 3)
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 2) -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName $taskname -Description $taskdescription -Settings $settings -User "System"

This is why I went straight to enumeration of the tasks themselves and command lines

Get-ScheduledTask -TaskName * | Get-ScheduledTaskInfo | Sort-Object -Property LastRunTime -Descending | Select-Object -Property TaskName -First 10

Now this might not be super helpful if the last task run was encrypter.exe (if that’s occured there’s a whole different route you probably need to take, like build new environments and restoring from backups! anyway with regards to the scheduled tasks command, the rest you can see is history! Stay tuned because we are going to look at this in a bit more detail!

Detection in Microsoft Defender for Endpoint (MDE)

Now.. you are going to need to realise that this isn’t so simple! Because in a “normal” windows environment you will have these events created all the time

DeviceEvents 
| where ActionType == "ScheduledTaskCreated"
| sort by Timestamp desc 
| summarize count() by ActionType

So let’s see if we can get some more details:

DeviceEvents 
//| where ActionType == "ScheduledTaskCreated"
// options include ScheduledTaskUpdated ScheduledTaskDeleted
| where ActionType == "ScheduledTaskCreated"
| sort by Timestamp desc 
//| summarize count() by ActionType
//| summarize count() by InitiatingProcessAccountSid
// look for system SID https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-identifiers
| project Timestamp, DeviceId, DeviceName, ActionType, AdditionalFields

AdditionalFields is going to give us some more strings to search on, however as you can see, that’s not that much detail!

The best place to hunt is going to be via PowerShell, Event logs and head to the domain controllers and monitor GPO changes I reckon!