君子藏器于身待时而动,安全不露圭角覆盂之安。
——AnonySec
项目地址: SchTask
本文阐述Windows计划任务在系统中的隐藏方式及工具化的转换。
前言
计划任务作为持久化的机制之一,也被用在红队行动中。但常见的利用方法在被安全软件阻断的同时,也没有达到隐藏效果,并提高了被发现的风险。所以,需要深入理解利用计划任务,规避风险,达到持久控制。
隐藏
创建计划任务
1 |
schtasks /Create |
命令行
1 |
schtasks /create /tn TestSchtask /tr C:\Windows\System32\cmd.exe /sc DAILY /st 13:00:00 |
XML 文件
计划任务一旦创建成功,将会自动在
%SystemRoot%\System32\Tasks
目录生成一个关于该任务的描述性 XML 文件,包含了所有的任务信息。
运行
taskschd.msc
,同时可以在任务计划程序看到刚才所创建的任务,处在程序库的根目录下。
注册表
1 |
计算机\HKEY_LOCAL_MACHINE\Software\Microsoft\SchedulingAgent\ |
1 |
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\ |
Id {GUID},任务对应的guid编号。
Index 一般任务值为3,其他值未知。
SD Security Descriptor 安全描述符,在Windows中,每一个安全对象实体都拥有一个安全描述符,安全描述符包含了被保护对象相关联的安全信息的数据结构,它的作用主要是为了给操作系统提供判断来访对象的权限。
【 经测试:Windows 7 、Windows Server 2008 无 SD 值、Windows 10 有 SD 值 】
安全软件阻止
如果主机存在安全软件,计划任务的创建会被阻止,命令行无法成功创建。(可通过 计划任务API 绕过,工具化利用此点)
schtasks /create /tn "TestTask" /ru system /tr C:\Windows\System32\cmd.exe /sc weekly /d mon /st 01:00
隐藏姿势
非完全隐藏
非完全隐藏一个计划任务,通过修改
\Schedule\TaskCache\Tree
下对应任务的 Index 值,一般情况下值为 3 。
Index 修改
以 Windows 10 为例,新建计划任务
cmd
的高级安全设置中所有者为 SYSTEM,默认无法更改注册表键值。
更改所有者为 Administrators,并赋予完全控制权限,才能修改注册表键值。
当 Index 修改为 0 后, 利用
taskschd.msc
、
schtasks.exe
、甚至系统API查询出的所有任务中,都查看不到所创建的任务。但如果知道该任务名称,可以通过
schtasks /query /tn {TaskName Path}
查到。
但在 Windows Server 2008 与 Windows 7 中,修改 Index 键值为 0 ,任务计划程序中仍存在该任务。原因未知
XML 文件删除
-
在 Windows 10 中,删除 XML 文件,并不影响计划任务的运行,且在
taskschd.msc
任务计划程序中,依然存在对应任务; - 在 Windows 7 与 Windows Server 2008 中,若删除 XML 文件,任务计划程序中的对应任务也会被删除,并且影响计划任务的运行,但注册表中项值依然存在。
完全隐藏
SD 删除
-
删除
HKLM\Software\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tree\{TaskName}\SD
-
删除
%SystemRoot%\System32\Tasks
下任务对应的 XML 文件
但经过测试,Windows 7 、Windows Server 2008 无 SD 值、Windows 10 有 SD 值。
总结
Windows 计划任务的隐藏并未绝对,因操作系统存在差异,最终实现的效果也不同。但作为持久化的机制之一,需要深入理解利用。
工具化
效果图
实现步骤
- 选择主机随机进程名作为计划任务程序文件名
-
将计划任务程序文件复制到
%AppData%\Microsoft\Windows\Themes\
中 - 创建的计划任务名取同一随机进程名
- 计划任务触发器以分钟为单位,无限期持续
- 更改 Index、删除 SD 的键值,隐藏计划任务对应的 XML 文件
-
删除已添加的计划任务
编写代码
编写任务计划的工具,需要用到任务计划API:
Microsoft.Win32.TaskScheduler.dll
。在 Visual Studio 中,可以直接从NuGet程序包中安装获取。
当然,也可以从
GitHub TaskScheduler
中下载获取。
随机进程名
选择主机随机进程名,作为计划任务程序文件名与计划任务名,主要为了每次运行名称都随机,防止后续被溯源,并且取随机进程名,也是一种隐匿。
1 |
//选择主机随机进程名 |
创建计划任务
触发器以分钟为单位,无限期持续的运行所创建的计划任务,主要是为了权限的持久性。如果说只运行一次或持续时间为一天,那对于权限的维持可以说是毫无意义。
计划任务的创建没有放在根路径下,而是创建在
\Microsoft\Windows\UPnP\
路径下,达到隐匿。
1 |
//创建计划任务 |
隐藏计划任务
XML 文件隐藏
-
在 Windows 10 中,删除 XML 文件,并不影响计划任务的运行,且在
taskschd.msc
任务计划程序中,依然存在对应任务; - 在 Windows 7 与 Windows Server 2008 中,若删除 XML 文件,任务计划程序中的对应任务也会被删除,并且影响计划任务的运行。
为了程序的可用性,这里只能将 XML 文件进行隐藏,而不是删除。
1 |
//隐藏 %SystemRoot%\System32\Tasks 下计划任务对应的 XML 文件 |
Index 修改
首先需要更改注册表对应计划任务项值的高级安全设置中的所有者。在未获取特权模式下,工具运行后提示“拒绝访问”,这显然是权限不足。
可以使用
TokenManipulator 类
,从而获取特权模式。这就需要在项目中添加一个新的C#类,之后在头部
using CosmosKey.Utils;
。
1 |
try |
获取特权模式后,更改注册表项值的所有者为 Administrators,同时要更改注册表项值的权限,这才能对 Index 进行修改操作。
1 |
//更改注册表项值的所有者 |
SD 删除
1 |
//判断SD键值是否存在(Win7 与 win2008 无SD) |
删除计划任务
修改注册表中的键值 Index 与 SD 后,任务计划程序中就查看不到该任务。通过
TaskCollection
也无法查到此任务,就无法删除所创建的计划任务。
所以,为了工具的完整性,删除代码只做参考,并未引用到程序中。
1 |
//删除计划任务 (需要管理员权限) |
DLL文件打包到EXE
可以使用 ILMerge 将 .Net 的 DLL 文件打包到 EXE 中,直接在 Visual Studio 中使用 NuGet 程序包管理下载安装即可。也可以使用 ILMerge-GUI 图形化版本打包,更加方便。
程序打包后,在 CobaltStrike 中利用
execute-assembly
可以成功在内存中加载运行。