0x01 文件上传
File Upload,即文件上传漏洞,通常是由于对上传文件的类型、内容没有进行严格的过滤、检查,使得可以通过上传webshell获取服务器权限,因此文件上传漏洞带来的危害常常是毁灭性的。
0x02 Low级别
代码如下:
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 这段代码是有关文件上传之后的位置的。basename函数返回路径中的文件名部分。如果可选参数suffix为空,则返回的文件名包含后缀名,反之不包含后缀名。 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // 判断是否可以上传。move_uploaded_file函数将上传的文件移动到新位置。 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // 上传失败 echo '<pre>Your image was not uploaded.</pre>'; } else { // 上传成功,并返回文件路径 echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } ?>
直接上传一句话木马即可。
上传之后,浏览器访问,看是否上传成功。
上传成功。因为我在一句话木马前面加了GIF89a的。
蚁剑连接一句话:
0x03 Medium级别
代码如下:
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 同Low级别 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // 这里是上传的文件的相关信息 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ]; $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; // 判断上传的文件是否是jpeg和png图片且大小小于100000字节 if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && ( $uploaded_size < 100000 ) ) { // 判断文件是否能够上传 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { // 上传失败 echo '<pre>Your image was not uploaded.</pre>'; } else { // 上传成功 echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // 上传的文件不是图片,返回以下信息给用户 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } ?>
medium级别相比于low级别,多了一次验证,验证上传的文件是否是图片。
这里可以使用burp来绕过,当然还有其他的方法。
先将shell.php改为shell.jpg,发送包时用burp进行拦截,并将后缀名重新修改为php。
即可上传成功。
0x04 High级别
代码如下:
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 同以上两个级别 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); // 文件信息。strrpos函数查找字符串在另一字符串中最后一次出现的位置(区分大小写);substr函数返回字符串的一部分。 $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ]; $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);//这句的意思是将文件的后缀名赋给$uploaded_ext $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ]; $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ]; // 判断是否是图片。strtolower函数将所有字符转换为小写;getimagesize函数用于获取图像的大小及相关信息。 if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) && ( $uploaded_size < 100000 ) && getimagesize( $uploaded_tmp ) ) { // 判断能否上传 if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) { // 不能 echo '<pre>Your image was not uploaded.</pre>'; } else { // 能 echo "<pre>{$target_path} succesfully uploaded!</pre>"; } } else { // 上传文件不是图片的反馈信息 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } ?>
high级别的文件上传可以结合low级别的文件包含进行实验。
上传一个图片马,再用文件包含进行读取即可。
0x05 Impossible级别
代码如下:
<?php if( isset( $_POST[ 'Upload' ] ) ) { // 检查token checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' ); // 文件信息 $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' ]; // 将上传的文件进行改名以及确定上传的目录位置。uniqid函数基于以微秒计的当前时间,生成一个唯一的 ID;ini_get函数用于获取一个配置选项的值。sys_get_temp_dir函数用于返回用于临时文件的目录。 $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; // 判断是否为图片 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 ) ) { // 将上传的图片进行重新的编码 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 );//销毁图像 // 判断是否可以将文件从临时目录转移到web根目录。rename函数重命名文件或目录;getcwd函数用于获取当前的工作目录; if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) { // 能 echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>"; } else { // 不能 echo '<pre>Your image was not uploaded.</pre>'; } // 删除所有的临时文件。file_exists函数用于检查文件或目录是否存在。unlink函数用于删除文件。 if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // 上传的文件不符合规则 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; } } // 生成token generateSessionToken(); ?>
0x06 总结
文件上传漏洞防御:
1.上传文件进行重命名(md5值,导致%00截断无法绕过过滤规则)。
2.加入Anti-CSRF token防护CSRF攻击
3.对文件的内容进行严格的检查,让攻击者无法上传含有恶意脚本的文件。