Windows 计划任务是什么
任务计划程序由 TaskScheduler 服务驱动,是 Windows 上最常用的持久化手段之一。一个任务由触发器和动作两部分组成:触发器决定什么时候跑(开机、登录、空闲、指定时间、事件触发),动作决定跑什么(程序、脚本、COM 处理器)。任务定义以 XML 文件存放在 C:\Windows\System32\Tasks,并同步镜像到注册表,因此删掉一边还会残留另一边,排查时两边都要看。
基本信息
| 命令行工具 | schtasks /query /fo LIST /v;/tn 指定任务;/xml 导出定义 |
|---|---|
| PowerShell | Get-ScheduledTask、Get-ScheduledTaskInfo、Export-ScheduledTask |
| 定义存放 | C:\Windows\System32\Tasks 下的 XML 文件,同时镜像到注册表路径 |
| 运行身份 | 可用 SYSTEM、指定服务账号或普通用户,权限决定动作能做什么 |
| 触发器类型 | 开机、登录、空闲、定时与重复间隔、事件触发、会话状态变化 |
| 隐藏属性 | 任务可设置隐藏,界面上看不见,但命令行仍能枚举出来 |
典型使用场景
- 终端出现可疑外联后核对任务动作,确认是否被写入定时回连
- 钓鱼附件执行后的主机排查,任务计划是最常见的落地持久化之一
- 确认任务动作指向的程序路径、签名与运行账号是否合理
- 排查按固定间隔触发的异常行为,定位对应的任务定义
- 清理前导出全部任务 XML,作为处置证据与恢复依据
枚举任务与动作
枚举任务与动作
Get-ScheduledTask | Select-Object TaskName, TaskPath, State | Sort-Object TaskPath | Format-Table -AutoSize
Get-ScheduledTask | Where-Object State -ne 'Disabled' | ForEach-Object {
$a = ($_.Actions | ForEach-Object { $_.Execute + ' ' + $_.Arguments }) -join '; '
Write-Output ('{0}{1} :: {2}' -f $_.TaskPath, $_.TaskName, $a) # 任务名与动作一次打印
}
schtasks /query /tn '\SuspiciousTask' /fo LIST /v # 单任务详情
schtasks /query /xml ONE /tn '\SuspiciousTask' > D:\evidence\task.xml # 导出原始 XML 留证关键字段读法
| 字段 | 含义 | 异常信号 |
|---|---|---|
| TaskName / TaskPath | 任务名与所在文件夹 | 任务名仿冒 OneDrive、Edge、系统更新,却不在微软目录下 |
| Task To Run | 实际执行的程序与参数 | 脚本落在用户目录或临时目录,或使用编码命令 |
| Run As User | 运行身份 | 普通业务机器上出现 SYSTEM 或新创建的本地账号 |
| Schedule Type | 触发器类型 | 开机、登录与每几分钟重复组合,是保活的典型配置 |
| Last Result | 上次执行返回码 | 动作指向的文件已不存在却仍在触发,说明已被部分清理 |
| Author | 创建者 | 作者字段与运维团队不符,或为空 |
| Hidden | 是否隐藏 | 被设为隐藏的任务要优先核对内容 |
动作里出现 powershell -EncodedCommand、mshta、rundll32、regsvr32 或 wscript 这类写法时属于高危信号:编码命令本身就是为了规避关键字检测,需要先导出 XML、再解码参数内容,最后才谈删除。
删除任务要两边一起:schtasks /delete /tn 会同时处理 XML 与注册表镜像;如果只手工删掉 System32\Tasks 下的文件,任务计划程序界面仍可能残留条目。清理后重新枚举一遍确认。
批量导出与清理
批量导出与清理
New-Item -ItemType Directory -Force -Path 'D:\evidence\tasks' | Out-Null
Get-ScheduledTask | ForEach-Object { $n = $_.TaskName -replace '[\\/:*?"<>|]','_';
Export-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath | Out-File "D:\evidence\tasks\$n.xml" } # 全量留证
Get-ScheduledTaskInfo -TaskName 'SuspiciousTask' | Format-List # 看上次运行结果与时间
Disable-ScheduledTask -TaskName 'SuspiciousTask' # 先禁用观察影响
Unregister-ScheduledTask -TaskName 'SuspiciousTask' -Confirm:$false # 确认后注销
Get-ScheduledTask | Where-Object TaskName -eq 'SuspiciousTask' # 复查是否已清任务动作里的脚本文件本身也要清理,并且要核对它是否被其他入口(服务、Run 键、WMI 订阅)引用:只注销任务而留下脚本,常被下一次触发重新建回来。
触发器排查要点
- 开机或登录触发:保活首选,重启后自动恢复执行,排查时要问「谁在重启后还活着」
- 重复间隔:设置每 5 或 10 分钟重复一次,绕过本就只执行一次的设定
- 空闲触发:等用户不操作时执行,行为更隐蔽,日志时间点看起来毫无规律
- 事件触发:订阅系统事件日志或其他任务完成事件,几乎没有显式的时间规律
- 起始时间与过期设置:起始时间已过去很久却仍在重复,说明是长期潜伏
- 多动作组合:一个任务挂多个动作,删掉一个后还有另一个继续执行
任务的凭据保存方式同样要看:以「存储的密码」运行的任务,意味着攻击者已掌握该账号的明文口令;注销任务却不改密码,通道依然敞着。