打开题目是一个上传页面
随便上传一个php文件,发现报错

于是随意改变文件后缀,仍然报错,但报错内容不一样了,判断这是黑名单过滤后缀

html字符转义:

发现报错信息里提到的是文件内容的<?进行了过滤,但也说明了他是用黑名单过滤文件后缀的
因为对<?进行了过滤,所以要绕过可以将php标记格式改为脚本标记格式:

1
<script language=php> phpinfo(); </script>

但是上传后发现又报错

不过其中的信息有些敏感exif_imagetype,判断可能是用了exif_imagetype()函数对文件格式进行了检查

1
exif_imagetype() 读取一个图像的第一个字节并检查其签名

可以在内容的开头直接加上图片的标识头:GIF、JFIF..

成功上传,不过没有办法直接利用
于是就想到了.htaccess但是这个方法局限性太大,反正是不成功….(查了之后才知道这是nginx不是apache,难怪…)

后来看大佬的writeup学习了…

.user.ini

这得从php.ini说起了。php.ini是php默认的配置文件,其中包括了很多php的配置,这些配置中,又分为几种:PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER。

其中就提到了,模式为PHP_INI_USER的配置项,可以在ini_set()函数中设置、注册表中设置,再就是.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_prepend_file 表示在php程序加载第一个php代码前加载的php文件
auto_append_file 是在php代码执行完毕后加载的文件

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

再上传一个1.jpg文件

由于同一目录下还有index.php文件,所以我们可以访问他来执行1.jpg的内容

成功

所以再上传文件’cat /flag’即可