# .user.ini文件构成的PHP后门

Author: 乌云历史资料库 (@wooyun_archive)
Published: 2014-10-30T02:51:00Z
Canonical: https://wepostx.com/topics/607

> 乌云历史资料归档
>
> **原始作者：** phith0n
> **原始编号：** superkieran-wooyundrops:377
> **原始发布时间：** 2014-10-30 10:51
> **声明：内容仅用于技术研究和个人使用，版权归 wooyun.org。**

---

## 0x00 背景

这个估计很多同学看了不屑，认为是烂大街的东西了：
[.htaccess文件构成的PHP后门](http://zone.wooyun.org/content/16114)
那么我来个新的吧：.user.ini。它比.htaccess用的更广，不管是nginx/apache/IIS，只要是以fastcgi运行的php都可以用这个方法。我的nginx服务器全部是fpm/fastcgi，我的IIS php5.3以上的全部用的fastcgi/cgi，我win下的apache上也用的fcgi，可谓很广，不像.htaccess有局限性。

## 0x01 .user.ini

那么什么是.user.ini？
这得从php.ini说起了。php.ini是php默认的配置文件，其中包括了很多php的配置，这些配置中，又分为几种：PHP_INI_SYSTEM、PHP_INI_PERDIR、PHP_INI_ALL、PHP_INI_USER。 在此可以查看：[http://php.net/manual/zh/ini.list.php](http://php.net/manual/zh/ini.list.php) 这几种模式有什么区别？看看官方的解释：

![原文图片](/media/2016/06/8927316ad68429614787df522c0257e6)

其中就提到了，模式为PHP_INI_USER的配置项，可以在ini_set()函数中设置、注册表中设置，再就是.user.ini中设置。 这里就提到了.user.ini，那么这是个什么配置文件？那么官方文档在[这里](http://php.net/manual/zh/configuration.file.per-user.php)又解释了：
除了主 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配置项中有两个比较有意思的项（下图第一、四个）：

![原文图片](/media/2016/06/abcb947c8282d0342f6132a499166209)

auto_append_file、auto_prepend_file，点开看看什么意思：

![原文图片](/media/2016/06/9df5e03866b6550d7dc06318a30a8d49)

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

```text
auto_prepend_file=01.gif
```
01.gif是要包含的文件。
所以，我们可以借助.user.ini轻松让所有php文件都“自动”包含某个文件，而这个文件可以是一个正常php文件，也可以是一个包含一句话的webshell。
测试一下，我分别在IIS6.0+Fastcgi+PHP5.3和nginx+fpm+php5.3上测试。 目录下有.user.ini，和包含webshell的01.gif，和正常php文件echo.php：

![原文图片](/media/2016/06/2e2e3655e16ceb6d405e9d06776c361f)

![原文图片](/media/2016/06/0528ef4c45e7a2fda720b07e3cfa3ac4)

访问echo.php即可看到后门：

![原文图片](/media/2016/06/f5183424ebc6eeb70a3335845df6c167)

Nginx下同样：

![原文图片](/media/2016/06/11f242849007a6728689596151e8a1a1)

![原文图片](/media/2016/06/5702c2cacb6d0142eaa9764cb09b6f3d)

那么，我们可以猥琐地想一下，在哪些情况下可以用到这个姿势？ 比如，某网站限制不允许上传.php文件，你便可以上传一个.user.ini，再上传一个图片马，包含起来进行getshell。不过前提是含有.user.ini的文件夹下需要有正常的php文件，否则也不能包含了。 再比如，你只是想隐藏个后门，这个方式是最方便的。

## 0x02 参考文献：

- [http://php.net/manual/zh/ini.list.php](http://php.net/manual/zh/ini.list.php)

- [http://php.net/manual/zh/configuration.changes.modes.php](http://php.net/manual/zh/configuration.changes.modes.php)

- [http://php.net/manual/zh/configuration.file.per-user.php](http://php.net/manual/zh/configuration.file.per-user.php)

- [http://php.net/manual/zh/configuration.changes.php](http://php.net/manual/zh/configuration.changes.php)

## Replies
