Advanced Windows Task Scheduler Playbook-Part.3 Lateral Movement

· 2022-09-28 06:30 · 0 阅读

原创 zcgonvh 2022-09-28 06:30 北京

Advanced Windows Task Scheduler Playbook - Part.3 from RPC to lateral movement

Advanced Windows Task Scheduler Playbook - Part.3 from RPC to lateral movement

0x00 问题

书接上文,在对计划任务组件本机调用的跟踪与研究下,我们将

COM

UAC

ITaskService

进行了巧妙的结合,从而成功地找到了一个新的UAC Bypass,或者说一个新的攻击面。
现在,不妨继续拓宽思路。回顾第一篇,我们在研究的开始确认了计划任务程序的本质为以

XML

为数据载体的

RPC

接口。按照微软的说法,

RPC

用于“跨进程间调用,不论进程是否在同一台主机上”。
所以,基于

RPC

协议的计划任务天生可用来进行横向移动。
当然,这并不是什么新技术,作为没在八月初猝死的那一批,我们已经再次狠狠地把玩了一番

atexec

schtasks

甚至更古老的

at.exe

。这些技巧无一例外利用了计划任务组件RPC接口进行横向移动。在已知的利用方式中,我们可以通过在远程执行命令,写入文件,最终通过共享目录进行读取的方式完成回显;或是通过诸多无文件手段直接上线。

而在实战中,这些或多或少会遇到一些问题。例如文件回显的技巧可能面临共享无法访问、SMB协议不兼容等诸多非常规环境;除了环境限制的因素之外,对抗环境下更多时候还要面临“已知”带来的威胁:一个已知的攻击方式或手法,一定有对应的检测。

这也就进一步导致了一个很实际的问题:

工具也好,武器也好,平台也罢,无论在理论环境下运行的多么完美,实战环境下总可能“不那么好用”。

探究新方法永远是对抗的第一课题。现在,基于实战环境下的需要,我们为自己找了一个新课题:如何实现更为稳定的横移回显/环境探测?

0x01 思考

安全研究绝不是盲目解决问题。在这里,我们的最终目的是探索一个(某些环境下)相对更好的横向移动技术,技术问题往往能够很容易的分解为多个递进的步骤,所以可以继续细化一些:

横向移动存在哪些阶段?每个阶段中分别涉及哪些技术?每个技术细节存在哪些优劣?

顺着这样的思路来思考,就会带出下面的技术细节:

横向移动需要连接到目标,在网络层面则表现为协议,那么第一个子问题就是:

采用什么协议?

协议承载服务,非漏洞的横向移动本质上是服务功能的

滥用

,所以可以分解出第二个子问题:我们能够使用服务本身提供的哪些功能,来获取执行权限?

成功获取执行权限后,实战环境下往往需要一个结果反馈,我们得到第三个子问题:服务本身是否可以直接返回结果?如果不支持,那么需要额外采用哪些手段?

最后,则是实战环境经久不衰的老问题:上述方式实现是否存在已知的特征?

将上述阶段串联起来,就是我们期望进行的完整流程。这个思路可以用

反序列化链/ROP

做对比,我们把整个步骤视作

Chain

,每一步中任意实现均视作独立且可连接的

Gadget

,对抗点视作

黑名单

,结合已知的知识,很容易得到类似这样一个简单且不完善的表格:
协议服务执行返回对抗点
SMBATSVC命令文件共享cmd /c重定向、文件落地
SMBSRVSVC服务文件共享cmd /c重定向、文件落地
RPC/DCOMWMI命令/服务文件共享/注册表cmd /c重定向、SMB依赖、流量UUID

看,威胁情报和安全研究串起来了,Web和对抗也有了联系。

考虑到我们正在研究计划任务,那么随之思考:计划任务能否做到这一点?根据我们前两篇文章的研究结果,不难回答这一问题:

1.

MS-TSCH

基于

RPC

,无法关闭且多数情况下允许访问。2.

ExecAction

提供无限制的命令执行,写入文件与注册表后,

ComHandlerAction

提供无限制的代码执行。3.协议内部通过

UTF-16

编码,将

完整的

XML定义以

原样

传输至客户端。其中

Description

元素可

无限制

放置任何

字符串

内容。

4.流量层面仅能够通过

UUID

捕获握手包,直接报警/阻拦可能影响服务器管理;主机层面进程链全部为

白名单

ExecAction

不支持输出重定向所以需要

无文件

手段;

ComHandlerAction

需要无文件手段或其他方式

写入文件

注册表

所以我们的表格可以添加下面并列的两项:

协议服务执行返回对抗点
RPCTSCH命令原生协议流量UUID、无文件攻击检测
RPCTSCH命令原生协议流量UUID、文件注册表落地
考虑复杂度,基于无文件的

ExecAction

显然优于需要大量落地的

ComHandlerAction

所以,我们的问题从

横向移动

顺理成章地转换为

无文件攻击对抗

而这项至少十年的技术利用方式非常成熟,变换手段非常多样化,也就意味着我们拥有很多顺畅的实现方式。在当前场景下,我们需要利用无文件攻击执行命令或进行信息探测,并在随后修改计划任务信息作为返回。

显然,各种基于脚本形式的无文件攻击都能做到这一点,例如

mshta

、各种形式的

sct

xslt

cmd

、以及

PowerShell

首先排除

cmd

;其次,考虑到前几种基于Windows脚本宿主(

Windows Script Hosting

)的技术需要对外发起http或smb请求,而文件落地又容易引起某些不必要的问题。所以,通过命令行实现完整脚本功能的

PowerShell

成为首选。

0x02 实现

确认了技术要点,实现起来就完全没难度了。

首先,我们参考前两章的内容,无论是照抄

MSDN

示例、自己编译

IDL

、使用

C# Interop

等等均可直接实现连接至远程目标,要做的无非是在使用RPC时指定正确的

Binding

,并调用

RpcBindingSetAuthInfoEx

_SEC_WINNT_AUTH_IDENTITY identity = { 0 };LPWSTR domain = L"ROOT";LPWSTR username = L"administrator";LPWSTR password = L"P@ssw0rd";identity.Domain = (unsigned short*)domain;identity.DomainLength = lstrlenW(domain);identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;identity.User = (unsigned short*)username;identity.UserLength = lstrlenW(username);identity.Password = (unsigned short*)password;identity.PasswordLength = lstrlenW(password);RpcBindingSetAuthInfoExW(hBinding, 0, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, &identity, 0, (RPC_SECURITY_QOS*)&qos);
或是在调用

ITaskService::Connect

时指定凭据:
pService->Connect(_variant_t(L"Target"), _variant_t(L"administrator"),_variant_t(L"ROOT"), _variant_t("P@ssw0rd"));

(体会到

抽象

透明

的好处了么)

其次,PowerShell提供了针对计划任务的完整对象模型,并提供了

Get-ScheduledTask

Set-ScheduledTask

等一系列

Cmdlet

进行操作。我们甚至不需要参考msdn,仅根据本地的cmdlet帮助文档就可以写出类似这样的脚本:
$task=Get-ScheduledTask -TaskName TestTask -TaskPath \;$task.Description=(iex $task.Description|out-string);Set-ScheduledTask $task;
在这段脚本中,我们通过

Get-ScheduledTask

获取到远程操控的对象,通过

iex

执行

Description

中保存的命令,考虑到PowerShell一切返回均为对象,所以采用

out-string

将结果转换为可读的字符串,最后进行保存。
Gadget思想的一个重点在于:如果gadget没错,将gadget串联的逻辑也没错,那么最终的结果一定是正确的。所以接下来,我们只需要创建一个计划任务,将

XML

/Task/RegistrationInfo/Description

元素内容设置为要执行的命令,将名称设置为

TestTask

,将命令行指定为上面的PowerShell命令,运行这个计划任务,

Description

将变为命令结果。

最后只要读取XML的内容,匹配出

Description

内容即可。

var xd=new XmlDocument();xd.LoadXml(task.Xml);Console.WriteLine(xd.SelectSingleNode("/*[local-name()='Task']/*[local-name()='RegistrationInfo']/*[local-name()='Description']").InnerText);

0x03 打磨

通过上面思考至落地的过程,我们有了一个可执行、有效果的技术原型,接下来进行打磨,使之更贴近实战“武器”的状态。

首先,我们利用

ExecAction

创建计划任务,这意味着需要使用命令行传参,所以最好使用

-EncodedCommand

。这实际上和

opsec

无关,主要目的是为了处理转义可能带来的一系列问题。
在对抗层面,我们知道PowerShell处理参数的逻辑是

根据前缀

执行

不区分大小写

的匹配,所以实际上

-EncodedCommand

除了常见的

-e

-enc

,还有类似以下几万种写法:
-eN-eNCo-Encode....
计划任务在后台运行,所以最好加上

-NonInteractive

,同样的,这个参数也有以下几万种写法:
-nonInt-nOnInTe....

对付一些没有词法分析的常规防御手段,这些基本上足够了。

接下来,由于我们在进行横向移动,所以并不能确定命令在目标环境的执行时间,所以需要加一个轮询。

轮询的退出条件绝不能

睿智地

直接判断是否修改了Description,这实际上也不是不能用,但在

脚本出错

的情况下等于死循环。

IRegisteredTask

对象提供了表示当前任务状态的

State

属性,任务运行结束后将由

Running

变为

Ready

,所以只要轮询读取任务状态即可。

while (task.State != TaskState.Ready){ task = folder.GetTask(taskname); Thread.Sleep(1000);}

接着是一些锦上添花的可选

opsec

手段,因为命令内容中并没有常见的(我特指

下载执行

这个被很多规则视作Powershell

唯一

滥用方式的)强特征,所以几乎不用处理。
同样的,没什么杀软会扫任务计划的

Description

属性(无论

对象

内存

还是

Xml

),所以默认不进行处理也是足够的。
当然,这些都是后续,等到这个方法被捕获了部分

“强特征”

,到时候处理一下

iex

,对

返回

命令

进行编码就会变为新的对抗点等待挖掘。
最后,不要忘记

iex

实际上执行的是PowerShell脚本,所以,这是一个

远程PowerShell

(回忆一下

WinRM

),也就意味着我们不光可以执行

命令行程序

也可以执行任意

Cmdlet

甚至于更为复杂的

脚本

也即意味着,一切

.Net

能做到的事情,我们都能在

远程(Remotly)

无文件(fileless)

无感知(undetectable)

地进行操作。再进一步修改我们甚至能够做到真正基于

MS-TSCH

实现的

交互式(Interactive)

远程PowerShell。

(为什么上面说可能脚本出错?这里就是了)

0x04 反思

至此,和计划任务相关的内容基本结束了。接下来我们跳出计划任务角度,站在应用场景的角度来回顾曾经我们可用的方案。一方面做个简单的总结,另一方面,想一想如何合理的进行使用。

在横向移动这个场景下,除了漏洞与计划任务之外,最为经典好用的技术要数

PsExec

WMI

这两种。
为什么PsExec经久不衰?除了微软签名带来曾经的opsec之外,还有着通过域环境下默认必须开启的

SMB

协议,实现了单协议的横移与回显结合的特点,所以在相当长的时间用作内网渗透的首选。哪怕是现在,基于

Impacket

或是

API

的自修改版PsExec依然能起到不俗的作用。
为什么后续换成

WmiExec

?因为WMI服务同样默认开启,且基本上不存在关闭的可能,通过

stdregprov

依然可以达到同协议回显的目的,从而变为基于

DCOM

协议横移的首选。
现在,我们多了

基于RPC的taskexec

这个技术选择。是的,这仅仅是一个技术补充,而非替代品。

为什么?

因为每一种攻击技术,必定有着不同的

应用范围/环境要求

,同时必定存在各种各样的

强特征

所有声称无感的(

undetectable

)绕过(

bypass

)/逃逸(

evasion

)方式,只是没有捕获强特征罢了

强特征

意味着被检测、被追溯的可能。但没有哪家产品敢于声称100%检测

某一技术与其变种

。也没有哪家产品能够做到100%无需

人为

判断/处置。而且检测和追溯需要

。更何况验证自动化的结果进行处置同样需要

。在我们从

钓鱼的

变成

钓鱼佬

之前,几乎不可能见到这个场景下可以替代人工的AI大规模商用。
所以,每一个备选项在实战中,都是通向成功的一个Gadget。更深入一些,在最初0x01列出的

mshta

sct

ComHandler

等等未选择的实现方式同样也是备选项,都是在实现

基于任务计划的横向移动

这一目的的过程中可用的Gadget。甚至于将这些备选项重新组合,还能得到另外一大堆很好用的

chain

而本文所述内容,则是在

对抗-内网渗透-域-RPC

这个更大的行为链条中的一个更大的gadget。

0x05 总结

这是本系列第三篇,我们从应用场景入手,随后进行可行性分析,接下来根据分析的内容进行原型实验,最后结合实战经验,打磨出一个全新的横向移动工具。

与人斗,其乐无穷。安全研究实质上是人与人之间的博弈,从纯粹技术的角度看来,每一个

精通

掌握

的技术点都应当能够变为我们的

Gadget储备

,并结合我们长期积累的

经验

,在过程中

动态地

创造一条合理的

Chain

,最终在实战中发扬光大。

实战应用应当是知识的有机组合,不存在一劳永逸绝对成功的技巧,但知识的积累与理解能让我们更加轻松。

当然,如果你就是喜欢无脑12345,那权当我什么都没说

文章中的代码可以在https://github.com/zcgonvh/TaskSchedulerMisc/找到,这次是一个没什么坑的原型,可以直接用,但最好自行修改一些特征防止撞车。

还是那句话,希望这篇文章能在技术点之外为各位带来启发。

阅读原文

跳转微信打开