# check in

题目源码：

```php
<!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>php

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

审计代码，分别存在文件大小WAF、文件后缀名检查WAF、文件内容审计WAF以及图片类型判断WAF。

稍微总结一下绕过方式，文件大小WAF比较简单，类型判断只要加个文件头content-type就可以了。

后缀名检查过滤了php脚本以及.htacess文件。

文件内容审计进一步过滤了php以及一句话木马的可能性，但是我们可以通过图片码来进行绕过，例如这样：

```
<script language='php'><scirpt>
```

但是又需要上传.htacess文件来对图片码进行php解析。

这里利用到了.user.ini文件。

> 自 PHP 5.3.0 起，PHP 支持基于每个目录的 INI 文件配置。此类文件 *仅*被 CGI／FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果你的 PHP 以模块化运行在 Apache 里，则用 .htaccess 文件有同样效果。
>
> 除了主 php.ini 之外，PHP 还会在每个目录下扫描 INI 文件，从被执行的 PHP 文件所在目录开始一直上升到 web 根目录（[$\_SERVER\['DOCUMENT\_ROOT'\]](https://www.php.net/manual/zh/reserved.variables.server.php) 所指定的）。如果被执行的 PHP 文件在 web 根目录之外，则只扫描该目录。
>
> 在 .user.ini 风格的 INI 文件中只有具有 **`PHP_INI_PERDIR`** 和 **`PHP_INI_USER`** 模式的 INI 设置可被识别。
>
> 两个新的 INI 指令， [user\_ini.filename](https://www.php.net/manual/zh/ini.core.php#ini.user-ini.filename) 和 [user\_ini.cache\_ttl](https://www.php.net/manual/zh/ini.core.php#ini.user-ini.cache-ttl) 控制着用户 INI 文件的使用。
>
> [user\_ini.filename](https://www.php.net/manual/zh/ini.core.php#ini.user-ini.filename) 设定了 PHP 会在每个目录下搜寻的文件名；如果设定为空字符串则 PHP 不会搜寻。默认值是 `.user.ini`。
>
> [user\_ini.cache\_ttl](https://www.php.net/manual/zh/ini.core.php#ini.user-ini.cache-ttl) 控制着重新读取用户 INI 文件的间隔时间。默认是 300 秒（5 分钟）。

简单来讲，就是在目录下的INI文件会被PHP进行扫描，如果扫描到了则被用于配置该文件目录。

我们可以在INI文件中设置当访问该目录下的文件时，该文件包含图片马并进行解析，这样就可以利用图片马了。

注意利用条件：只有在 CGI/FastCGI SAPI 模式的服务器上才能使用 .user.ini。

在.user.ini文件中有两个设置**auto\_prepend\_file**和**auto\_append\_file**。

**auto\_prepend\_file**是在文件前插入文件；而**auto\_append\_file**在文件最后插入，类似于调用include进行文件包含。

有些时候，需要在文件前插入文件，以此来绕过死亡exit。

请注意，该利用方式需要文件目录下必须有一个可执行php文件，这样在该文件被访问时才会包含木马并被解析。这也提示我们，当文件上传目录下包含一个可执行php文件时，可以通过ini的方式进行利用。

上传.user.ini：

```
GIF89a
auto_prepend_file=shell.jpg
```

上传成功；接着上传图片马：

```
GIF89a
<script language='php'>system('cat /flag');</script>
```
