这次打的是 HTB 的 Cap(Easy / Linux)。实际链路包括 Dashboard 数据编号、抓包中的明文 FTP 认证、FTP/SSH 凭据复用,以及错误授予 Python 的 cap_setuid。

本文按实际发现顺序整理。Flag 与口令用占位符表示;

目标靶机信息

项目内容
平台Hack The Box
靶机Cap
难度Easy
系统Ubuntu 20.04.2 LTS
实战日期2026-11-03(北京时间)
完成情况已取得 user flag 与 root flag,并获得交互式 root shell

HTB Cap 实例与初始目标 IP

靶机重启后 IP 会改变。初始扫描使用 10.129.161.149;中间因为扫描原因reset了靶机,后续实际验证时使用 10.129.161.160。

路径概览

已验证的关键节点

01 · Dashboard 数据编号

枚举 /data/<id>,发现少数编号返回数据页,其余编号重定向回首页。

02 · PCAP 中的 FTP 明文认证

下载较大的抓包,在 Wireshark 中发现 FTP 控制流与成功认证记录。

03 · FTP 与 SSH 凭据复用

实际登录 FTP 取得 user flag,再验证同一凭据可登录 SSH。

04 · Python capability 提权

发现 python3.8 具有 cap_setuid;验证 UID 可切换为 0 后获得 root shell。

信息收集:扫描结果为什么不能直接下结论

最初对 10.129.161.149 使用了:

1
nmap -p- --min-rate 5000 -T4 -oN nmap_10.129.161.149.txt 10.129.161.149

当次输出只显示 80/tcp,其余端口大多为 filtered。但扫描期间浏览器和 Nmap 都曾暂时失去目标可达性,停止后约一两分钟才恢复。因此这次只证明“高频探测时仅收到 80 的响应”,不能证明 21、22 等端口不存在。

高频全端口扫描仅显示 80/tcp

后续在 Dashboard 网络连接表中可以看到:

  • 0.0.0.0:80 处于 LISTEN;
  • 0.0.0.0:22 和 :::22 处于 LISTEN,22 是 SSH 候选服务;
  • :::21 处于 LISTEN,后续以实际 FTP 登录验证该服务可用;
  • 127.0.0.53:53 仅绑定在 loopback,是本地 DNS stub;
  • 10.129.161.160:37680 -> 8.8.8.8:53 是出站连接使用的临时源端口,37680 不是监听服务端口。

Dashboard 中的活动网络连接与监听端口

LISTEN 才是服务端监听的证据;SYN_SENT、ESTABLISHED 等只是连接状态。高频扫描造成的丢包或临时不可达,也可能造成端口漏报。

Dashboard 数据编号与抓包下载

Dashboard 中存在 /data/1 一类路径。数字位于 path segment,而非 Query 参数;它可能是资源编号,但单凭 URL 不能直接断定是 IDOR。

对相邻编号做有限枚举后,0、1、2、3 返回 200,页面大小约为 17 KB;其余多数编号返回 302 并重定向至 /。这说明编号会影响所选数据记录,但尚不足以证明不同记录归属于不同用户。

对 /data/ 编号的有限枚举:0–3 返回 200,其余多为 302

其中 data/0 显示 72 个数据包,而 data/1 只有 2 个数据包。页面提供下载入口,因此优先检查包数较多的捕获文件。

data/1 页面显示 2 个数据包及下载入口

PCAP 分析:FTP 明文凭据

在 Wireshark 的 Statistics -> Protocol Hierarchy 中发现 FTP 控制协议。查看同一 TCP stream 的请求与响应后,认证过程如下:

1
2
3
USER nathan
PASS <redacted>
230 Login successful.

230 Login successful 是关键证据:它说明抓包中出现用户名与明文口令,也说明这组凭据在捕获时对 FTP 服务认证成功。

Wireshark 中的 FTP 认证流程与 230 成功响应

后续出现的 SYST、PORT、LIST、TYPE I、RETR notes.txt 都是 FTP 协议命令,而不是服务器上的任意系统命令执行。RETR notes.txt 返回 550 Failed to open file,表示该次下载失败。

验证凭据复用并取得 user flag

以抓包中的 nathan 凭据登录 FTP 后,服务端返回 230 Login successful,ls 显示可读取的 user.txt。FTP 客户端不是 Linux shell,因此使用 get user.txt 下载,再在本机 shell 中读取。

FTP 登录、下载 user.txt 并在本机读取 user flag

随后验证同一凭据可登录 22 端口 SSH,得到:

1
uid=1001(nathan) gid=1001(nathan) groups=1001(nathan)

FTP 抓包中的 230 只证明该口令当时可用于 FTP;实际 SSH 登录成功后,才能证明存在 SSH 凭据复用。

本地枚举与 Linux capabilities 提权

进入 SSH 后先进行只读枚举:

1
2
3
4
id
sudo -l
getcap -r / 2>/dev/null
find / -xdev -type f -perm -4000 -ls 2>/dev/null

nathan 没有 sudo 权限;常规 SUID 列表中没有立即验证的路径。真正异常的是:

1
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip

getcap 结果:python3.8 具有 cap_setuid

cap_net_bind_service 通常只允许进程绑定低端口;关键是 cap_setuid。它不是把 root 身份永久赋给 nathan,而是让带该 capability 的 Python 进程可调用 setuid(0) 修改自身 UID。+eip 中的 e 表示该能力可进入执行进程的有效集合。

初始本地枚举摘录
1
2
3
4
uid=1001(nathan) gid=1001(nathan) groups=1001(nathan)
Sorry, user nathan may not run sudo on cap.
Linux cap 5.4.0-80-generic x86_64
Ubuntu 20.04.2 LTS (Focal Fossa)

先用一个不启动 shell 的最小测试验证 capability 是否实际生效:

1
/usr/bin/python3.8 -c 'import os; os.setuid(0); print(f"uid={os.getuid()} euid={os.geteuid()}")'

输出:

1
uid=0 euid=0

确认后,在同一 Python 进程中切换 UID 并启动 Bash:

1
/usr/bin/python3.8 -c 'import os; os.setuid(0); os.execv("/bin/bash", ["bash", "-p"])'

进入 root shell 后读取 root flag。

Python capability 验证、root shell 与 root flag

两个 Flag 均已取得。 初始访问来自可枚举的数据记录与 PCAP 凭据泄露;最终 root shell 来自错误授予 Python 的 cap_setuid。

总结与复盘

观察能证明什么不能直接证明什么
高频扫描只显示 80当时仅收到 80 的响应21、22 不存在
/data/0–/data/3 返回 200编号会影响所选数据记录已确认跨用户越权
FTP 中有 USER / PASS 与 230明文凭据泄露,且捕获时 FTP 认证成功该密码必然能用于 SSH
python3.8 带 cap_setuidPython 进程可能修改 UID当前环境一定能切换至 UID 0
uid=0 euid=0capability 在此环境中实际生效自动获得 root 的所有组身份或持久化权限

这台靶机最需要记住的不是命令本身,而是把“线索”和“已验证结论”分开:端口监听需要实际验证,捕获到的口令需要验证目标服务,file capability 也需要最小化测试后才能确认影响。

后续复盘的关键知识点

  1. 扫描可靠性与控制变量:--min-rate 5000 -T4 让目标出现暂时不可达时,不能把 filtered 当作“端口不存在”。复盘时应能说明:为什么降低速率、缩小端口范围、固定同一实例 IP,才有助于区分扫描漏报、服务异常和网络路径问题。

  2. 可枚举资源不等于已证实 IDOR:/data/<id> 返回不同内容,证明的是编号参与资源选择。要证明 IDOR/BOLA,还需要补足资源归属、当前身份以及服务端是否做对象级授权检查等证据。

  3. PCAP 的分析顺序:先从 Protocol Hierarchy、Conversations 找出应用层会话,再查看完整 TCP stream。FTP 控制连接中的 USER、PASS、230 分别说明什么,LIST、RETR 又为什么只是 FTP 操作而不是系统命令执行,应能独立解释。

  4. 凭据泄露与凭据复用是两次验证:抓到明文密码只证明它曾在某个协议中出现;230 证明 FTP 认证成功;只有实际 SSH 登录成功,才能证明该密码复用于 SSH。三个结论不能合并成一句“抓包拿到 SSH 密码”。

  5. SUID 与 file capabilities 的差别:SUID root 程序启动时会获得有效 UID 0;cap_setuid 则让进程能够调用改变 UID 的系统调用。本次还通过 uid=0 euid=0 验证了 capability 在实际执行环境中生效,而不是仅凭 getcap 输出下结论。

  6. 最小化验证与权限边界:先验证 UID/EUID 是否变为 0,再启动交互 shell,能把“配置异常”“能力生效”“获得 root shell”拆成独立证据。即使有效 UID 为 0,也应区分它与永久修改用户、获得所有附加组或持久化权限之间的差别。