Soupedecode01
# Soupedecode 01 域控渗透 - 从零到 SYSTEM 的完整记录
复刻自 TryHackMe Soupedecode 01,单机域控练习,flag 在目标 C 盘根目录下。
目标:192.168.111.20 本机:192.168.111.25 VPN 已连接
0x00 前言
这是棉花糖复刻的 TryHackMe Soupedecode 01 域控渗透靶场,考点覆盖了从外网侦察到域内提权的完整链路。这篇文章记录了实际操作的全过程,包括每一步踩的坑和思路转折,希望能帮到同样在学 AD 渗透的朋友。
0x01 端口扫描与服务识别
先用 fscan 快速扫一遍常见端口:
1 | |
扫出 4 个端口:135、139、445、88。但 fscan 默认只扫常见端口,漏掉了域控的关键服务。用 PowerShell 写了个快速 TCP 探测,把域控典型端口全测了一遍:
1 | |
53(DNS)、88(Kerberos)、389/3268(LDAP)、445(SMB)、135(RPC)全在——这台机器是域控无疑,主机名 DC01。
0x02 FQDN 获取
渗透 AD 第一步要搞清楚域名。Windows AD 域有两套名字:
- NetBIOS 短名:SOUPEDECODE(fscan 扫出来的)
- FQDN 完整域名:需要主动获取
.local 不是默认后缀,不能猜。有两种方式拿到 FQDN:
方式一:匿名 LDAP 查 RootDSE
LDAP 服务器(389 端口)允许匿名绑定查询 RootDSE,里面有 defaultNamingContext 字段:
1 | |
把 DC= 去掉用点拼起来就是 FQDN:soupedecode.local,Kerberos realm 用 SOUPEDECODE.LOCAL。
小坑:用 ADSI(DirectoryEntry)匿名绑定时,它会偷偷用当前 Windows 登录身份去认证,反而连不上。换成 LdapConnection + 强制 Anonymous 才干净。
方式二:enum4linux-ng 通过 SMB 获取
enum4linux-ng 在 445 端口建立 SMB 会话后,会从 SMB 协议的协商响应里直接读到域信息,不需要任何凭据:
1 | |
输出里的关键字段:
1 | |
SMB 协议在会话协商阶段会交换机器的完整域名信息,enum4linux-ng 帮你把它解析出来了。两种方式的区别:LDAP 走 389 端口查目录元数据,SMB 走 445 端口从协议握手里读。哪条通就用哪条,实战中两个都试一遍最稳。
0x03 空会话与匿名枚举(全部失败)
SMB 空会话
1 | |
用 net use 测了空会话和 guest 空密码。结果:
- SYSVOL/NETLOGON:拒绝匿名
- backup 共享:能连不能读(Access Denied)
- 用
smbclient -L //192.168.111.20 -U 'guest%'列出共享,能看到 backup、NETLOGON、SYSVOL(Windows 下也可以用net view \\192.168.111.20)
匿名 LDAP
匿名绑定成功了,但只能读 RootDSE 元数据(域名、命名上下文),子树搜索用户列表被拒(An operation error occurred)。
AS-REP Roasting
用 impacket 原版 GetNPUsers.py 对已知用户做 AS-REP Roasting:
1 | |
结果:所有用户都启用了预认证(doesn't have UF_DONT_REQUIRE_PREAUTH set),没有可烤用户。
到这一步,所有”无凭据白嫖”的通道都试过了,全堵死。
0x04 突破口:guest + rpcclient + RID 爆破
这是整个渗透的转折点。
之前用 net use 测 guest 时,注意力全放在”能不能读共享、能不能调 enumdomusers”,都被拒就以为 guest 这条路死了。但其实 一个命令不行,不代表所有命令都不行。
关键区别在于:net use 只是建立通道,不会去管道里调 RPC 函数;而 rpcclient 会主动打开 \PIPE\lsarpc 命名管道调 LSA 接口。每个 RPC 接口有独立的权限检查,要逐个试探。
Windows 原生没有 rpcclient,在 WSL Kali 里装了 smbclient(含 rpcclient):
1 | |
进去后依次试三个命令:
1 | |
lsaquery 和 lookupsids 对 guest 放行了,enumdomusers 没有。这就是突破口——虽然不能批量列用户,但能逐个反查。
SID 与 RID 的关系
先搞清楚几个概念:
- SID(Security Identifier):Windows 里每个安全主体(用户、组、计算机)的唯一标识符,格式
S-1-5-21-<域标识>-<RID> - 域 SID:同一个域内所有主体共享的固定前缀,比如
S-1-5-21-875679470-3476450079-2794512899 - RID(Relative Identifier):SID 的最后一段数字,域内每个主体各不相同
举个例子:
1 | |
RID 的分配规则:
| RID | 含义 |
|---|---|
| 500 | Administrator(固定) |
| 501 | Guest(固定) |
| 502 | krbtgt(固定) |
| 512+ | 内置组 |
| 1000+ | 域内创建的用户、组、计算机 |
关键点:lookupsids 这个 RPC 调用能把任意 SID 反查成用户名,而且 guest 权限就够用。所以只要拿到域 SID,从 500 开始逐个拼 域SID-RID 去查,就能枚举出所有用户名——这就是 RID 爆破能成功的根本原因。
RID 爆破
拿到域 SID 后,从 RID 500 开始递增,逐个 lookupsids 反查用户名:
1 | |
爆出来的有效用户:
| RID | 用户名 | 类型 |
|---|---|---|
| 500 | Administrator | 用户 |
| 501 | Guest | 用户 |
| 502 | krbtgt | 用户 |
| 1139 | ybob317 | 用户 |
| 1140 | file_svc | 用户(服务账户) |
| 1141-1151 | FileServer$、WebServer$ 等 | 计算机账户 |
RID 分配规则:500-502 是固定内置账户,1000+ 是普通用户和组。WP 里用 crackmapexec 的
--rid-brute参数就是把这个循环自动化了。
0x05 密码喷洒
拿到用户列表后,用”用户名=密码”模式喷洒。ybob317:ybob317 命中(靶场常见套路,很多人把密码设成自己的用户名)。
这组凭据是域账户密码,不是某个协议的密码。AD 的精髓就是单点登录——一套凭据通吃 SMB、LDAP、Kerberos、RDP、WinRM 等多个协议。密码对了只是认证通过,能不能用还要看每个协议的授权层。
0x06 拿到第一份情报:backup 共享
用 ybob317 认证后重新枚举共享,比匿名时多了 ADMIN$、C$:
1 | |
backup 共享现在能读了(之前 guest 只能连不能读),里面有 backup_extract.txt:
1 | |
内容是所有机器账户的 NTLM 哈希和 Kerberos key:
1 | |
0x07 Pass-the-Hash 拿 SYSTEM
backup 文件里的是 NTLM 哈希,不是 Kerberos 票据。NTLM 哈希可以直接用(Pass-the-Hash),不用爆破——因为 Windows 认证只验哈希不验密码,有哈希等于有密码。
逐个测试机器哈希,FileServer$ 登录成功且有管理员权限(能访问 C$ 和 ADMIN$):
1 | |
用 psexec.py 拿交互式 shell:
1 | |
cmd 里
$不是特殊字符,直接写FileServer$,不要加反斜杠转义。
psexec 的原理:用 PTH 认证连上 ADMIN$ 共享 → 上传一个远程 shell 服务 → 通过 SCM 创建并启动服务 → 拿到 SYSTEM 权限的 cmd。
1 | |
flag 到手。
WP 的另一条路:Kerberoasting
Writeup 里走了另一条路拿凭据——Kerberoasting。和我们从 backup 文件直接拿 NTLM 哈希不同,WP 是用 ybob317 的凭据去烤 TGS 票据:
1 | |
输出拿到 file_svc 服务账户的 TGS 票据 hash:
1 | |
这个 hash 的原理:TGS 票据是用服务账户密码的 NTLM hash 加密的,拿到票据后可以离线爆破,爆破成功就得到服务账户的明文密码。
两种路线对比:
| 我们的路线 | WP 的路线 | |
|---|---|---|
| 哈希来源 | backup 共享里的 backup_extract.txt | Kerberoasting 烤出的 TGS 票据 |
| 哈希格式 | NTLM hash(aad3b...:3647bc...) |
Kerberos TGS($krb5tgs$23$*...) |
| 能否直接用 | 能,PTH 直接登录 | 不能,需要爆破 |
| 爆破 | 不需要 | 用 hashcat 爆破 TGS hash 得明文密码 |
| 最终手段 | PTH + psexec.py | 明文密码 + psexec.py |
核心区别:NTLM 哈希是钥匙,拿到直接用;TGS 票据是上锁的箱子,拿到要爆破。 我们运气好,backup 文件直接给了 NTLM 哈希,省去了爆破步骤。WP 没有 backup 这条路(或者没发现),只能走 Kerberoasting 爆破。
补充:如果 backup 文件里还有 AES256 key(
aes256-cts-hmac-sha1-96),那也是钥匙级别的——拿到可以直接 Pass-the-Key,不用爆破。TGS 票据之所以要爆破,是因为它不是 key 本身,而是用 key 加密后的密文。
0x08 完整攻击链
1 | |
0x09 关键概念总结
为什么”没有凭据但需要用户名”
一组凭据 = 用户名 + 密码。用户名是能”白嫖”的半组凭据(KDC 会泄露存在性),密码是要攻击的半组。先把便宜的半组搞到手,再攻贵的半组。
NTLM 哈希 vs Kerberos 票据
- NTLM 哈希 = 钥匙,拿到直接用(PTH)
- Kerberos 票据($krb5tgs$) = 上锁的箱子,拿到要爆破
- Kerberos key(AES256 等) = 钥匙,拿到直接用(Pass-the-Key)
每个端口背后的能力
| 端口 | 协议 | 能干什么 |
|---|---|---|
| 88 | Kerberos/KDC | 认证、发票、用户名枚举、AS-REP Roasting |
| 445/139 | SMB | 共享文件、承载 RPC 管道、空会话 |
| 389/636 | LDAP | 查域数据库(用户、组、密码策略) |
| 135 | RPC | 远程调用总机 |
| 53 | DNS | 名字解析 |
| 3389 | RDP | 远程桌面 |
一个命令不行不代表全不行
enumdomusers 被拒,但 lsaquery 和 lookupsids 没被拒。每个 RPC 接口有独立权限检查,要逐个试探。这是 RID 爆破能成功的根本原因。
0x0A 工具清单
| 工具 | 用途 | 运行环境 |
|---|---|---|
| fscan | 快速端口扫描 | Windows |
| kerbrute | Kerberos 用户名枚举 | Windows |
| GetNPUsers.py | AS-REP Roasting | Python (impacket) |
| rpcclient | SMB/RPC 枚举、RID 爆破 | WSL Kali (Samba) |
| smbclient | SMB 共享访问 | WSL Kali (Samba) |
| psexec.py | PTH 拿 shell | Python (impacket) |
0x0B 踩坑记录
- net use 删连接报 1219:删的时候要用完整共享路径
\backup,不能只写服务器根 - ADSI 匿名绑定失败:DirectoryEntry 会偷用当前身份,换 LdapConnection + Anonymous
- kerbrute Encoding_Error 不是 AS-REP:是解析 bug,要用 GetNPUsers.py 确认
- WSL 网络不通:要开
networkingMode=mirrored,重启 WSL 才生效 - psexec 报 ACCESS_DENIED:cmd 里
$不需要转义,直接写FileServer$ - cme v5.22 跑不了:依赖
imp模块,Python 3.12+ 删了,需要旧 Python
0x0C 远程 Shell 工具:各种 exec 的区别
拿到凭据或哈希后,需要远程执行命令拿 shell。impacket 自带了多种 exec,底层走的 Windows 远程执行机制各不相同,一个被堵就换另一个。
psexec.py — SMB + 服务控制管理器
原理:用凭据/哈希连上 ADMIN$ 共享 → 上传一个 exe → 通过 RPC 调 SCM 创建 Windows 服务指向该 exe → 启动服务 → 拿到半交互式 shell。退出时删文件、删服务。
特点:会落地文件、创建服务,痕迹明显但最稳定,拿到的是 SYSTEM 权限(服务以 LocalSystem 跑)。
1 | |
wmiexec.py — WMI over DCOM
原理:通过 DCOM 连上 WMI 服务 → 调用 Win32_Process.Create 执行命令 → 输出重定向到临时文件 → 再通过 SMB 读文件拿回显 → 读完删除。
特点:不上传二进制、不创建服务,隐蔽性好,体感最快(每条命令只走一轮 WMI 调用)。但不是真交互式 shell,每条命令单独执行。拿到的是登录账户的权限,不是 SYSTEM。-codec gbk 解决中文回显乱码。
1 | |
smbexec.py — SMB + 计划任务
原理:不上传 exe,把命令写进 bat 文件,通过 SMB 共享让目标执行,输出重定向到临时文件再读回来。
特点:介于 psexec 和 wmiexec 之间,隐蔽性比 psexec 好,但比 wmiexec 慢。
atexec.py — 任务计划服务(TSCH)
原理:通过 RPC 调 Task Scheduler 创建一次性计划任务执行命令,跑完任务自动删除。
特点:适合”只想跑一条命令拿结果”的场景,不留持久痕迹。
dcomexec.py — DCOM(ShellWindows)
原理:走 ShellWindows 或 ShellBrowserWindow 这两个 DCOM 对象的 Execute 方法,跟 wmiexec 原理接近但走的 COM 接口不同。
特点:当 WMI 被监控或禁用时能顶上,算 wmiexec 的隐蔽变种。
对比表
| 工具 | 底层通道 | 落地文件 | 权限 | 隐蔽性 | 典型场景 |
|---|---|---|---|---|---|
| psexec.py | SMB + SCM 服务 | 上传 exe 到 ADMIN$ | SYSTEM | 低 | 需要稳定 shell |
| wmiexec.py | WMI/DCOM | 不上传,只写临时输出文件 | 登录账户 | 高 | 快速隐蔽执行 |
| smbexec.py | SMB + 计划任务 | bat 文件 | 登录账户 | 中 | psexec 不通时替补 |
| atexec.py | TSCH(任务计划) | 无 | 登录账户 | 高 | 只跑一条命令 |
| dcomexec.py | DCOM ShellWindows | 不上传 | 登录账户 | 高 | WMI 被禁时替补 |
非 impacket 的 exec
| 工具 | 特点 |
|---|---|
| CrackMapExec / NetExec | --exec-method smbexec/atexec/wmiexec/mmcexec 参数切换,一个工具覆盖多种方法,批量执行神器 |
| Evil-WinRM | 走 WinRM(5985),需要目标开了 WinRM 且账户在 Remote Management Users 组,拿的是 PowerShell,功能最强 |
| Metasploit psexec_psh | 用 PowerShell 版的 psexec,不走传统 SMB exe,过一些 AV |
怎么选
实战决策顺序:先试 wmiexec(快、隐蔽)→ 不通就试 psexec(稳、拿 SYSTEM)→ 都不通就换 smbexec / atexec / dcomexec。想要 PowerShell 环境直接上 Evil-WinRM(前提 5985 开着)。批量打多台机器用 NetExec 一把梭。本质上这些工具的区别就是”用 Windows 的哪个远程执行机制”——服务管理器、WMI、计划任务、DCOM、WinRM,都是 Windows 自带的管理通道,各自需要的权限和留下的痕迹不同。
结语
这个靶场把 AD 渗透的侦察链串得很完整:从端口特征判定域控,到匿名通道逐个试探,到 RID 爆破突破用户名瓶颈,最后 PTH 拿 SYSTEM。最核心的一课是”一个命令不行不代表所有命令都不行”——SMB 空会话被拒不等于 RPC 接口全关,逐个试探才找到 lsaquery 和 lookupsides 这两个漏网的口子。
渗透测试本质就是个不断试错的过程,拿到新凭据后要回头重新走一遍之前的流程,经常会有新的发现。
flag: bd42e8070dd53effd2c93ae6c7e08685