文章目录
4.File Inclusion
参考文献:
文件包含漏洞
原理分析
File Inclusion,文件包含漏洞,目录遍历漏洞在国内外有许多不同的叫法,也可以叫做信息泄露漏洞、非授权文件包含漏洞等。
文件包含分类
- LFI:本地文件包含(Local File Inclusion)
- RFI:远程文件包含(Remote File Inclusion)
与文件包含有关的函数
include():只有代码执行到该函数时才会包含文件进来,发生错误时只给出一个警告并继续向下执行。
include_once():和 include()功能相同,区别在于当重复调用同一文件时,程序只调用一次。
require():只要程序执行就包含文件进来,发生错误时会输出错误结果并终止运行。
require_once():和 require()功能相同,区别在于当重复调用同一文件时,程序只调用一次。
相关的 php.ini 配置参数
allow_url_fopen = on (默认开启)
allow_url_include = on (默认关闭)
远程文件包含是因为开启了 php 配置中的 allow_url_fopen 选项(选项开启之后,服务器允许包含一个远程的文件)。
4.1、low
源码赏析
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
?>
start
没有任何判断,可以执行任何路径
本地用…/等路径查看文件,远程用http等查看文件。链接如下:
http://192.168.10.208:8081/DVWA-master/vulnerabilities/fi/?page=file2.php
4.2、medium
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
?>
由源代码可以发现,本文中过滤了http://、https://、../、..\
字符,本地文件直接用绝对路径,相对路径可以用 ..././..././..././dvwa/fi
,远程文件可以用 htthttp://p:
,如下:(这个我尝试了一下,没有试出来。)
http:/192.168.10.208:8081/DVWA-master/vulnerabilities/fi/?page=htthttp://p://127.0.0.1/phpinfo.txt
4.3、high
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
从源代码可以看出,这里要求page参数的开头必须是file,服务器才会去包含相应的文件。然而可以利用file协议绕过防护策略。
http://www.dvwa.com/vulnerabilities/fi/?page=file:///F:/phpStudy/PHPTutorial/WWW/dvwa/php.ini
4.4、Impossiable
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Only allow include.php or file{1..3}.php
if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
这里直接利用白名单进行拦截,除非修改文件内容,或者将文件设置为白名单中的文件(即发生了替换),否则将无法进行绕过
5.File Upload
5.1、low
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
/*basename() 函数返回路径中的文件名部分。
$_FILES['userfile']['name']客户端机器文件的原名称。*/
// Can we move the file to the upload folder?
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
$html .= '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
$html .= "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>
由上可得,对于文件没有进行任何的过滤,因此可以对任意文件进行上传,无需过滤。
5.2、medium
这里利用白名单对于上传文件的后缀、大小、文件类型进行了过滤。即文件类型只能为jpeg或者png,大小只能为10000字节以内。在前端我们不能直接上传php文件,因此我们需要在后端进行修改绕过。
因此我们需要bp拦包,然后修改内容类型为 Image/png
,如下图,可见上传成功。
5.3、high
有源码可得,这里对上传的文件进行截取,以点最后一次出现的位置后面作为文件后缀,判断是否为jpg、jpeg、png文件并且大小是否小于100000字节。此时只能上传jpg、jpeg、png文件。
绕过方法:通过构造一句话图片木马,然后上传来绕过防御,然后结合php文件解析漏洞或者web中间件解析漏洞或者文件包含漏洞来达到解析含有php代码的png文件。
16进制00截断
仔细查看后发现%00截断需要PHP<5.3.4,实验环境为5.6.35所以无法利用。
图片后门
参考文件:DVWA & File Upload文件上传最详细绕过
做了一张图片隐藏后门fun.jpg
用16进制编辑器010editor实现,文件上传。
上传后可以正常访问,而此时我们的难题就是怎么让文件被解析而触发我们的后门
http://127.0.0.1/DVWA/vulnerabilities/fi/?page=file://D:\phpstudy\WWW\DVWA\hackable\uploads\fun.jpg
发现文件被解析,下面我们菜刀连接就好了。
5.4、Impossiable
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
//文件在上传者机器的文件名,即最开始的名字
echo $uploaded_name."<br/>";
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
//上传文件的后缀名
echo $uploaded_ext."<br/>";
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
//上传文件的大小
echo $uploaded_size."<br/>" ;
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
//上传文件的类型
echo $uploaded_type."<br/>";
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
//文件上传到服务临时文件夹后的文件名
echo $uploaded_tmp."<br/><br/><br/>";
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
echo DVWA_WEB_PAGE_TO_ROOT."<br/>";
echo $target_path."<br/>";
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
/*uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。*/
echo $target_file."<br/>";
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
/*ini_get用来取php.ini文件里的环境变量的值,有时候我们也
没有权限去修改php.ini文件,这时就用这个函数。
sys_get_temp_dir():返回用于临时文件tem_file的目录*/
echo "temp_file=".$temp_file."<br/>";
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
/* DIRECTORY_SEPARATOR 目录分隔符*/
echo "temp_file=".$temp_file."<br/>";
echo "DIRECTORY_SEPARATOR = ".DIRECTORY_SEPARATOR ."<br/><br/><br/>";
// Is it an image?
/*他是一个图片吗?*/
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {
/*getimagesize()函数:用于获取图像大小及相关信息,成功返回一个数组,
失败则返回 FALSE 并产生一条 E_WARNING 级的错误信息。*/
echo getimagesize( $uploaded_tmp ) ."<br/>";
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
/*通过重新编码图像来剥离任何元数据
(注意,建议使用php-GD建议使用php-Imagick)*/
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
/*imagecreatefromjpeg($file_name) 返回一图像标识符,
代表了从给定的文件名取得的 jpg 图像。
$filename为图片路径,即从某给定的路径中取出图片。*/
echo "图片信息为".$img."<br/>";
imagejpeg( $img, $temp_file, 100);
/*imagejpeg(),以 jpg 格式输出图像到浏览器或文件;
即输出之前的图像 $img 到 $temp_file文件夹,100保存图片的质量。
一般是0~100,100为质量最大。*/
echo imagejpeg( $img, $temp_file, 100)."<br/><br/><br/>";
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
echo "png图像信息为 ".imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
/*imagedestroy():销毁图像*/
// Can we move the file to the web root from the temp folder?
/*我们可以将文件从temp文件夹移动到Web根目录吗?*/
echo "oldname = ".$temp_file."<br/>";
echo "newname = ".getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file."<br/>" ;
echo "结束了。";
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
/*rename($oldname,$newname)尝试着把oldname重命名为newname*/
// Yes!
$html .= "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
$html .= '<pre>Your image was not uploaded.</pre>';
}
// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>