File Upload(文件上传) File Upload文件上传由于对上传文件的内、类型没有做严格的过滤、检查使得攻击者可以通过上传木马文件获取服务器的webshell文件。low这关需要我们上传一个图片文件但我们明确了文件上传漏洞的定义知道他是由于没有严格检查文件内容因此我们试着上传一个并非图片的文件如下用于显示php的配置信息可以看到上传成功了并给我们指出了路径试着访问一下确实给我们返回了php的配置文件源码分析?php if( isset( $_POST[ Upload ] ) ) { // Where are we going to be writing to? //文件的目标路径hackable/uploads/也就是文件上传的位置 $target_path DVWA_WEB_PAGE_TO_ROOT . hackable/uploads/; // basename(path,suffix) //函数返回路径中的文件名部分如果可选参数suffix为空则返回的文件名包含后缀名反之不包含后缀名。 $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 preYour image was not uploaded./pre; } else { // Yes! echo pre{$target_path} succesfully uploaded!/pre; } } ?从源码中可以看到对上传文件的类型、内容没有做任何的过滤与检查同时告诉了我们文件上传的路径存在明显的文件上传漏洞。Medium我们还是先试试上传一个php文件失败了告诉我们只能上传JPEG或者PNG的图片文件那我们抓个包看看可以看到我圈出了Content-Type这个元素它用于告诉服务器我这个请求体里的数据是什么格式。常见文件对应的 Content-Type文件类型Content-Type 值.phpapplication/x-php或text/plain.jpg/.jpegimage/jpeg.pngimage/png.gifimage/gif.html/.htmtext/html.txttext/plain.exeapplication/x-msdownload.zipapplication/zip回到原题中要求我们要上传图片格式那我们就改变其content-type值改为所需要的图片类型值再上传试试能看到上传成功了源码分析?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? //文件类型必须是image/jpeg 或者 image/png大小不能超过100000B约为97.6KB 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 echo preYour image was not uploaded./pre; } else { // Yes! echo pre{$target_path} succesfully uploaded!/pre; } } else { // Invalid file echo preYour image was not uploaded. We can only accept JPEG or PNG images./pre; } } ?对文件上传的类型做了限制要求必须是image/jpeg 或者 image/png 类型的但我们依旧可以抓包改包绕过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? // strtoLower把所有字符转换为小写 getimagesize(string filename) 函数会通过读取文件头返回图片的长、宽等信息如果没有相关的图片文件头函数会报错。 可以看到High级别的代码读取文件名中最后一个”.”后的字符串期望通过文件名来限制文件类型因此要求上传文件名形式必须是”*.jpg”、”*.jpeg” 、”*.png”之一。同时getimagesize函数更是限制了上传文件的文件头必须为图像类型。 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 preYour image was not uploaded./pre; } else { // Yes! echo pre{$target_path} succesfully uploaded!/pre; } } else { // Invalid file echo preYour image was not uploaded. We can only accept JPEG or PNG images./pre; } } ?这里用到了getimagesize($uploaded_tmp)这个函数强制要求上传图片我们可以制作一个图片马首先需要准备一个图片一个脚本文件我用的还是最简单的读取php配置文件在命令行里使用copy合并两个文件这是制作图片马最常用的方式这里需要说明一下/b表示以二进制方式复制图片文件用二进制/a表示以ASCII方式复制PHP文件用文本image_shell.png是最终生成的文件名合并后大家可以看到新文件大小应该 ≈phpinfo.pngphpinfo.php的大小之和并且我们用记事本打开这个图片文件可以在末尾看到这样的字符这说明我们的图片马制作成功了有关其他方式制作图片马可以参考大佬写的这篇文章做一个图片马图片木马的四种方法 小白也能看会(详细步骤 ) 需要.htaccess等执行图片内代码_图片马制作-CSDN博客然后选择一手上传成功了还告诉了我们文件路径接下来我们回到文件包含漏洞中验证一下在URL中输入刚刚上传成功的图片马路径回车页面顶部出现的乱码是图片马中PNG图片的二进制数据被浏览器/服务器误当作文本字符进行渲染时产生的。这并不影响其后的PHP代码被成功执行也恰好证明了该图片马已通过了getimagesize()的图片头检测成功给我们返回了php配置信息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 ) . -; //上传文件的文件前缀md5加密 $target_file md5( uniqid() . $uploaded_name ) . . . $uploaded_ext; //in_get(varname) 函数返回相应选项的值 $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 ) { //imagecreatefromjpeg ( filename ) 函数返回图片文件的图像标识失败返回false $img imagecreatefromjpeg( $uploaded_tmp ); //imagejpeg ( image , filename , quality) 从image图像以filename为文件名创建一个JPEG图像可选参数quality范围从0最差质量文件更小到100最佳质量文件最大。 imagejpeg( $img, $temp_file, 100); } else { $img imagecreatefrompng( $uploaded_tmp ); imagepng( $img, $temp_file, 9); } // imagedestroy( img ) 函数销毁图像资源 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 prea href${target_path}${target_file}${target_file}/a succesfully uploaded!/pre; } else { // No echo preYour image was not uploaded./pre; } // Delete any temp files if( file_exists( $temp_file ) ) unlink( $temp_file ); } else { // Invalid file echo preYour image was not uploaded. We can only accept JPEG or PNG images./pre; } } // Generate Anti-CSRF token generateSessionToken(); ?这个级别的文件上传对上传的文件进行了重命名搞了一个MD5的加密还增加了token值的校验对文件的内容也做了严格的检查。