web漏洞之文件上传

一、基础概念

文件上传漏洞是指网站或应用程序允许用户上传文件(如图片、文档等)时,未对上传的文件进行充分的安全验证和限制,导致攻击者可以上传而已文件并执行危险操作。

这种攻击时最为直接有效的,“文件上传”本身没有问题,问题在于上传的文件在服务端中如何处理、解释文件,如果服务端处理文件的逻辑不够安全,则会导致严重的后果。

二、脚本解析拓展名

以下的解析拓展名不是在所有情况下均能够解析,部分拓展名需要在开启特定的配置的情况下才能够正确解析

  1. PHP 脚本解析拓展名
1
2
.php|.php2|.php3|.php4|.php5|.php6|.php7|.phps|.pht|
.phtm|.phtml|.pgif|.shtml|.htaccess|.phar|.inc|.hphp|.module
  1. PHP8 脚本解析拓展名
1
.php|.php4|.php5|.phtml|.module|.inc|.hphp
  1. ASP 脚本解析拓展名
1
.asp|.aspx|.config|.ashx|.aspq|.axd|.cshtm|.cshtml|.rem|.soap|.vbhtml|.asa|.cer|.shtml
  1. JSP 脚本解析拓展名
1
.jsp|.jspx|.jsw|.jsv|.jspf|.wss|.do|.action
  1. Coldfusion 脚本解析拓展名
1
.cfm|.cfml|.cfc|.dbm
  1. Flash 脚本解析拓展名
1
.swf
  1. Perl 脚本解析拓展名
1
.pl|.cgi
  1. Erlang Yaws Web Server 脚本解析拓展名
1
.yaws

三、基本分类

文件上传漏洞的目的就是想方设法让服务端解析上传的文件。在上传文件的过程中可能会遇到诸多阻碍,包括但不限于限制文件上传类型或者限制上传的文件内容等等,为了能够顺利上传文件需要绕过相应的限制,具体的限制类型分为以下两类:

3.1 客户端过滤

客户端过滤也称为前端过滤,通过 JavaScript 前端代码对上传的文件做一些基本的判断,但是这种过滤方式本质上就是不安全的,只能作为一些辅助手段,不能替代后端的安全验证;

通过以下的方法能够基本判断网页的文件上传是否为前端过滤:

  1. 验证速度:验证响应速度快,且网页似乎没有产生停顿或跳转时;
  2. 网页源码是否存在相关判定:查看网页源代码是否存在对上传文件判断的相关 js 代码;
  3. Burpsuite 抓包验证:在产生验证结果前,是否存在向服务端发送文件相关的数据包;

3.2 服务端过滤

服务端过滤也称为后端过滤,通过服务器端对上传文件的处理逻辑进行过滤,包括但不限于后缀名过滤、文件内容过滤、文件内容大小过滤等等;这也是文件上传过滤的主要方式,但是如果存在不安全的处理逻辑,也会导致文件上传漏洞;

可以通过判断是否为客户端过滤来判断是否为服务端过滤,若文件上传点不为前端过滤,则为后端过滤;

若前端存在过滤,则可以通过绕过前端过滤后,再进一步判断是否存在后端过滤;

四、过滤绕过方法

4.1 客户端过滤

4.1.1 抓包重放

  1. 首先构造一个满足前端条件的文件上传,抓取上传文件的数据包;
  2. 修改数据包中文件的名称、内容、类型等数据再重放;

上述方法是普遍使用绕过客户端过滤的方式,通过修改数据包重放绕过前端过滤;

4.1.2 js 禁用

通过禁用 js ,使 js 代码不能执行,从而绕过前端过滤,由于需要对浏览器进行设置,所以一般不适用该方法,并且使用该方式某些情况下无法绕过;

4.2 服务端过滤

4.2.1 文件后缀名大小写绕过

在黑名单过滤的情况下,服务端可能仅对小写字母的后缀名进行过滤,没有考虑大写字母后缀的情况;或者近考虑了大写字母和小写字母的情况,没有考虑大小写字母共存的情况;因此可以通过大小写文件后缀名绕过后缀名过滤。eg:

1
.Php|.pHp|.PHp|.pHp5|.pHaR|.pHtMl

4.2.2 特殊文件后缀名绕过

在服务端过滤的文件后缀名中仅存在一些常见的脚本解析后缀名时,可以通过使用一些特殊的脚本解析后缀名进行绕过。

在某些httpd.conf中,默认对于文件的解析规则可能如下:

1
2
3
<FilesMatch "+\.ph(p[3457]?|t|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>

由于黑名单规则不严谨,可以通过如下扩展名绕过:

1
Php|php2|php3|php4|php5|php6|php7|pht|phtm|phtml

4.2.3 .htaccess 绕过

在apache中,该文件作为一个配置文件,可以用来控制所在目录的访问权限以及解析设置

若服务端没有限制.htaccess文件的上传,那么上传一个.htaccess文件,就可以改变当前目录及其子目录的 apache 配置信息,将其他后缀的文件当作 php 文件解析。

限制条件:服务器主配置文件将AllowOverride设置为All

.htaccess文件中重新编写解析规则

1
2
3
<FilesMatch "info.gif">
SetHandler application/x-httpd-php
</FilesMatch>
1
AddType application/x_httpd_php jpg	 # 匹配所有的jpg后缀文件

在当前目录及其子目录下,如果匹配到info.gif文件,则会被解析成 php 代码执行。上传.htaccess文件覆盖后,上传带有木马的图片以脚本形式解析导致木马执行;

1
echo '<?php phpinfo();?>' > info.gif

4.2.4 .user.ini 绕过

.user.ini文件是php的一个特性,允许位特定的php文件或目录设置特定的ini配置,而无需更改全局的php.ini文件。(.user.ini实际上就是一个可以由用户自定义的php.ini)

限制条件:只有在php>=5.3.0版本中

  • Apache 模块模式:.user.ini 文件默认可以生效
  • FastCGI 模式(如 PHP-FPM):PHP-FPM 配置中未禁用用户级 INI 文件(默认启用);PHP-FPM 子进程有权限读取 .user.ini 文件。

.user.ini.htaccess用的更广泛,不管是 Nginx、Apache、IIS 只要是符合配置运行的 php 就可以。

在 Apache 中.user.ini.htaccess有同样的效果,但.htaccess只可以用于 Apache。

在利用.user.ini绕过文件过滤主要是依赖于以下两个配置:

1
2
auto_prepend_file=	# 指定一个文件,在每个php脚本执行之前加载该文件(包含在文件头)
auto_append_file= # 指定一个文件,在每个php脚本执行之后加载该文件,若php最后exit()则不会加载(包含在文件尾 )

可以简单的理解成在文件前后添加了一条指令include("xxxx");

可以通过上传一个.user.ini文件

1
auto_prepend_file=info.gif

此时,即可上传带有木马的一个文件,将其当作脚本解析即可实现脚本解析执行;

1
echo '<?php phpinfo();?>' > info.gif

这里再提一嘴,有时我们发送的数据包的 url 请求路径会被记录到/var/log/nginx/access.log日志中

当服务端对上传文件内容存在极端过滤的情况下,可以通过请求脚本代码,使/var/log/nginx/access.log记录我们请求的脚本代码,再通过.user.ini包含/var/log/nginx/access.log文件,使其将/var/log/nginx/access.log文件当作脚本解析执行,从而执行请求的脚本代码。

4.2.5 文件内容绕过

  1. 文件头检测

在每一个文件(包括图片,视频或其他的非ASCII文件)的开头都有一片区域来显示这个文件的实际用法,这就是文件头标志。添加服务器允许的文件头以绕过检测。

基本上许多文件都有特定格式的文件头字节,可以将文件头加入到响应的地方。

1
2
3
GIF: 47 49 46 38 39 61
PNG: 89 50 4E 47 0D 0A 1A 0A
JPG: FF D8 FF E0 00 10 4A 46 49 46

只能上传图片格式的后缀,在进行文件头绕过时可以把上面的文件头添加到一句话木马内容最前面,达到绕过文件头检测的目的。

也可以通过在图片的元数据中引入脚本代码实现绕过

1
exiftool -comment="<?php phpinfo(); ?>" info.png
  1. 图片马绕过
  • 绕过getimagesize函数

php一般使用 getimagesize() 函数检测文件头内容检测,getimagesize()函数会返回一个数组,其中下标2是图像的类型,其中1=GIF|2=JPG|3=PNG。上传一个正常图像后缀的图片马即可绕过。

  • 绕过exif_imagetype函数

exif_imagetype()函数会判断一个图像的类型。检查图像的第一个字节。可能返回的常量有IMAGETYPE_GIF=1|IMAGETYPE_JPEG=2|MAGETYPE_PNG=3文件头不正确返回false,上传具有正常文件头的图片马即可绕过。

图片马需要结合解析漏洞或者文件包含漏洞才能解析图片木马。

  • 图片马的制作
1
2
copy gif1.gif/b+shell.php/a hackshell.gif
//表示gif1.php的二进制文件与shell.php的Ascii码文件合成一个新的hackshell.gif图片木马
  1. 二次渲染

在上传文件后,网站会对图片进行二次处理(格式、尺寸要求等),服务器会把里面的内容进行替换更新,处理完成后,我们原有的图片生成一个新的图片并放到网站对应的标签进行显示。

  • 判断方法

对比要上传图片与上传后的图片大小,使用16进制编辑器打开图片查看上传后保留了哪些数据,查看那些数据被改变。

  • 绕过方法

文件包含漏洞:将一句话木马插入到网站二次处理后的图片中,也就是把一句话插入图片在二次渲染后会保留的那部分数据里,确保不会在二次处理时删除掉。这样二次渲染后的图片中就存在了一句话,在配合文件包含漏洞获webshell。

  • 条件竞争

这里二次渲染的逻辑存在漏洞,先将文件上传,之后再判断,符合就保存,不符合删除,可利用条件竞争来进行爆破上传。

4.2.6 文件类型伪造(MIME)绕过

浏览器通常使用 MIME 类型(而不是文件拓展名)来确定如何处理 URL。大部分 Web 应用系统判定文件类型是通过Content-Type字段。

只需要将 MIME 类型修改为白名单中允许的类型即可,上传对文件类型做了白名单限制,可以根据白名单上传白名单中的文件类型;

1
2
3
4
5
6
7
8
9
10
text/plain (纯文本)
text/html (HTML文档)
text/javascript (js代码)
application/xhtml+xml (XHTML文档)
image/gif (GIF图像)
image/jpeg (JPEG图像)
image/png (PNG图像)
video/mpeg (MPEG动画)
application/octet-stream (二进制数据)
application/pdf (PDF文档)

4.2.7 00 截断绕过

%00是字符串的结束标识符,可以利用手动添加字符串结束标识符的方式来将后面的内容进行截断,而后面正常的扩展名又可以帮助我们绕过黑白名单检测。

注意:0x00%00都表示字节值为零的字符,%000x00字节的URL编码形式。

上传路径可控php.ini中的magic_quotes_gpcoff时,可以使用00截断来绕过白名单:

如果上传文件的路径为:可控的上传路径/随机数.白名单中的后缀

正常情况下,服务器拼接得到的上传路径为:$img_path = ../upload/5920201223231032.gif;

而在可控的上传路径中,使用%00截断后,拼接得到的上传路径为:$img_path = ../upload/eval.php%00/5920201223231032.gif

对后缀进行白名单检测时.gif可以很好绕过。但是保存在服务器上的文件却是eval.php,因为%00之后的内容被截断了。

4.2.8 win 系统特性绕过

  • 空格绕过

在Windows平台,在对用户上传的文件名进行处理时,没有使用trim()函数去除字符串首尾处的空白字符。

当用户上传图片马时,用Burp拦截在文件尾部加入空格。带有空格的后缀可以绕过黑名单的检测,但文件存在Windows服务器上时,会自动去除后缀中的空格。

  • 点 dot 绕过

在Windows平台,在对用户上传的文件名进行处理时,没有使用deldot()函数删除文件名末尾的点。

上传文件名末尾的点的文件。在Windows服务器中,后缀名之后的点在保存时,会被自动忽略。

  • NTFS 文件流(::$DATA)绕过

::$DATA流是Windows NTFS文件系统中的一个功能,它允许一个文件拥有多个数据流。创建一个数据交换流文件的方法:宿主文件:准备与宿主文件关联的数据流文件

文件名为文件名+::DATA,则会把::DATA之后的数据当成文件流处理,并不会检测后缀名,且保持::DATA之前的文件名。

上传一个名为eval.php::$DATA的木马,可以绕过黑名单的检测,并且通过eval.php就可以访问。

参考链接

https://www.cnblogs.com/smileleooo/p/18162287


web漏洞之文件上传
http://candyb0x.github.io/2025/02/05/web漏洞之文件上传/
作者
Candy
发布于
2025年2月5日
更新于
2025年4月13日
许可协议