代码审计中的文件上传漏洞
0x00 背景
文件上传漏洞是一种威胁极大的漏洞,如果存在该漏洞,黑客一般会上传一个可执行文件至服务器,如木马,通过这个文件来获取服务器的一定权限。如果对这种攻击方式防范不严,我们会受到极大的损失。本文以代码审计的形式研究文件上传漏洞的原理、挖掘形式、防御方案及缺陷。
0x01 文件上传漏洞的产生原理
文件上传漏洞是由程序解析了黑客上传的恶意程序产生的,我们以DVWA的low级别源码为例学习一下文件上传漏洞的产生原理:
1 <?php 2 3 if( isset( $_POST[ 'Upload' ] ) ) { 4 // Where are we going to be writing to? 5 $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; 6 $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] ); 7 8 // Can we move the file to the upload folder? 9 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { 10 // No 11 echo '<pre>Your image was not uploaded.</pre>'; 12 } 13 else { 14 // Yes! 15 echo "<pre>{$target_path} succesfully uploaded!</pre>"; 16 } 17 } 18 19 ?>
我们通过以上代码可以看出用户上传的文件未经任何验证直接保存到了hackable/uploads/目录下。basename(path,suffix)函数返回路径中的文件名,保存在变量target_path中。最后还把文件路径和文件名输出到了前端。黑客在知道文件上传的路径后访问该文件,如果文件被解析,那么就可以进行下一步的利用。
0x02 文件上传漏洞的挖掘形式
在上文代码的第9行就是PHP中唯一的上传函数:
move_uploaded_file(file,newloc)
若成功,则返回 true,否则返回 false。 所以我们在挖掘的时候全局搜索这个函数,然后再检查文件是否验证了文件格式,能否进行绕过。
绕过的主要思路是配合Web容器的文件解析漏洞进行,所以我们还需要了解目前已知存在文件解析漏洞的Web容器版本,具体利用方式可以参考这篇博客https://www.cnblogs.com/v01cano/p/10326366.html
0x03 防御方案及缺陷
黑白名单
黑名单曾经是比较流行的防御方案,通过验证拓展名的方式阻止可疑文件上传,但是由于这种验证方式容易被绕过,所以基本被白名单验证所淘汰。
1.黑名单不全
以IIS+asp为例,能够解析asp的拓展名有:asp、cdx、asa、cer,如果我们只把asp放入黑名单,显然不足以阻止文件上传攻击的产生。
2.%00截断
熟悉黑盒测试的一定了解在url中%00表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。例如test.php%00.jpg,校验黑名单的时候程序会认为后缀名为jpg放行,但是执行时却会以php文件执行。在PHP5.3之后的版本中,修复了%00截断的问题。
文件头验证
getimagesize(filename)
进行验证。例如:
<?php print_r(getimagesize('1.gif')); ?>
在1.gif文件中,我们写入文件头GIF89a,文件内容随便写,我们发现这个文件被判断为GIF文件,返回了尺寸数组。
content-type验证
content-type位于request请求里,是我们抓包后可以自行修改的内容,例如:
1 <?php 2 $upload_type=$_FILES['img']['type']; 3 // Is it an image? 4 if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) && 5 ( $uploaded_size < 100000 ) ) { 6 7 // Can we move the file to the upload folder? 8 if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) { 9 // No 10 echo '<pre>Your image was not uploaded.</pre>'; 11 } 12 else { 13 // Yes! 14 echo "<pre>{$target_path} succesfully uploaded!</pre>"; 15 } 16 } 17 else { 18 // Invalid file 19 echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>'; 20 } 21 } 22 23 ?>
早期不少网站存在这种漏洞,现在已经比较少见了。
上传文件重命名
将用户上传的文件重命名是一种安全程度较高的防御方式,我们一般采用hash(文件名+时间戳+salt随机数)的方式对文件重命名。入侵者在不清楚自己的木马命名的时候就很难连接进行攻击了。