漏洞描述

文件上传漏洞是指由于程序员未对上传的文件进行严格的验证和过滤,而导致用户可以越过其本身权限向服务器上传可执行的动态脚本文件。如常见的头像上传,图片上传,oa 办公文件上传,媒体上传,允许用户上传文件,如果过滤不严格,恶意用户利用文件上传漏洞,上传有害的可以执行脚本文件到服务器中,可以获取服务器的权限,或进一步危害服务器。

漏洞危害

非法用户可以上传的恶意文件控制整个网站,甚至是控制服务器,这个恶意脚本文件,又被称为 webshell,上传 webshell 后门可以很方便地查看服务器信息,查看目录,执行系统命令等。

靶场

upload-labs:https://github.com/c0ny1/upload-labs

项目提供了一个Windows下,按照需求配置好的集成环境

下载地址:https://github.com/c0ny1/upload-labs/releases

集成环境绿色免安装,解压即可使用

1、与文件上传的相关知识

文件上传的过程

客户端 选择发送的文件->服务器接收->网站程序判断->临时文件->移动到指定的路径

服务器 接收的资源程序

服务器接收资源的代码

 1 <?php
 2     if ($_FILES["file"]["error"] > 0)
 3         {
 4         echo "Error: " . $_FILES["file"]["error"] . "<br />";
 5         }
 6     else
 7     {
 8         echo "Upload: " . $_FILES["file"]["name"] . "<br />";
 9         echo "Type: " . $_FILES["file"]["type"] . "<br />";
10         echo "Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
11         echo "Stored in: " . $_FILES["file"]["tmp_name"];
12     }
13 ?>

客户端文件上传的代码

 1 <html>
 2     <head></head>
 3     <body>
 4         <form action="upload.php" method="post" enctype="multipart/form-data">
 5             <label for="file">Filename:</label>
 6             <input type="file" name="file" id="file" />
 7             <br />
 8         <input type="submit" name="submit" value="Submit" />
 9         </form>
10     </body>
11 </html>

文件上传代码

文件上传时会返回一些代码给客户端,客户端根据这些值判断上传是否正常

  • 值:0 没有错误发生,文件上传成功
  • 值:1 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值
  • 值:2 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定 的值
  • 值:3 文件只有部分被上传
  • 值:4 没有文件被上传

文件上传漏洞

文件上传漏洞分为直接文件上传,这种漏洞类型是属于高危漏洞的一种,能直接 getshell,而且没有任何限制,攻击者很容易通过上传点,获取网站的控制权限。另外一种是有条件的上传漏洞,这种漏洞一般是开发者经验不足,对文件上传做了简单的限制,如简单的前端认证,文件头文件检测,这种检测行为是可以完全绕过的,另外就是权限认证没处理,没有对文件上传页面进行权限认证,匿名者就能访问上传文件,上传网页后门到网站目录,控制整个网站。还有一些上传逻辑有问题,导致文件上传可以被绕过,上传后门到网站上。有的文件上传漏洞则是通过中间件或者系统特性上传可以被服务器解析脚本文件,从而导致网站可被控制。

修复方案

  • 文件上传目录设置为禁止脚本文件执行,这样即使被上传后门的动态脚本也不能解析运行
  • 在网站中需要存在上传模块,需要做好权限认证,不能让匿名用户可访问
  • 设置上传白名单,白名单只允许图片上传,如 jpg png gif 其他文件均不允许上传
  • 上传的后缀名,一定要设置成图片格式,如 jpg png gif

攻击方法

寻找测试网站的文件上传的模块,常见头像上传,修改上传,文件编辑器中文件上传,图片上传、媒体上传等,通过抓包上传恶意的文件进行测试,上传后缀名 asp php aspx 等的动态语言脚本,查看上传时的返回信息,判断是否能直接上传,如果不能直接上传,再进行测试上传突破。例如上传文件的时候只允许图片格式的后缀,但是修改文件时,却没有限制后缀名,图片文件可以修改成动态语言格式如 php,则可能访问这个文件的 URL 直接 getshell,可以控制网站。

常见网站文件后缀名

可执行脚本的文件后缀名,可被网站目录解析

以下是常见的后缀名

asp asa cdx cer php aspx ashx jsp php3 php.a shtml phtml

有些网站会对 asp 或者 php 进行过滤,转成空可用这些后缀名

aspasp asaspp phpphp

2、任意文件上传漏洞

任意文件上传漏洞又名文件直接上传漏洞,这种漏洞危害极大,如果攻击者能直接上传恶意脚本到网站存放的目录,且这个目录可解析动态脚本语言,那么攻击者就能够直接获取网站权限,进一步权限提升,从而控制服务器

代码分析

直接获取文件名,把上传的临时文件移动到 hackable/uploads 目录下

直接上传文件,网页会返回路径,访问 url 即可 getshell

上传的文件可以改成其他恶意脚本或者后门,如中国菜刀一句话,后门大马等,即可获得 webshell

3、绕过前端 js 检测上传

Pass-01

在文件上传时,用户选择文件或者提交时,有些网站会对前端文件名进行验证,一般检测后缀名,是否为上传的格式。如果上传的格式不对,则弹出提示文字,此时数据包并没有提交到服务器,只是在客户端通过 js 文件进行校验,验证不通过则不会提交到服务器进行处理。

代码分析

客户段 html 上传文件时会调用 checkFile 函数,首先获取文件后缀名。如果文件为空,则弹出“请选择要上传的文件”,如果文件不为空,获取上传的文件后缀名不是 .jpg、.png 、.gif 其中一种则提示“该文件不允许上传”,上传失败。

绕过 js 检测方法

  • 按 F12 使用网页审计元素,把校验的上传文件后缀名文件删除,即可绕过上传
  • 把恶意文件改成 js 允许上传的文件后缀,如 jpg、gif、png 等,再通过抓包工具抓取 post 的数据包,把后缀名改成可执行的脚本后缀如 php 、asp、jsp、 net 等,即可绕过上传

删除 js 文件

抓包修改后缀名

4、绕过 contnet-type 检测上传

Pass-02

有些上传模块,会对 http 的类型头进行检测,如果是图片类型,允许上传文件到服务器,否则返回上传失败。因为服务端是通过 content-type 判断类型, content-type 在客户端可被修改,则此文件上传也有可能被绕过的风险。

代码分析

首先进行 submit 提交判断,再检测文件类型如果是 image/jpeg 或者 image/png 即允许上传

content-type 检测上传攻击

上传脚本文件,抓包把 content-type 修改成 image/jpeg 即可绕过上传

参考网站:https://www.runoob.com/http/http-content-type.html

5、绕过黑名单上传

Pass-03

上传模块,有时候会写成黑名单限制,在上传文件的时候获取后缀名,再把后缀名与程序中黑名单进行检测,如果后缀名在黑名单的列表内,文件将禁止文件上传。

代码分析

首先检测 submit 是否有值,获取文件的后缀名,进行黑名单对比,后缀名不在黑名单内,允许上传

绕过黑名单上传攻击

上传图片时,如果提示不允许 php、asp 这种信息提示,可判断为黑名单限制,上传黑名单以外的后缀名即可

在 iis 里 asp 禁止上传,可以上传 asa cer cdx 这些后缀,如果网站允许.net 执行,可以上传 ashx 代替 aspx

在不同的中间件中有特殊的情况,如果在 apache 可以开启 application/x-httpd-php

在 AddType application/x-httpd-php .php .phtml .php3 后缀名为 phtml 、php3 均被解析成 php 有的 apache 版本默认就会开启,即上传目标中间件可支持的环境的语言脚本即可,如.phtml、php3

6、htaccess 重写解析绕过上传

Pass-04

htaccess 文件的作用是可以帮我们实现包括:文件夹密码保护、用户自动重定向、自定义错误页面、改变文件扩展名、封禁特定 IP 地址的用户、只允许特定 IP 地址的用户、禁止目录列表,以及使用其他文件作为 index 文件等功能

在 htaccess 里写入 SetHandler application/x-httpd-php 则可以把文件重写成 php 文件,要 htaccess 的规则生效,则需要在 apache 开启 rewrite 重写模块,因为 apache 是多数都开启这个模块,所以规则一般都生效

代码分析

如果 submit 有值,$deny_ext = array(“.php”,”.php5″,”.php4″,”.php3″,”.php2″,”php1″,”.html”,”.htm”,”.phtml”,”.pht”,”.pHp”,”.pHp5″,”.pHp4″,”.pHp3″,”.pHp2″,”pHp1″,”.Html”,”.Htm”,”.pHtml”,”.jsp”,”.jspa”,”.jspx”,”.jsw”,”.jsv”,”.jspf”,”.jtml”,”.jSp”,”.jSpx”,”.jSpa”,”.jSw”,”.jSv”,”.jSpf”,”.jHtml”,”.asp”,”.aspx”,”.asa”,”.asax”,”.ascx”,”.ashx”,”.asmx”,”.cer”,”.aSp”,”.aSpx”,”.aSa”,”.aSax”,”.aScx”,”.aShx”,”.aSmx”,”.cEr”,”.sWf”,”.swf”);

其中包括了所有的执行脚本,上传的文件后缀名在列表内则禁止上传

htaccess 重写解析攻击

上传.htaccess 到网站里,其内容是

<FilesMatch “jpg”>

SetHandler application/x-httpd-php

</FilesMatch>

再上传恶意的 jpg 到.htaccess 相同目录里,访问图片即可获取执行脚本

重点 fck 编辑器

7、大小写绕过上传

Pass-05

上传模块的后缀名采用黑名单判断,但是没有对后缀名的大小写进行严格判断,导致可以更改后缀大小写绕过

如 PHP、 Php、 phP、pHp

代码分析

获取文件后缀名进行判断,如果后缀在这个字典里则禁止上传。 $deny_ext = array(“.php”,”.php5″,”.php4″,”.php3″,”.php2″,”.html”,”.htm”,”.phtml”,”.pht”,”.pHp”,”.pHp5″,”.pHp4″,”.pHp3″,”.pHp2″,”.Html”,”.Htm”,”.pHtml”,”.jsp”,”.jspa”,”.jspx”,”.jsw”,”.jsv”,”.jspf”,”.jtml”,”.jSp”,”.jSpx”,”.jSpa”,”.jSw”,”.jSv”,”.jSpf”,”.jHtml”,”.asp”,”.aspx”,”.asa”,”.asax”,”.ascx”,”.ashx”,”.asmx”,”.cer”,”.aSp”,”.aSpx”,”.aSa”,”.aSax”,”.aScx”,”.aShx”,”.aSmx”,”.cEr”,”.sWf”,”.swf”,”.htaccess”);

黑名单大小写绕过攻击

仔细阅读黑名单,查看是否有被忽略的后缀名,当前可以使用 phP 绕过

8、空格绕过上传

Pass-06

在上传模块里,采用黑名单上传,如果没有对空格进行去掉可能被绕过

代码分析

检测 submit 后,上传目录存在时,进入黑名单判断。如果文件后缀名在黑名单里,则不允许上传,但是文件后缀名没有过滤空格,可以添加空格绕过

空格绕过上传攻击

抓包上传,在后缀名后添加空格

9、利用 windows 系统特征绕过上传

Pass-07

在 windows 中文件后缀名. 系统会自动忽略,即 up.php. 和 up.php 的效果一样,所以可在文件名后面加上.绕过

代码分析

同样是黑名单禁止上传,但是可以上传.php.这种文件后缀

windows 系统特征绕过攻击

抓包修改,在后缀名后加上.即可绕过

10、NTFS 交换数据流::$DATA 绕过上传

Pass-08

如果后缀名没有对::$DATA 进行判断,利用 windows 系统 NTFS 特征可以绕过上传

代码分析

同样用黑名单过滤后缀名,但是程序中没有对::$DATA 进行过滤可以添加::$DATA 绕过上传。$deny_ext = array(“.php”,”.php5″,”.php4″,”.php3″,”.php2″,”.html”,”.htm”,”.phtml”,”.pht”,”.pHp”,”.pHp5″,”.pHp4″,”.pHp3″,”.pHp2″,”.Html”,”.Htm”,”.pHtml”,”.jsp”,”.jspa”,”.jspx”,”.jsw”,”.jsv”,”.jspf”,”.jtml”,”.jSp”,”.jSpx”,”.jSpa”,”.jSw”,”.jSv”,”.jSpf”,”.jHtml”,”.asp”,”.aspx”,”.asa”,”.asax”,”.ascx”,”.ashx”,”.asmx”,”.cer”,”.aSp”,”.aSpx”,”.aSa”,”.aSax”,”.aScx”,”.aShx”,”.aSmx”,”.cEr”,”.sWf”,”.swf”,”.htaccess”);

NTFS 交换数据流::$DATA 攻击绕过上传

开启抓包,修改后缀名为 php::$DATA

11、利用 windows 环境的叠加特征绕过上传

Pass-09

在 windwos 中如果上传文件名 up.php:.jpg 的时候,会在目录下产生空白的文件名 up.php 再利用 php 和 windows 环境的叠加属性。以下符号在正则匹配时相等

双引号” 等于点号.

大于符号> 等于问号?

小于符号< 等于星号*

文件名.<或文件名.<<<或文件名.>>>或文件名.>><空文件名

代码分析

同样是黑名单匹配,把.去掉,过滤空格,过滤::$data

利用 windows 环境的叠加特征绕过上传攻击

首先抓包上传 up.php:.jpg 上传会在目录里生成 up.php 空白文件,接着再次提交把 up.php 改成 up.>>>

12、双写后缀名绕过上传

Pass-10

在上传模块,有的代码会把黑名单的后缀名替换成空,例如 up.php 会把 php 替换成空,但是可以使用双写绕过,例如 asaspp,pphphp,即可绕过上传

代码分析

同样是黑名单过滤,str_ireplace 对上传的后缀名是黑名单内的字符串转换成空

文件上传双写绕过攻击

抓包修改,把后缀名改成 pphphp 即可绕过上传

13、目录可控 %00 截断绕过上传

Pass-11

以上都是一些黑名单被绕过的,如果黑名单上传检测后,没有限定后缀名,绕过的方法很多,与黑名单相对的就是白名单,使用白名单验证会相对比较安全,因为只允许指定的文件后缀名。但是如果有可控的参数目录,也存在被绕过的风险。

代码分析

代码中使用白名单限制上传的文件后缀名,只允许指定的图片格式,但是 $_GET[‘save_path’] 服务器接受客户端的值,这个值可被客户端修改,所以会留下安全问题

文件上传参数目录可控攻击

上传参数可控

  • 当 gpc 关闭的情况下,可以用%00 对目录或者文件名进行截断
  • php 版本小于 5.3.4

首先截断攻击,抓包上传将%00 自动截断后面内容

例如 up.php%00.up.jpg 变成 up.php

14、目录可控 POST 绕过上传

Pass-12

上面是 GET 请求的,可以直接在 url 输入%00 即可截断,但是在 post 下直接注入%00 是不行的,需要把 %00 解码变成空白符,截断才有效,才能把目录截断成文件名

代码分析

同样是白名单限制后缀名,$_POST[‘save_path’] 是接收客户端提交的值,可以任意修改,所以会产生安全漏洞

目录可控上传攻击

文件名可控,通过抓包修改可控的参数,与不同的中间件的缺陷配合使用

使用%00 截断文件名,在 post 环境下%00 要经过 decode 但是受 gpc 限制

使用 burpsutie POST %00 截断文件名

15、文件头检测绕过上传

Pass-13

有的文件上传,上传时候会检测头文件,不同的文件,头文件也不相同。常见的文件上传图片头检测,它会检测图片是两个字节的长度,如果不是图片的格式,会禁止上传

常见的文件头

  • JPEG (jpg),文件头:FFD8FF
  • PNG (png),文件头:89504E47
  • GIF (gif),文件头:47494638
  • TIFF (tif),文件头:49492A00
  • Windows Bitmap (bmp),文件头:424D

代码分析

文件头检测的上传,getReailFileType 是检测 jpg、png、gif 的文件头,如果上传的文件符合数字即可通过检测

文件头检测绕过上传攻击方法

制作图片一句话,使用 copy 1.gif/b+up.php shell.php 将 php 文件附加在 jpg 图片上,直接上传即可

本例因为限制了后缀为 jpg,可以考虑文件包含将图片文件包含进去 getshell

burpsuite 上传的数据包头加上 GIF89a 也可以绕过

16、图片检测函数绕过上传

Pass-14 查看代码 getimagesize 是获取图片的大小,如果头文件不是图片会报错,可以用图片马绕过检测

再用文件包含漏洞引入 gif 图片即可 getshell

17、绕过图片二次渲染上传

Pass-16

有些图片上传,会对上传的图片进行二次渲染后再保存,体积可能会更小,图片会模糊一些,但是符合网站的需求。例如新闻图片封面等需要二次渲染,因为原图片占用的体积更大,访问的人数太多时会占用很大带宽。二次渲染后的图片内容会减少,如果里面包含后门代码,就可能会被省略,导致上传的图片马,恶意代码被清除。

代码分析

只允许上传 JPG PNG gif 图片,使用 imagecreatefromgif 函数对图片进行二次生成

绕过图片二次渲染攻击

判断是否允许上传 gif 图片,gif 图片在二次渲染后,与原图差别不会太大,所以二次渲染攻击最好用 gif 图片马

制作图片马,将原图片上传,下载渲染后的图片进行对比,找相同处覆盖字符串,填写一句话后门或恶意指令

原图片与渲染后的图片该位置的字符串没有改变,在这里替换成<?php phpinfo();?>上传即可

18、文件上传条件竞争漏洞绕过

Pass-17

在文件上传时,如果逻辑不对,会造成很大危害。例如文件上传时,用 move_uploaded_file 把上传的临时文件移动到指定目录,接着再用 rename 文件,设置为图片格式,如果在 rename 之前 move_uploaded_file 这个步骤,这个文件可被客户端访问,这样也可以获取一个 webshell。

代码分析

采用白名单上传,$upload_file = UPLOAD_PATH . ‘/’ . $file_name; 设置上传路径,后缀名没有限定,接着 move_uploaded_file($temp_file, $upload_file) 将图片移动到指定的目录,使用 rename 重名为图片类型

在重名之前如果被浏览器访问,可以得到一个 webshell

文件上传条件竞争攻击方法

上传 php 后门脚本,上传之后用 burpsutie 设置访问,线程建议提高一些

抓包上传 php 文件,设置变量不停的提交这个包

要知道 php 的访问路径,然后用浏览器一直访问,按F5一直刷新,如果在上传的瞬间访问到了,它就无法删除

19、文件名可控绕过上传

Pass-19

文件上传时,文件名可被客户端修改控制,会导致漏洞产生

代码分析

采用黑名单限制上传文件,但是 $_POST[‘save_name’] 文件是可控的,可被客户端任意修改,造成安全漏洞

文件名控可控攻击方法

文件名攻击的方法主要有两种

上传文件,文件后缀采用%00 截断,抓包解码例如 up.php%00.up.jpg 截断后为 up.php 或者使用/.

%00 截断需要 gpc 关闭,截断文件名 php 版本小于 5.3.4

与中间的漏洞配合使用,例如

iis6.0 上传 1.php;1.jpg 解析成 1.php

apache 上传 1.php.a 解析成 1.php

a.asp;1.jpg 解析成 a.asp

20、数组绕过上传

Pass-20

有的文件上传,如果支持数组上传或者数组命名,逻辑写的有问题就会造成安全隐患,导致不可预期的上传。这种上传攻击,它是属于攻击者白盒审计后发现的漏洞居多

代码分析

首先检测文件类型,看到可控参数 save_name 如果不是数组,后缀名不是图片就禁止上传,如果是数组就绕过图片类型检测,继续处理数组

首先对于如下的例子

1 <?php
2 $file= $_GET['save_name'];
3 echo $file_name = reset($file) . '.' . $file[count($file) - 1];
4 ?>

如果是两个参数,拼接字符串是 xx.php/.png

如果下标是 1 为正常图片上传,如果下标大于 1 拼接字符串 xx.php/.

在 move_uploaded_file()函数中 /.会自动忽略,所以可以移动到指定目录

数组绕过攻击方法

构造上传表单,设置数组上传。从代码中,可以知道第二个数组大于 1 即可上传,第二个数组的值就无法获取,字符串拼接起来就是 up.php/. 就能成功上传

upload.php

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4     <meta charset="UTF-8">
 5     <title></title>
 6     </head>
 7     <body>
 8         <form enctype="multipart/form-data" method="post" action="http://127.0.0.1/Pass-20/index.php">
 9         <p>请选择要上传的图片:<p>
10         <input class="input_file" type="file" name="upload_file"/>
11         <p>保存名称:<p>
12         <input class="input_text" type="text" name="save_name[0]" value="up.php/" /><br/>
13         <input class="input_text" type="text" name="save_name[3]" value="jpg" /><br/>
14         <input class="button" type="submit" name="submit" value="上传"/>
15         </form>
16     </body>
17 </html>    

21、文件上传其他漏洞

nginx 0.83 /1.jpg%00php

apahce(1x 或者 2x)当 apache 遇见不认识的后缀名,会从后向前解析,例如 1.php.rar 不认识 rar 就向前解析,直到解析出认识的后缀名

phpcgi 漏洞(nginx iis7 或者以上)上传图片 1.jpg 后,访问 1.jpg/1.php 也会解析成 php

Apache HTTPD 换行解析漏洞(CVE-2017-15715)

apache 通过 mod_php 来运行脚本,其 2.4.0 – 2.4.29 中存在 apache 换行解析漏洞,在解析 php 时 xxx.php\x0A 将被按照 PHP 后缀进行解析,导致绕过一些服务器的安全策略

通用检测方法

判断是否为黑白名单,如果是白名单寻找可控参数,如果是黑名单禁止上传,可以用有危害的后缀名批量提交测试,寻找遗留的执行脚本

.php.php5.php4.php3.php2.html.htm.phtml.pht.pHp.phP.pHp5.pHp4.pHp3.pHp2.Html.Htm.pHtml.jsp.jspa.jspx.jsw.jsv.jspf.jtml.jSp.jSpx.jSpa.jSw.jSv.jSpf.jHtml.asp.aspx.asa.asax.ascx.ashx.asmx.cer.aSp.aSpx.aSa.aSax.aScx.aShx.aSmx.cEr.sWf.swf.htaccess

使用 burpsuite 抓包上传将后缀名设置成变量,把这些文件设置成一个字典批量提交

查看数据包大小,找到可上传的后缀即可

防御方法 服务器端使用白名单防御,修复 web 中间件的漏洞,禁止客户端存在可控参数,存放文件目录禁止脚本执行,限制后缀名。一定要设置图片格式 jpg、gif 、png 文件名为随机的,不可预测
攻击方法