文件包含漏洞学习
概述
什么是文件包含?
将需要重复调用的函数写入一个文件,对该文件进行包含时产生的操作。
漏洞产生原因
文件包含函数加载的参数没有经过过滤或严格定义,可以被用户控制,包含其他恶意文件,导致了执行非预期代码。
示例:
1 |
|
可以看出,改变URL中filename的值即可改变代码中包含的文件。
PHP中的文件包含函数
include
函数出现错误时,会抛出警告,但程序仍继续执行。include_once
同 include ,但仅包含一次(避免函数重定义,变量重新赋值等问题)。require
函数出现错误时,会直接报错并退出程序执行。require_once
同 require ,但仅包含一次。
类型
本地文件包含
被包含的文件在服务器本地
包含本地敏感文件
敏感文件默认路径列举(以下目录随系统版本不同而有差异):
windows系统:
C:\windows\win.ini //基本系统配置文件
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //iis配置文件
C:\windows\repair\same //存储windows系统初次安装密码
C:\ProgramFiles\mysql\my.ini //mysql配置信息
C:\ProgramFiles\mysql\data\mysql\user.MYD //mysql root密码
C:\windows\php.ini //php配置信息
linux/unix系统:
/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配置文件
包含上传文件
包含文件的内容只要符合php语法都能被当成php代码进行执行,无关后缀名是什么。
远程文件包含
被包含的文件在远程服务端
条件:php.ini中设置allow_url_fopen = On(默认)、allow_url_include = On ( php5.2后默认为off )
包含远程文件
包含远程shell
remoteshell.txt
1 |
|
包含构造好的文件后,会在当前目录下创建test.php,即写入一句话木马,可以对其进行利用,后续也可用菜刀进行连接
利用方式
利用PHP伪协议
何为伪协议?简单的说,就是自己定义的协议,也只有自己的软件支持,其他软件都不识别的协议就是伪协议。
在PHP中,PHP给自己定义了一个php伪协议,以:php://
起头。
至于http://
、file://
这些都不是伪协议,都是大部分系统/软件都支持的协议,共享同一套协议标准。
php://filter
php伪协议的过滤器功能,可以通过拼接各种过滤器达到快速转换字节流的效果。如:
php://filter/read=convert.base64-encode/resource=index.php
其中
filter/[read|write]=[过滤器]
可简写为filter/[过滤器]
,php会自选判断是read还是write。
此时php会读取index.php文件的内容,通过convert过滤器的base64-encode方法,最总将所得结果以php代码的形式包含到运行的php文件之中,由于base64编码之后的内容不会出现<?
,所以必然不会被识别为php代码,故而能起到文件读取的作用。
对其进行base64解码得到源码
常用的过滤器有:
过滤器名称 | 说明 | 类别 | 版本 |
---|---|---|---|
string.rot13 | rot13转换 | 字符串过滤器 | PHP>4.3.0 |
string.toupper、string.tolower | 大小写互转 | 字符串过滤器 | PHP>5.0.0 |
string.strip_tags | 去除<?(.*?)?> 的内容 |
string.strip_tags | PHP<7.3.0 |
convert.base64-encode、convert.base64-decode | base64编码转换 | 转换过滤器 | PHP>5.0.0 |
convert.quoted-printable-encode、convert.quoted-printable-decode | URL编码转换 | 转换过滤器 | PHP>5.0.0 |
convert.iconv.编码1.编码2 | 任意编码转换 | 转换过滤器 | PHP>5.0.0 |
zlib.deflate、zlib.inflate | zlib压缩 | 压缩过滤器 | PHP>5.1.0 |
bzip2.compress、bzip2.decompress | zlib压缩 | 压缩过滤器 | PHP>5.1.0 |
利用 php://input 协议
主要用来接收post数据,将post请求中的数据作为php代码执行。
条件:allow_url_include = On
(PHP版本>5.2后,默认值为Off)
file_put_contents
示例:
1 |
|
$content在开头增加了exit过程,导致即使我们成功写入内容,也执行不了,这时候如何绕过?
payload
1 | filename=php://filter/convert.base64-decode/resource=phpinfo.php&content=aPD9waHAgcGhwaW5mbygpOyA/Pg== |
对写入内容(这里是<?php phpinfo(); ?>
)进行Base64编码(PD9waHAgcGhwaW5mbygpOyA/Pg==
),在包含phpinfo.php这个文件时又进行Base64解码,这时写入内容还原,而死亡代码exit()被解码为乱码,达到绕过目的。
添加额外字符a:Base64解码时是4个byte一组,前面的phpexit
一共7个字符,增加一个a凑成8个字符,这样phpexita
被正常解码,而后面我们写入的内容也才会正常解码。
base64编码中只包含64个可打印字符(大小写字母,0-9,+,/),而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。
其他协议
除了php伪协议外,PHP还支持包含以下协议的数据流:
1 | file:// — 访问本地文件系统 |
如利用file协议:
配合日志文件
如果知道服务器日志文件的路径,可在URL请求中添加攻击代码,此代码会被记录在服务器日志文件内,再对日志文件进行包含,攻击代码便会被执行。(前提有访问权限)
测试靶场:DVWA
在日志文件中可见,部分字符被URL编码,代码无法执行,可用burpsuite抓包改回。
利用文件包含漏洞包含此日志文件,即可执行插入代码
绕过方式
- %00截断
条件:magic_quotes_gps=off php版本<5.3.4
示例:
1 | include("inc/" . $_GET['file'] . ".php"); |
这里对后缀名进行了限制,可是我们无法上传php文件,满足条件下可用00截断绕过。
?page=../../../../phpinfo.php%00
- 长度截断
前提:PHP版本<5.2.10
操作系统对于目录字符串存在长度限制,在linux下4096字节时会达到最大值,在window下是256字节。只要不断的重复./
即可:
1 | lfi.php?file=././././[./]+/./shell.txt |
- 重写
?page=….//….//….//phpinfo.php
- 利用php伪协议等
危害
最简单的,我们可以通过上传一个包含webshell内容的图片,然后通过包含此图片即可得到一个可以控制的webshell。
- 获取敏感信息
- 执行任意命令
- 获取服务器权限
防御
- 尽量不使用动态包含,无需情况下设置allow_url_include和allow_url_fopen为关闭;
- 对可以包含的文件进行限制︰使用白名单的方式,或者设置包含的目录,open_basedir ;
- 严格检查用户输入,参数中不允许出现../之类的目录跳转符;
- 严格检查变量是否初始化;
- 不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
参考资料: