SUCTF 2019 CheckIn 1题解


SUCTF 2019 CheckIn 1题解

前置知识

.htaccess常用payload

语句的作用是让Apache将1.png以php格式解析


SetHandler application/x-httpd-php

语句的作用是让Apache将其他类型文件均以php格式解析

SetHandler application/x-httpd-php

.user.ini

摘自ini文件后门

它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法。应用范围可谓很广,不像.htaccess有局限性。
什么是.user.ini?

这得从php.ini说起了。php.ini是php默认的配置文件,其中包括了很多php的配置,这些配置中,又分为几种:PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER。 在此可以查看:php.ini 配置选项列表这几种模式有什么区别?参考官方文档:配置可被设定范围

PHP_INI_USER     可在用户脚本(例如 ini_set())或 Windows 注册表以及 .user.ini 中设定
PHP_INI_PERDIR     可在 php.ini,.htaccess 或 httpd.conf 中设定
PHP_INI_SYSTEM     可在 php.ini 或 httpd.conf 中设定
PHP_INI_ALL     可在任何地方设定

其中就提到了,模式为PHP_INI_USER的配置项,可以在ini_set()函数中设置、注册表中设置,再就是.user.ini中设置。 这里就提到了.user.ini,那么这是个什么配置文件?那么官方文档.user.ini 文件解释了:
除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($ _ SERVER[‘DOCUMENT_ROOT’] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。
在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIR 和 PHP_INI_USER 模式的 INI 设置可被识别。
这里就很清楚了,.user.ini实际上就是一个可以由用户“自定义”的php.ini,我们能够自定义的设置是模式为“PHP_INI_PERDIR 、 PHP_INI_USER”的设置。(上面表格中没有提到的PHP_INI_PERDIR也可以在.user.ini中设置)
实际上,除了PHP_INI_SYSTEM以外的模式(包括PHP_INI_ALL)都是可以通过.user.ini来设置的。
而且,和php.ini不同的是,.user.ini是一个能被动态加载的ini文件。也就是说我修改了.user.ini后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl所设置的时间(默认为300秒),即可被重新加载。
然后我们看到php.ini中的配置项,可惜我沮丧地发现,只要稍微敏感的配置项,都是PHP_INI_SYSTEM模式的(甚至是php.ini only的),包括disable_functions、extension_dir、enable_dl等。 不过,我们可以很容易地借助.user.ini文件来构造一个“后门”。

Php配置项中有两个比较有意思的项(第一个和第四个):

auto_append_file     NULL     PHP_INI_PERDIR      
auto_detect_line_endings     "0"     PHP_INI_ALL      
auto_globals_jit     "1"     PHP_INI_PERDIR      
auto_prepend_file     NULL     PHP_INI_PERDIR      

点开auto_prepend_file

 auto_prepend_file string

    Specifies the name of a file that is automatically parsed before the main file. The file is included as if it was called with the require function, so include_path is used.

    The special value none disables auto-prepending.

指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而auto_append_file类似,只是在文件后面包含。 使用方法很简单,直接写在.user.ini中:

auto_prepend_file=01.gif

01.gif是要包含的文件。
所以,我们可以借助.user.ini轻松让所有php文件都“自动”包含某个文件,而这个文件可以是一个正常php文件,也可以是一个包含一句话的webshell。
那么,我们可以想一下,在哪些情况下可以用到这个姿势? 比如,某网站限制不允许上传.php文件,你便可以上传一个.user.ini,再上传一个图片马,包含起来进行getshell。不过前提是含有.user.ini的文件夹下需要有正常的php文件,否则也不能包含了。

exif_imagetype()

exif_imagetype() 读取一个图像的第一个字节并检查其签名。
我们可以通过给上传脚本加上相应的幻数头字节就可以绕过:

JPG :FF D8 FF E0 00 10 4A 46 49 46
GIF(相当于文本的GIF89a):47 49 46 38 39 61
PNG: 89 50 4E 47

题目详解

<?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!");
    }
    #正则判断文件名后缀不允许包含ph和htacess且无法通过大小写绕过
    $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));
}

首先制作一个.user.ini文件

GIF89a
auto_prepend_file=test.jpg

然后制作一个图片马,并命名为test.jpg

GIF89a

先上传1.user.ini文件,回显中包含index.php,确认做题方向正确,然后上传图片马,最后用蚁剑连接uploads/cc551ab005b2e60fbdc88de809b2c4b1/index.php
(QWQ复现半天没有成功,不知道是哪里出锅了,希望有大手子浇浇)

2.4更新:复现成功,名称就为.user.ini文件,前面不能再有东西了,呜呜呜

参考:
https://blog.csdn.net/weixin_44077544/article/details/102688564
https://wooyun.js.org/drops/user.ini文件构成的PHP后门.html


Author: kingkb
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source kingkb !