一、前言
在10月份的DerbyCon 2018期间,我的小伙伴们(@tifkin_、@enigma0x3以及@harmj0y)发表了题为“The Unintended Risks of Trusting Active Directory”的精彩演讲,在演讲中他们演示了攻击者如何强制域控制器(DC)向配置了无约束委派(unconstrained delegation)的服务器发起身份认证请求,捕获并导出域控的TGT(Ticket-Granting Ticket,票据授予票据),以便模拟DC,执行DCSync之类的攻击来请求任意域用户密码。在演讲中,小伙伴们通过带有多个子域的森林环境来演示这种攻击场景。然而,最近Will拓展了攻击场景,如果目标环境中存在多个外围森林,并且配置了双向信任(two-way trust)选项,Will依然能够成功搞定其他域的DC。我强烈建议大家先阅读一下Will的这篇文章(Not A Security Boundary: Breaking Forest Trusts),文中从攻击方视角介绍了具体攻击过程,也介绍了如何在实际环境中部署特定配置,以缓解此类攻击。
在本文中,我会简单介绍Will在文章中提到的攻击技术,主要关注的是主机账户强制认证过程中所生成的安全事件。我也会提供一些IOC(indicators of compromise),这些特征来自于Rubeus所生成的Windows安全事件,可以用来监控TGT以及SpoolSample的执行(SpoolSample是Lee Christensen开发的一款工具,是现在唯一公开的、能够向无约束服务器发起身份认证的poc代码)。SpoolSample代码中用到了Printer Server,现在Windows系统中有仍有上百个类似的RPC服务器尚未进行分析。因此,我们不能假设攻击者总会使用RPC Printer Server来执行此类攻击。此外我们还需要理解一点,这类攻击并不会凭空出现,为了完成攻击任务,在攻击之前、之中以及之后都会涉及到其他事件以及操作。
二、攻击简介
Will在文中从攻击方角度详细介绍了攻击过程。作为防御方,我们需要理解攻击者执行的每个步骤,识别潜在的数据来源,以便收集足够多的信息来检测此类攻击活动。Will在文中引用了一句话:“如果攻击者入侵了森林中的某台域控(或者森林中配置无约束委派的任何服务器),那么他就可以通过“打印机bug”来强制外部森林中的域控向攻击者控制的服务器发起身份认证。在各种委派设置的影响下,攻击者可以在已控制的服务器上导出、重新应用并使用外部域控的TGT,最终获取外部森林的凭证数据”。
三、攻击中涉及的概念
在开始模拟此类攻击并介绍如何检测攻击行为之前,我们需要理解攻击者的具体操作及背后原因。在本节中,我会引用其他一些参考文章,帮助大家更好理解攻击过程。关于Will文章中介绍的攻击方法,我能想到如下几个要点:
委派
简单而言,当服务器连接到其他网络资源时,可以利用委派(delegation)机制来模拟客户端。根据微软官方文档的描述,微软将委派定义为一种操作,用来授予服务器相关权限,允许服务器以客户端的身份来与环境中其他远程系统交互。服务器以客户端身份与其他服务器交互是非常常见的一种场景。
Kerberos委派类型
Kerberos有3种委派类型,如下表所示:
Kerberos无约束委派
根据微软官方文档描述,当用户通过另一个服务(带有无约束委派的前端服务器)请求访问某个服务(后端服务器)时,会经过如下几个步骤:
1、用户将KRB_AS_REQ
消息发送至KDC(Key Distribution Centre,密钥分发中心)进行身份认证,请求消息会通过AS(Authentication Service,认证服务)交换,请求可转发的TGT;
2、KDC通过KRB_AS_REP
消息返回可转发的TGT,响应消息通过AS交换;
3、用户根据步骤2种可转发的TGT,通过KRB_TGS_REQ
消息请求forwarded TGT;
4、KDC通过KRB_TGS_REP
消息向用户返回forwarded TGT;
5、用户使用步骤2返回的TGT,通过KRB_TGS_REQ
消息请求Service 1对应的服务票据(service ticket);
6、TGS(Ticket Granting Service,票据授予服务)通过KRB_TGS_REP
消息返回服务票据;
7、用户向Service 1发送KRB_AP_REQ
消息,展示服务票据、forwarded TGT以及forwarded TGT对应的会话密钥(session key);
8、为了满足用户的请求,Service 1需要Service 2以用户身份执行某些操作。Service 1使用用户提供的forwarded TGT,通过KRB_TGS_REQ
消息将这个票据发送给KDC,以用户的身份请求Service 2的票据。
配置了无约束委派的服务器不仅可以使用forwarded TGT来访问网络中其他未请求的服务,如果这是域控TGT,那么也能执行类似DCSync之类的攻击。大家可以阅读这篇文章了解详细信息。大家都知道滥用无约束委派并不是一个新的概念。然而,此时非常有趣也非常糟糕的是攻击者可以在双向信任的外围域林中使用这种技术。此时域林信任再也不是一个安全屏障了。
大家也可以在Will的“Another Word on Delegation”这篇文章中了解委派方面更多信息。
域林信任
微软在官方文档中将信任定义成域之间的一种关系,可以让某个域的用户通过另一个域域控的身份认证。Will也在“A Guide to Attacking Domain Trusts”这篇文章中介绍了关于域和森林信任的其他信息。
有两种信任类型:
默认信任
当新域添加到根域中时,默认情况下会创建双向传递信任关系。
其他信任
在本文中,为了解释Will在文章定义的攻击方法,我们主要从防御方角度来分析域林双向信任关系。这一点非常重要,因为涉及两个森林的攻击活动可能会生成一些Windows安全事件,帮我们梳理蛛丝马迹。
打印机bug
Lee认为打印机bug是MS-RPRN(Windows Print System Remote Protocol,Windows打印系统远程协议)中一个古老但又默认启用的方法,具备域用户账户权限的攻击者可以使用MS-RPRN的RpcRemoteFindFirstPrinterChangeNotification(Ex)
方法来强迫运行Spooler
服务的任何主机通过Kerberos或者NTLM向攻击者选择的目标发起身份认证请求。
MS-RPRN打印系统远程协议
根据微软文档描述,这是基于RPC(Remote Procedure Call)的一种协议,支持客户端和服务器之间的同步打印和联机操作,包括打印任务控制以及打印系统管理。此外,打印系统远程协议只使用了基于命名管道的RPC。因此,源和目标服务器会通过445端口建立网络连接。
RpcRemoteFindFirstPrinterChangeNotification(Ex) 功能
该方法可以创建远程修改通知对象,用来监控对打印机对象的修改,向打印客户端发送修改通知。大家可以在这篇文章的“Notification of Print System Changes”例子中找到该方法的使用示例。
Lee在POC中只用到了前2个方法(RpcOpenPrinter
以及RpcRemoteFindFirstPrinterChangeNotificationEx
),并且当Notification
方法返回非零的Windows错误代码后就停止执行。“打印机bug”只需要目标(打印机服务器)和客户端(无约束服务器)之间建立初始连接即可。当调用RpcOpenPrinter
方法时,该方法需要返回ERROR_SUCCESS
才能跳转到Notification
方法,而后者会返回特定的非零错误值。Lee在POC中监控如下两个ERROR返回值,能为我们提供一些信息:
ERROR_ACCESS_DENIED
:“目标服务器尝试进行身份认证并且被拒绝访问。如果将身份认证强制切换到NTLM挑战-响应捕获工具(如responder/inveigh/MSF SMB捕捉工具等),这正是预期结果,表明强制身份认证已经成功”。ERROR_INVALID_HANDLE
:“尝试执行打印机通知操作,收到无效句柄。表明强制身份认证很可能已经成功”。希望以上内容能帮大家在尝试攻击前理解一些背景知识,也能帮我们了解潜在的数据来源,检测Will所演示的这种新型攻击技术。
四、模拟攻击场景
环境需求
需要设置双向认证的两个域林。
被入侵的域林:
hydrogen.covertius.local
)。在演示案例中,攻击者入侵了根域的域控制器(DC),利用该DC攻击另一个域林中的另一个DC。目标域林:
rikers.cyberpartners.local
),因为我们需要该DC的TGT,然后利用配置了无约束委派的DC发起DCSync攻击。工具:
日志:
攻击流程
Will在文章中介绍了整体攻击流程图。我非常喜欢这张图,因为其中每个步骤都有详细的说明。
在配置无约束委派服务器上的操作
在高权限的命令提示符(cmd.exe
)中运行如下命令,请替换实际所使用的服务器名称:
Rubeus.exe monitor /interval:5 /filteruser:VICTIM-DC-NAME$
在另一个命令提示符中(不需要高权限)执行如下命令:
SpoolSample.exe VICTIM-DC-NAME UNCONSTRAINED-SERVER-DC-NAME
如果第1个Rubeus窗口中没有输出任何内容,我们可能需要再次执行第2个步骤。在测试时我没有看到任何输出,所以我运行了SpoolSample两次。
Rubeus应该能捕捉到来自目标DC的认证请求,导出其TGT数据。
数据源
相关安全事件
攻击者使用hydrogen.covertius.local
中的localadmin
账户来运行Rubeus
,开始监控来自于rikers$
账户的4624登录事件。
攻击者使用hydrogen.covertius.local
中的localadmin
账户来运行SpoolSample
POC,设置目标服务器为rikers.cyberpartners.local
,凭据捕捉服务器为hydrogen.covertius.local
。换句话说,hydrogen
会强迫rikers
向其发起身份认证请求。
hydrogen.covertius.local
中的localadmin
账户会使用CYBERPARTNERS.LOCAL
SPN来请求Kerberos服务票据,以便连接到其他域林。由于SpoolSample
没有使用服务器的IP地址,而是使用了服务器的DNS名称,因此会发生Kerberos认证过程。
Hydrogen.covertius.local
通过ldap协议查询rikers.cyberpartners.local
的DC。
Hydrogen.covertius.local
通过88端口(Kerberos)与rikers.cyberpartners.local
建立通信连接,以便请求访问rikers.cyberpartners.local
的服务票据。
Rikers.cyberpartners.local
收到来自hydrogen.covertius.local
的Kerberos服务票据请求,SPN为rikers$
。
localadmin
账户请求Kerberos服务票据,SPN为krbtgt
,票据选项为0x60810010
。
Hydrogen.covertius.local
开始使用MS-RPRN RpcOpenPrinter
方法,通过SMB 445端口(出站)与rikers.cyberpartners.local
通信,以便从“打印机服务器”(即rikers
)处获取打印机句柄。
Rikers.cyberpartners.local
收到来自hydrogen.covertius.local
的账户认证成功事件,账户为localadmin
。
localadmin
使用covertius
域名访问rikers.cyberpartners.local
的IPC$
共享命名管道,以便绑定到spoolss
服务。
rikers.cyberpartners.local
使用COVERTIUS.LOCAL
SPN请求Kerberos服务票据,以便连回攻击者已控制的域林,以及向配置了无约束委派的服务器(hydrogen.covertius.local
)发起身份认证。之所以会发生Kerberos认证,是因为SpoolSample
使用的是服务器的DNS名称,而非IP地址。
Rikers.cyberpartners.local
查询hydrogen.covertius.local
的DC。
Rikers.cyberpartners.local
通过88端口(Kerberos)与hydrogen.covertius.local
DC建立连接。
Hydrogen.covertius.local
收到来自rikers$
的Kerberos服务票据请求,SPN为hydrogen$
。
在打印机bug的驱使下,rikers.cyberpartners.local
通过445端口回连hydrogen.covertius.local
。
当riker$
向hydrogen.covertius.local
发起身份认证请求时就会出现SID过滤,这是因为riker$
是其他域DC,默认情况下是企业域控制器组的一部分(企业域控制器SID为S-1-5-9
)。大家可以阅读微软官方文档了解更多信息。
localadmin
账户请求Kerberos服务票据,SPN为krbtgt
,票据选项为0x60810010
。由于委派的存在,我们可以看到localadmin
貌似来自于10.7.30.100
这个地址(rikers
服务器)。
hydrogen.covertius.local
收到来自rikers.cyberpartners.local
的身份认证成功事件,账户名为rikers$
。这证实了rikers$
已被强制向配置了无约束委派的服务器发起身份认证请求。
由于委派的存在,localadmin
也会成功登录到hydrogen
DC,但源IP地址为rikers
的IP地址。
赋予新的登录各种权限:
rikers.cyberpartners.local
访问hydrogen.covertius.local
共享命名管道IPC$
,以便绑定到客户端的spoolss
服务。需要指出的是,访问IPC$
的是来自于COVERTIUS
的localadmin
账户,而非rikers$
。
一旦Rubeus
捕捉到从rikers$
到Hydrogen
的4624登录事件,就会提取rikers$
的TGT。该工具首先连接至LSA服务器,验证调用方的确是logon应用。如果第一个步骤失败,则可能表明运行rubeus
的用户不具备足够的权限来获取LSA的句柄。如下所示:
一旦操作失败,Rubeus
会使用自己的GetSystem
函数,通过令牌模拟方法将本地管理员账户提升到SYSTEM权限。然后再次尝试,这次该工具可以获取LSA的句柄,枚举Kerberos票据。
作为LSA句柄的一部分,Rubeus
会将logon应用名注册为User32LogonProcesss
(末尾带有3个“SSS”)。微软文档中在介绍LsaRegisterLogonProcess
函数的LogonProcessName
参数时所使用的标准名称为User32LogonProcess
。
到目前为止不会再生成其他事件。后面攻击者可以使用已提取的TGT来执行其他操作。本文的主要目的是记录下Will提出的攻击过程中会生成哪些安全事件。
五、初步检测方法
Rubeus
1、在POC攻击场景中,攻击者运行的是磁盘上的Rubeus工具,因此我们可以根据命令行参数来构建基本的检测特征。需要注意的是,命令行参数值是攻击者可以操控的一个参数,这意味着攻击者可以修改命令参数,轻松绕过基于原始参数特诊的检测方法。
2、在记录相关事件日志时,我们发现Rubeus在枚举Kerberos票据时存在较为明显的特征。在获取LSA的句柄时,这个过程涉及到logon进程应用的名称。Rubeus会注册如下名称:User32LogonProcesss
(末尾为3个“S”)。这个信息会出现在4611安全事件中。此外,即便拼写正确,User32LogonProcess
也不是常见的logon应用名(如Winlogon
),因此我们可以监控此类特征。
3、检测Rubeus的另一种方法就是关注其更为常见的行为特征。当Rubeus尝试获取LSA的句柄时,如果所使用的账户不具备SeTcbPrivilege
权限集,那么该工具在调用LsaRegisterLogonProcess
特权服务时就会失败。我们可以检查审核失败事件以及4673安全事件中非系统用户对特权服务的调用操作。
无约束委派及双向认证域林
这种攻击方法会迫使域控制器通过双向域林信任向配置了无约束委派的、被攻击者入侵的服务器发起身份认证请求。因此,正如我们在前文看到的那样,无约束服务器上能看到SID过滤事件(4675安全事件),过滤匹配企业域控制器(S-1-5-9)的SID。我们可以执行如下检测步骤:
1、获取配置了无约束委派选项的服务器,提取每个服务器上的4675安全事件;
2、使用SID S-1-5-9过滤所得结果。我们可以提取到来自其他域林的DC的交互过程(可能是潜在受害者或者是正常行为);
3、我们也可以通过Tdo(trusted domain object)域SID来提取信息。通过这个信息我们可以知道通过双向信任进行交互的可信域SID,其中可能有已被攻击者控制的潜在无约束服务器。
我们还可以在配置了无约束委派的服务器上监控来自其他域林的域控制器DCNAME$
的成功的网络登录(类型3)事件。
SpoolSample
检测SpoolSample工具非常简单。我们可以监控5145安全事件,监控配置了无约束委派的服务器对IPC$
共享命名管道的访问行为,这些服务器需要借助这种方式,通过其他域的域控绑定到spoolss
服务。需要注意的是,除了SpoolSample
POC之外,还有其他RPC服务器可以用于强制认证。因此,这种检测方法只能覆盖本文提到的这种攻击。
六、总结
如果大家阅读了Will小伙伴的那篇文章,我希望本文能帮助大家进一步理解相关内容,也能帮助大家进一步了解这个攻击过程中会生成的大多数数据。本文只介绍了端点处的数据源信息,我会尽快更新本文内容,加入来自端点和网络的更多数据源。此外,我也会在其他文章中介绍攻击者对DC TGT的利用方式。
前面我们提到过,这类攻击技术并不会凭空出现。因此,由于实际环境中生成的类似事件有限,我们可能无法仅通过监控特定事件来捕捉这些攻击行为。然而,如果攻击者创建新的进程,将票据导入新登录的会话、或者执行DCSync攻击或者其他攻击时,我们就可以捕捉到这类攻击行为。
感谢Will耐心解答我在撰写本文时提到的各种问题,我会很快更新检测方法及新的攻击方式。
欢迎大家提出建议及意见。
七、参考资料
https://www.harmj0y.net/blog/redteaming/another-word-on-delegation/
https://msdn.microsoft.com/en-us/library/cc246071.aspx
https://www.harmj0y.net/blog/redteaming/a-guide-to-attacking-domain-trusts/
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc775736(v=ws.10)#trust-types-1
https://www.youtube.com/watch?v=-bcWZQCLk_4
https://www.slideshare.net/harmj0y/the-unintended-risks-of-trusting-active-directory
https://msdn.microsoft.com/en-us/library/cc237940.aspx
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc755321(v=ws.10)
https://blogs.technet.microsoft.com/networking/2009/04/28/rpc-to-go-v-3-named-pipes/
https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
https://docs.microsoft.com/en-us/windows/desktop/printdocs/findfirstprinterchangenotification
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc759073(v=ws.10)#forests-as-security-boundaries
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc755427(v=ws.10)
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn745899(v=ws.11)
https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/create-global-objects
https://msdn.microsoft.com/en-us/library/cc220234.aspx
https://adsecurity.org/?p=1667