揭秘DCShadow

Hi DC,they told me I could be anything I wanted. So i wanna became a domain controller. Yours faithfully, DCShadow. 😛

一、概述

DCShadow是由Benjamin Delpy和Vincent Le Toux两位安全研究员在2018年BlueHat大会上公布的一项关于Windows域的安全研究成果,该攻击并非利用Windows域控存在的漏洞,而是利用Windows域控制器提供的服务和机制进行的。从渗透测试的阶段上来看其并不属于漏洞攻击阶段,更多的是在攻击者已经获得域管权限之后维持权限的后渗透阶段。DCShadow攻击目前已经集成在mimikatz工具中。

DCShadow提出至今已有将近半年时间之久,国外对DCShadow较为详细的研究主要是alsid发布的文章《DCShadow explained: A technical deep dive into the latest AD attack technique》,该文章描述详细,对于DCShadow的原理和背后依赖的机制组件的理解有帮助。目前国内对DCShadow研究的公开文章较少,本文尝试从网络协议和源码的角度解析DCShadow的攻击过程及其背后的原理,旨在抛砖引玉,一方面是最近个人对DCShadow研究的一些总结,另一方面也是希望更多对内网安全有兴趣的小伙伴可以一起交流,如有错误,欢迎指正。

一句话对DCShadow的概括:攻击者将一台域内机器提升为域控角色,利用域控之间的数据同步推送,向活动目录数据库中注入恶意数据对象。

二、初探DCShadow

mimikatz作为一款Windows内网渗透利器,最初只是法国人Benjamin Delpy研究C语言和Windows安全机制的一个实验性工具。发展至今日,mimikatz已经成为一个强大的工具。最初源于其抓取Windows内存中的明文密码与哈希,随后,越来越多的功能加入到mimikatz中,如利用mimikatz进行哈希传递、票据传递、Kerberos黄金票据、查询域控数据库等。不得不说,mimikatz的作者对Windows背后复杂的安全机制和域环境有着深刻的认识和了解,尤其是最新加入的DCShadow,利用域环境中的数据同步,实现了一套精妙的攻击方法。

如前所述,DCShadow是攻击者拿下最高管理员权限后,在内网中维持权限的攻击手段,因此其攻击的前提条件是获得域管理员权限(另一个有趣的研究是nishang的作者发表的一篇博客文章《DCShadow – Minimal permissions, Active Directory Deception, Shadowception and more》,尝试在没有域管权限的条件下使用DCShadow,其前提也是先通过域管为某个普通用户分配一定的操作权限)。下面让我们先看看DCShadow攻击的一个过程。

测试环境
  • 主机名WIN-TTJ8SI6H6J1,操作系统Windows 2008 R2,IP地址10.0.83.13,是cody.com域内的域控制器
  • 主机名TESTWIN7-PC,操作系统Windows 7,IP地址10.0.83.16,加入cody.com域,启动mimikatz
测试账号
  • 用户名为fortest

新建一个域用户账户fortest作为测试目标,在活动目录用户和计算机管理面板中可以查看用户的属性配置,本次攻击利用mimikatz的DCShadow修改活动目录(AD)数据库中fortest用户的url属性。

打开mimikatz,启动mimidrv服务,获取SYSTEM权限。

mimikatz #  !+
mimikatz #  !processtoken
图片名称
图2.1

修改fortest用户的url属性值为test.dcshadow.com,该命令对fortest对象进行修改操作,并在本地启动RPC服务,等待push指令触发推送,如图2.2。

mimikatz #  lsadump::dcshadow /object:fortest /attribute:url /value:test.dcshadow.com
图片名称
图2.2

新开一个mimikatz窗口,执行push,触发域控间数据同步过程

mimikatz #  lsadump::dcshadow /push
图片名称
图2.3

如图2.3所示,对fortest对象属性的修改已经被提交同步,查看fortest用户的属性,可见url已被修改为test.dcshadow.com,如图2.4:

图片名称
图2.4

至此,DCShadow攻击成功修改活动目录数据库中的对象属性,既然活动目录数据库可被修改,那么在实际攻击场景中,攻击者可以做的事情就很多了,常见的如修改primaryGroupId属性、sidHistory属性等,具体的攻击方法在本文中不深入讨论,感兴趣的可以自己研究研究。

从上述攻击过程可见,由push指令触发的攻击过程分为三个步骤:

  • 注册(registration):将一台域成员主机提升为域控角色;
  • 推送(push):触发推送需要插入的恶意数据对象;
  • 注销(unregistration):还原主机角色,清除痕迹。

后文参照这三个步骤展开,在此之前,需要熟悉下相关的基础知识和概念。

三、背景知识

Windows域控制器

DCShadow是针对域控的攻击,要了解DCShadow,自然需要先对域控有一定的认识。Windows域控制器,是指添加了活动目录服务(角色)的Windows服务器,Windows域控通过以活动目录数据库的形式组织和存储一个域内相关的数据对象信息,这些数据包括域基础信息、域用户、域成员主机、服务或组件、策略配置等,域内提供的服务都围绕该活动目录数据库进行,通过活动目录,域控制器得以对域内的一切对象进行集中式管理。除了活动目录,域控制器还提供其他的一些服务,如为域内用户和主机提供身份认证、名称解析等服务。

1.活动目录

活动目录(Active Directory)是一个存储了不同数据对象的LDAP数据库,活动目录包含3个目录分区(Directory partitions,又称Name Context,简称NC),分别是域(domain)、配置(configuration)、架构(schema)。

除了活动目录,一个域控制器还需要提供以下的组件:

  • 身份认证:加入域的域成员机器进行登陆时,域控制器提供了登陆认证机制,如通过Kerberos、NTLM认证等。
  • 配置管理系统:提供用于统一管理域对象的配置策略,称为组策略对象(Group Policy Object,简称GPO),管理的对象包括域用户账户、域成员主机、服务等(包括其中的安全策略),通过LDAP和SMB协议进行管理和实现。
  • 域名解析(可选):为域内的主机提供DNS名称解析服务,帮助域内主机正确定位所需资源和服务的位置。

2.目录数据同步/复制(Drectory Replication Service,DRS)

Directory Replication Service是为了实现多个域控制器间活动目录数据库Name Context的数据一致性问题的一个服务。活动目录数据同步主要由一个叫Knowledge Consistency Checker(KCC)的组件来完成实际的工作,每当到达指定的数据同步间隔时间(默认15分钟)时,KCC将根据当前的网络环境计算出自身与其他域控之间的生成树拓扑并最终得到数据同步所需的连接拓扑关系,即,KCC主要用于获得每一个NC的数据同步来源。KCC支持的RPC调用包括IDL_DRSUpdateRefs,IDL_DRSReplicaAdd,IDL_DRSReplicaDel,IDL_DRSReplicaModify,IDL_DRSExecuteKCC。

实际上,DCShadow利用的是活动目录数据同步滥用问题。有关DRS和KCC的更多信息可以参考微软的文档[MS-DRSR][MS-ADTS]

协议交互

DCShadow攻击过程中,涉及到两种类型的协议交互,主要是操作活动目录数据库的LDAP协议和进行远程过程调用的DCERPC协议。

1.LDAP

LDAP(Lightweight Directory Access Protocol)是轻型目录访问协议,Windows的活动目录实际上就是基于LDAP的目录服务器,因此活动目录可以通过LDAP协议来进行访问。Windows活动目录的LDAP端口是TCP 389,可以通过一些客户端工具或编程语言的LDAP类库连接活动目录进行操作。LDAP协议交互并不复杂,此处就不深入展开。

图片名称
图3.1

2.DCERPC

RPC是一种编程模型,主要用于应用程序实现远程过程调用,微软的DCEPRC即是对远程过程调用的一种实现和扩展,实际上Windows上的很多服务以RPC的形式对外提供调用接口,外部应用程序可以通过调用这些PRC接口来实现对特定服务的访问。DCERPC有多种不同的承载方式,如TCP、UDP、HTTP、SMB命名管道等,客户端通过不同的承载协议连接到指定的服务端,由UUID绑定(Bind)到需要使用的终端接口(endpoint/interface)上,再传递所需参数来调用接口上指定的方法(operation),服务端随后将执行结果封装到协议数据包中返回。当使用TCP作为承载协议时DCERPC的知名端口号为135。

在RPC中,不同的终端定义了各自的一系列操作方法以供被调用,这些终端由各自唯一的UUID作为标识,在DCERPC的Bind操作中指定UUID,以告诉服务端使用哪个终端接口,如图3.2所示,TCP三次握手连接建立(56510端口和49157端口之间)之后,DCERPC的绑定操作中通过指定UUID为367ABB81-9844-35F1-AD32-98F038001003,该UUID对应的终端是SVCCTL(ServiceControl,与服务管理相关的调用)。

图片名称
图3.2

绑定操作完成后,将对选用的终端接口执行指定方法调用,调用方法通过opnum指定,如图3.3,调用SVCCTL中编号为15的方法,即OpenSCManagerW(调用参数已经过编码加密)。

图片名称
图3.3
EMP(Endpoint Mapper)

EPM也是DCERPC上的一个终端,对应的UUID为E1AF8308-5D1F-11C9-91A4-08002B14A0FA,其特殊之处在于EPM提供了对知名服务的查询映射、管理等功能。EPM接口中opnum为3的方法(ept_map)即提供了对某个RPC服务所在位置的查询功能。

图3.4实际上是发生在上一小节中,56510端口和49157端口建立连接(图3.2)并绑定SVCCTL(图3.3)之前发生的网络行为(由包序号排序),客户端首先连接服务端的135端口(43~45),并请求绑定到EPM(46、47),随后通过EPM的Map操作(Opnum为3)查询SVCCTL所在地址信息(48),从服务端EPM回复的响应中得知SVCCTL位于10.0.80.80的49157端口(49),于是,才有了后面客户端对49157端口发起连接请求的后续操作(图3.2/3.3中50~56)。

图片名称
图3.4

四、如何成为域控

nTDSDSA对象

一台普通的域内主机,攻击者如何在拿到域管权限之后,将其快速提升为域控角色呢。在Windows域环境中,域控制器与普通主机的区别体现在活动目录数据库中,在活动目录数据库中通过一些特殊对象以及一定的数据对象层级关系来标识某台机器是域控制器。在微软的[MS-ADTS]文档中,描述了标识域控的一些特殊数据对象:

图片名称
图4.1

其中,最关键的是nTDSDSA对象,该对象正是标识一台主机是域控角色的特殊对象,其位于活动目录数据库的configuration NC中,如[MS-ADTS]中的表述:

An object of class nTDSDSA that is always located in the configuration naming context (config NC). This object represents a domain controller (DC) in the forest.

同时,nTDSDSA对象需要位于正确的位置,根据文档其父对象应该是一个server对象,该server对象应位于serversContainer容器内,该容器中的每一个server对象即表示域内的每一台域控(server对象的名称就是对应的主机名)。其完整的DN为“CN=NTDS Settings,CN=XXXX-ServerName,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com”

除此之外,server对象有一个serverReference属性,该属性用于关联活动目录数据库中的一个计算机对象。

当前我们的域环境内只有一台合法域控,通过LDAP数据库查询我们可以观察到其对应的nTDSDSA对象:

图片名称
图4.2

值得注意的是,据[MS-ADTS]介绍,server对象可以通过LDAP的add操作进行插入,nTDSDSA对象却无法通过LDAP操作进行添加。后面对DCShadow攻击过程网络协议的分析和源码分析可以清楚的看到这一点。

Kerberos SPN

SPN,即Service Principal Name,用于Kerberos认证,每一个启用Kerberos认证的服务都拥有一个SPN,客户端通过Kerberos请求使用某种服务时,会在请求中附带上需要访问的服务的SPN名称,如文件共享服务cifs/DNS_DOMAIN_NAME,目录访问服务ldap/DNS_DOMAIN_NAME。如下访问域控的LDAP服务。

图片名称
图4.3

KDC(密钥分发中心)将通过SPN来确定客户端请求访问的是主机上的哪个具体服务,因为一个主机上通常情况下同时提供多种支持Kerberos认证的服务,随后,KDC将使用该服务账号的密码哈希来对票据进行加密。Kerberos也是一个复杂而有趣的协议,想要了解更多关于Kerberos和SPN的信息可以自己查阅相关资料,这里我们只要记住,Kerberos是Windows域环境中提供的一种身份认证机制,使用Kerberos的过程中需要提供正确的SPN名称。

我们通过LDAP查询来看看当前域控所注册的SPN,如图4.4所示,servicePrincipalName是计算机对象的一个属性,值为多个,可在注册或注销时添加和删除。

图片名称
图4.4

一个主机作为域控角色,使用DRS服务与域内其他域控进行数据同步,也需要使用正确的SPN名称,关于DRS服务需要使用的SPN,见[MS-ADTS]中的描述

图片名称
图4.5

简而言之,在域控间进行数据同步时,有两种可能存在的情况:

  • 连接域内指定的域控,这种情况下,SPN形式为<DRS interface GUID>/<DSA GUID>/<DNS domain name>,DRS interface GUID是一个固定的数值,为E3514235-4B06-11D1-AB04-00C04FC2DCD2,DSA GUID是nTDSDSA对象的objectGUID属性值,由于nTDSDSA对象无法直接通过LDAP操作插入,而DSA GUID(objectGUID属性值)依赖于nTDSDSA对象,因此该SPN同样不能直接通过LDAP进行插入。
  • 连接域林中的GC服务器,GC服务器(Global Catalog Server)是全局编录服务器,可以理解为一种服务或角色,用于存储本域所有对象信息和林中其他域部分对象信息,这种情况下,SPN形式为GC/<DNS hostname>/<DNS forest name>,可以直接通过LDAP操作为属性插入新值。

通过LDAP查询我们可以观察到当前域控注册的SPN中,包含有这两个特殊的SPN名称。

图片名称
图4.6

因此,DCShadow伪装的域控想要与其他域控进行数据同步复制,就需要提供以上两种情况的SPN名称。

drsuapi方法

上一节中讲到,Windows上很多服务以DCERPC的形式对外提供调用接口,DRS服务需要域控间的相互交互,其交互方式正是通过DCERPC方法调用的形式实现的。DRSRP(Direcotry Replication Service Remote Protocol)正是用于实现这一交互过程的协议,其工作在DCERPC协议上层,该协议包含了两部分RPC接口,其中之一是drsuapi,对应的UUID为E3514235-4B06-11D1-AB04-00C04FC2DCD2。该接口定义的方法主要用于操作域控间的数据同步,该接口以前缀“IDL_DRS”为开头命名方法。使用drsuapi调用前同样需要遵循前面对DCERPC介绍中先按照UUID进行Bind操作,再进行方法调用。

DCShadow欲实现域控间的数据同步,自然需要在本地对外提供drsuapi接口的RPC调用服务,对此,DCShadow实现了满足数据同步所需要的几个drsuapi接口方法,目前mimikatz中包含以下五个方法的实现:SRV_IDL_DRSBind、SRV_IDL_DRSUnbind、SRV_IDL_DRSGetNCChanges、SRV_IDL_DRSVerifyNames、SRV_IDL_DRSUpdateRefs。

图片名称
图4.7 kull_m_rpc_ms-drsr.h中定义的对外drsuapi接口方法函数原型(被真实域控调用)
图片名称
图4.8 数据同步时mimikatz需要调用的真实域控上的drsuapi接口方法

mimikatz通过push指令触发数据同步推送后,mimikatz所在伪域控和真实域控之间的drsuapi接口交互主要涉及以下方法(调用方为客户端,被调用方为服务端)

  • IDL_DRSBind/IDL_DRSUnbind:drsuapi接口方法调用需要先进行Bind操作。
  • IDL_DRSAddEntry:添加/修改一个或多个数据对象,该方法的一个关键作用是,可以为server对象添加nTDSDSA对象,前面讲到nTDSDSA对象无法通过LDAP操作添加,此处,mimikatz通过对IDL_DRSAddEntry方法的调用来实现插入nTDSDSA对象,使该台主机成为域控角色。
  • IDL_DRSReplicaAdd:为指定的NC添加数据同步引用源(respFrom变量),客户端调用该方法,通知服务端当前有数据需要进行同步,应立即根据respFrom变量的值发起数据同步复制,该方法的调用实际上就是push指令触发注入恶意数据对象背后的操作。
  • IDL_DRSGetNCChanges:服务端在接收到客户端调用IDL_DRSReplicaAdd方法后,开始数据同步过程,根据respFrom变量指定的数据同步源,服务端向其发起连接并调用其IDL_DRSGetNCChanges方法,需要同步的数据将被封装在调用请求的响应中返回。
  • IDL_DRSReplicaDel:与Add相反,移除数据同步引用源。

五、实现DCShadow

回顾前面提到的,DCShadow攻击过程分为三个步骤:注册、推送、注销,现在,我们可以来看看,DCShadow的背后到底发生了什么。

本文分析使用的mimikatz源码版本为mimikatz-2.1.1-20180527。实现DCShadow功能的入口函数位于mimikatz/modules/lsadump/kuhl_m_lsadump_dc.c中的kuhl_m_lsadump_dcshadow()。

图片名称
图5.1

1.注册

首先需要将普通域成员主机提升为域控角色,先从网络协议行为上浏览一下这个过程

图片名称
图5.2

上图5.2中wireshark展示的网络行为(66~99)正是DCShadow进行域控注册的整个过程,包括LDAP交互和DCERPC上的drsuapi接口调用交互,将其拆分来看。

LDAP操作目录数据库(72~76)

addRequest,请求向活动目录数据库中添加一个新数据对象节点,同时写入三个属性,object属性为server(这是一个server对象,位于serverContainer容器中),serverReference属性的值指向了DN为CN=TESTWIN7-PC,CN=Computer,DC=cody,DC=com的计算机对象。该操作完成后,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com节点应该加入了CN=TESTWIN7-PC这个新数据对象,即CN=TESTWIN7-PC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com

图片名称
图5.3

modifyRequest,请求修改活动目录数据库中的数据对象,此处修改CN=TESTWIN7-PC,CN=Computers,DC=cody,DC=com对象的servicePrincipalName属性,为该属性添加的一个新值为GC/TESTWIN7-PC.cody.com/cody.com。

图片名称
图5.4

前面章节的介绍中曾经说过,标识域控角色的特殊数据对象是nTDSDSA对象,LDAP的addRequest操作只是在serverContatiner容器下插入了新的server对象,还没有为其添加nTDSDSA对象,另外,DRS所依赖的两个SPN名称也只添加了其一(GC),这些未完成的操作将由接下来的DCERPC交互完成。

DRSUAPI调用DsAddEntry(94~97)

进行drsuapi接口调用前是DCERPC需要完成的一些交互,包括连接135端口(77~79)、通过EPM接口查询DRSUAPI所在位置(80~83)、连接到DRSUAPI接口所在的49157端口(84~86)、Bind接口操作(87~93),随后,mimikatz调用域控drsuapi接口的DsAddEntry方法,这个操作将为CN=TESTWIN7-PC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com对象加入nTDSDSA对象,并根据nTDSDSA对象的objectGUID属性构建出第二个SPN名称。

图片名称
图5.5

至此,域控注册完成,此时,TESTWIN7-PC这台主机已经被我们提升为域控。

让我们从代码上看一下这个过程,注册通过函数kuhl_m_lsadump_dcshadow_register()实现。

图片名称
图5.6

注册实现函数中有两个关键函数调用,kuhl_m_lsadump_dcshadow_register_ldap()完成插入server对象和添加GC的SPN名称,kuhl_m_lsadump_dcshadow_register_NTDSA()则通过drsuapi接口的AddEntry方法插入nTDSDSA对象。

图片名称
图5.7

在操作完成之后,mimikatz还进行了两次LDAP的searchRequest(100~103),目的是确认server对象和nTDSDSA对象已经正确添加。如图5.8所示。

图片名称
图5.8

红色框出部分表示以CN=TESTWIN7-PC为基本DN进行查找,过滤器为(name=NTDS Settings),还原该LDAP查询语句如下:

/***Searching...
ldap_search_s(ld, "CN=TESTWIN7-PC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com", 1, "(name=NTDS Settings)", attrList, 0, &msg)
Getting 1 entries:
Dn: CN=NTDS Settings,CN=TESTWIN7-PC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=cody,DC=com
    canonicalName: cody.com/Configuration/Sites/Default-First-Site-Name/Servers/TESTWIN7-PC/NTDS Settings;
    name: NTDS Settings;
    objectClass (3): top; applicationSettings; nTDSDSA;

查询成功找到该对象,说明已经是域控角色。

2.推送

现在,我们的主机已经是一台域控了,下一步,将把恶意数据对象利用DRS数据同步注入到活动目录数据库中。

图片名称
图5.9

图5.9中wireshark展示的网络行为(104~145),是mimikatz键入push指令后触发的推送数据同步,重点关注以下两个过程。

DRSUAPI_REPLICA_ADD

mimikatz键入push指令,我们的伪域控将向真实域控发起drsuapi接口IDL_DRSReplicaAdd方法的调用,KCC默认15分钟进行域控间活动目录数据库同步,调用该方法实际上等于手动触发了数据同步,告知真实域控有需要立即进行同步的数据。

DsGetNCChanges

真实域控收到REPLICA_ADD方法的调用请求后,开始进行数据同步,向我们mimikatz所在的伪域控发起DCERPC调用,调用的是DsGetNCChanges方法,该方法调用实际上就是数据同步的过程,请求需要进行同步的数据,而我们的伪域控将会把恶意对象数据作为响应内容推送给真实域控。

我们来看一下实现数据推送的函数kuhl_m_lsadump_dcshadow_push()。

图片名称
图5.10

推送操作完成后,通过LDAP查看活动目录数据库,可以发现,我们恶意数据对象已经成功插入。

3.注销

现在,我们的攻击已经完成了,最后的收尾工作就是把前面做的操作给复原,把伪域控恢复为普通域成员主机,经过前面的详述,想必这个过程就很简单了。

图片名称
图5.11

mimikatz通过LDAP删除前面添加的对象,包括server对象、nTDSDSA对象、SPN属性中的GC,至此,域控的角色被删除。

kuhl_m_lsadump_dcshadow_unregister()函数完成卸载域控角色。

图片名称
图5.12

使用mimikatz进行DCShadow攻击时,push指令会一次性完成注册、推送和注销,以完成注入恶意数据对象的目的,在这个过程中我们看不到mimikatz所在主机被提升为域控角色,为了更好的分析这几个步骤和当中的一些详细过程,我对代码做了一些修改,加入了一些提示信息中断,重新编译代码,使得每个步骤进行时的状态可以被捕捉到。在完成第一步域控注册后,可以通过LDAP观察到我们的主机被提升为域控时活动目录数据库发生的一些变化,如下图所示:

图片名称
图5.13

六、总结

通过上面的讲述,mimikatz实现的DCShadow巧妙的滥用了域控间的DRS数据同步机制这样一个合法的过程,使得攻击者可以修改活动目录数据库中的对象,下面的流程图总结了DCShadow攻击的整个过程。

图片名称
图6.1

以上是对DCShadow学习研究过程中的一些总结和见解,可以看到mimikatz实现的DCShadow通过简单的几个命令就可以完成这样的一次攻击,实际上这需要对其背后的原理和机制有相当深入的理解和认识,才能恰到好处的对其进行实现和利用,对于研究学习的我们来说,这个过程不仅仅是学习使用这样一种攻击手段,在挖掘和理解其背后原理的过程中也让我们学习了作者的一种思路。

作者:斗象能力中心TCC-Cody

BTW,TCC team长期招聘,包含各细分领域安全研究员、机器学习、数据分析、大数据等职位。感兴趣不妨发简历联系我们。Email: alex.xu@tophant.com。

评论(1)

哈哈

2018/06/25 13:27
学习了

发表评论