Advanced Windows Task Scheduler Playbook-Part.3 Lateral Movement

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

原创 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/找到,这次是一个没什么坑的原型,可以直接用,但最好自行修改一些特征防止撞车。

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

阅读原文

跳转微信打开

本文转载自微信公众号「头像哥老草」,查看原文。版权归原作者所有,如有侵权请联系删除。