文件上传这个功能点是现在大部分 UGC 站点必备的功能啦,像是头像、文章编辑、评论区等模块都标配。在编码时不考虑上传文件的内容和文件类型就有可能被上传 WebShell。

最常见的利用方法是对正常上传点,传递脚本直接获取 Web 服务控制权限,或者上传一个 HTML 页面将链接发给用户进行钓鱼;用户一看 URL 是官方就有可能放松警惕。

文件上传分为 WebServer 解析、应用检验不严格这两种类型。

上传功能原理分析(待补充)常见的上传方式:

  1. from 表单 multipart/form-data。
  2. 编码,如 data url base64 编码图片。

使用 Java 写个上传功能。

目录

1 常见绕过

1.1 后缀校验

1.没有判断后缀

截取字符串没有以最后一个点开始,而是只是判断文件后缀中是否包含正确后缀,导致多后缀也可以绕过限制。

2.大小写

没有将文件后缀统一转换为小写校验。

Windows 下更改文件它会忽略大小写,最终指向同一个文件,这个特性在切换目录也可以提现出来,Linux 则当成两个不同的文件,它对大小写是区分的。

系统特性差异.png

3.文件后缀加空格。加了空格就不再是同一个黑名单字符串。

4.遇到黑名单中的后缀直接剔除,后面代码检查没有后缀无法上传。那么可以嵌套 1.asaspxpx,最终得到 1.aspx,此操作有人称双写绕过。

5.遇到仅仅检查黑名单后缀无法上传,aspx 可以尝试上传 aspx、ashx、ascx、asmx。asp 尝试 asp、cer、asa。php 尝试上传 php、php2、php3、php4、php5、pht、phtm、phtml。jsp 尝试 jspx。

文件类型与文件头绕过

文件类型更改请求 Content-type 的 MIME Type 值即可。

文件头是不变的,有些代码仅检测文件头,可以把对应文件头后面加上一句话来上传。既限制了后缀有检查了文件头那么可以上传一个正常图片配合解析漏洞/文件包含拿 Shell。

下图是使用 UltraEdit 查看图片 16 进制的文件头。

常见文件头格式

NTFS 文件流

Windows 每个文件都对应着一个文件流,这里我创建了 shell.php 内容是 gbb,这个创建的过程默认就是用的 Default 文件流。实际上完整格式等同于 shell.php::$DATA,这个格式就是文件流的格式,具体含义为 文件名:流名称:流类型

E:\Pictures>dir
 驱动器 E 中的卷是 SoftWare2
 卷的序列号是 7E0F-A68D

 E:\Pictures 的目录

2024/09/18  17:46    <DIR>          .
2023/04/17  16:21    <DIR>          Camera Roll
2023/03/11  20:39    <DIR>          Saved Pictures
2024/08/14  15:47    <DIR>          Screenshots
               1 个文件             12 字节
               4 个目录 96,116,973,568 可用字节
E:\Pictures>echo raingray > shell.php && type shell.php
raingray

如果使用默认流的情况下,服务器没有此文件就会自动创建一个写入对应内容,文件存在就将原文件内容覆盖。为啥会覆盖?挡我们编辑一个文件时显示的内容都是默认文件流中的内容,把文件流名留空不写就相当于对默认文件流写入数据。

E:\Pictures>echo raingray-rewrite > shell.php::$DATA && type shell.php
raingray-rewrite

如果给文件流命名,就等同于我们重新创建一个文件流依附在源文件上。源文件 shell.php 默认流被删除的话,shell.php:raingray.php:$DATA 附加流也会删除。

E:\Pictures>echo raingray-patchStream > shell.php:raingray.php:$DATA && dir /R
 驱动器 E 中的卷是 SoftWare2
 卷的序列号是 7E0F-A68D

 E:\Pictures 的目录

2024/09/18  17:46    <DIR>          .
2023/04/17  16:21    <DIR>          Camera Roll
2023/03/11  20:39    <DIR>          Saved Pictures
2024/08/14  15:47    <DIR>          Screenshots
2024/09/18  17:56                20 shell.php
                                 24 shell.php:raingray.php:$DATA
               1 个文件             20 字节
               4 个目录 96,116,973,568 可用字节
E:\Pictures>more < shell.php:raingray.php
raingray-patchStream
E:\Pictures>::notepad 也可以获取文件流内容:notepad shell.php:raingray.php

这种 NTFS 文件流绕过方式适用于黑名单绕过,比如 Windows 下的 PHP 应用存在上传功能,但是后缀用黑名单限制不允许 .php,我们就可以在文件名改成通过文件流 shell.ext::$DATA 来绕过后缀限制从而创建 WebShell。

Apache htaccess 配置(待补充)

htaccess 可以针对指定目录进行配置,颗粒度会更细,放置该文件的目录其子目录和文件都会受到影响。

下面的配置是将 .configz 的文件交给 PHP 解析。

AddType application/x-httpd-php .configz

这个配置是将 shell.* 这个文件交给 PHP 解析。

<FilesMatch "shell">
    SetHandler application/x-httpd-php
</FilesMatch>

操作步骤:

  1. 上传 .htaccess 文件,内容是配置某个后缀文件能够交给语言解析。
  2. 上传指定后缀文件

需要给出详细测试 .htaccess 解析其他后缀的图例,如,设置 .htaccess 解析 jpg 为 php。

配合 PHP 文件包含 GetShell

File Inclusion

验证文件内容和后缀,那我们直接上传正常图片,如果服务器存在文件包含漏洞那么可以在图片文件头后面中添加一句话,让代码把中的内容当做代码执行。

Zip Slip(待补充)

应用在解压缩文件时获取了压缩包内文件名,由于文件名存在 ../ 目特殊字符,在写入文件时直接使用包内的文件名和路径做拼接,最终存储路径会根据文件名切换。

或者是有些应用设置白名单只允许上传压缩包、或者图片文件,但存在解压接口,可以直接解压缩指定文件。而且解压缩又没限制格式,给文件就行。

文件上传后自解压漏洞

https://github.com/snyk/zip-slip-vulnerability

具体 POC 可以用 traversal-archives 通过修改 makefile 快速生成自定义路径的压缩包。

SSI 执行命令(待补充)

上传 .shtml。

开启 SSI 并利用执行系统命令。

条件竞争(待补充)

有一种场景是检测到文件后缀是不允许上传的,程序会将其删除。

此时可以一边上传同时进行快速请求此文件,一旦被访问占用掉无法删除,直接成功保留住文件。

字符串截断

上传 shell.php.jpg,通过在 .jpg 开头放置一个结尾符,最后代码遇到就会直接停止在 shell.php,对这个文件名进行操作就成功截断为 php 文件了。

通过结尾符表示文件结束,%00 是 URL 编码后的结尾符。

%00 截断在 PHP 中 需要 Version 小于 5.3.7。当然,也不是非得 PHP 上才能用,只要底层采用 C/C++ 都可以试试,有遇到过在 Java 中也存在这种绕过案例。

Burp 抓包修改文件名处输入的标记字符,转换到十六进制中将标记字符改为 00,或者 1.php%00/1.jpg,选中 %00 Ctrl + Shift + U。

GD 二次渲染绕过(待补充)

  1. 上传符合长宽比的图片(如 1x1大小的图片),避免被图片缩小,导致内容改变。
  2. 常见库绕过,如 PHP 图片处理 GD 库。

2 WebServer 解析问题

就算代码写的没问题,Web 服务器存在问题会把其他文件当做其他正常脚本解析。不过在2026年如今很难碰到这种古老问题。

2.1 Apache 1.x / 2.x 解析漏洞(待补充)

Apache 处理 shell.php.jss.zd 从右到做依次判断后缀名能不能解析,不能往前走,直到能解析就停下来,此时得到处理的文件是 shell.php

Apache 加载的 PHP 模块配置文件正则匹配默认解析 pht、phtml、php3、php4、php5。

2.2 IIS 5.x / 6.0 / 7.5 解析漏洞(待补充)

IIS 调用 asp.dll 解析文件名时出现问题。

  1. Web 服务器上存在 .asp.asa.cer 结尾的目录,其目录下所有文件被访问时都会被当做脚本执行。
  2. 上传一个 xx.asp;.jpgxx.asa;.jpgxx.cer;.jpg 的图片,访问时这个图片会被当做脚本执行。

2.3 Nginx(待补充)

靶场练习

upload-labs

GitHub - c0ny1/upload-labs: 一个想帮你总结所有类型的上传漏洞的靶场

前端 JS 验证

在浏览器关掉 JS。

CheckFile.png

closeJS.JPG

这种方法比较好用,还有个地方可以让它不执行 JS 脚本,它是提交表单是调用这个方法我们可以双击把这双引号内内容删掉,就不会触发检测了。

elements.png

也可以在本地写一个 HTML 表单进行提交。

文件 MIME 验证

他的验证方式是检测 Content-Type 的MIME是否为图片类型 ,只有匹配上了才放你通过。

MimeSourceCode.png

我们将原来的 mime Content-Type: application/octet-stream 改为图片的 MIME 就可以绕过了。

MIME

文件后缀验证

它这里黑名单验证,会把名字转换为小写并重新用 时间+随机值 命名,文件后缀无法加空格绕过。

ExtendFormat.JPG

Web Security Academy

https://portswigger.net/web-security/all-labs#file-upload-vulnerabilities

upload-labs

https://github.com/sqlsec/upload-labs-docker

实战利用

WebShell

通过 ../ 目录遍历来切换目录上传 WebShell。

Java 写文件 new File(path, filename),文件名为空,path 直接绝对路径 /path/index.jsp 可以写直接把文件写入,而不是建立成目录。

XSS

.html.svg.xml 打 XSS。

.svg

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
   <polygon id="triangle" points="0,0 0,50 50,0" fill="#009900" stroke="#004400"/>
   <script type="text/javascript">
      alert(document.domain);
   </script>
</svg>
<svg><desc><![CDATA[</desc><script>alert(1)</script>]]></svg>

.xml

<html>
    <head></head>
    <body>
        <something:script src="http://localhost/1.js"
            xmlns:something="http://www.w3.org/1999/xhtml">
        </something:script>
    </body>
</html>
<html>
    <head></head>
    <body>
        <something:script xmlns:something="http://www.w3.org/1999/xhtml">alert(1)</something:script>
        <a:script xmlns:a="http://www.w3.org/1999/xhtml">alert(2)</a:script>
        <info>
          <name>
            <value><![CDATA[<script>confirm(document.domain)</script>]]></value>
          </name>
            <description>
              <value>Hello</value>
            </description>
            <url>
              <value>http://google.com</value>
            </url>
        </info>
    </body>
</html>

SSTI

传模板文件尝试 SSTI,通过模板来执行命令。

XXE

利用技巧 2,文件上传 xlsx 文件

业务场景:有时应用会解析 excel 内文件数据(POI-OOXML)作为内容进行数据处理最终展示内容。

利用方法:

  1. Windows 下创建 xx.xlsx 文件
  2. 将文件放到 Linux 中,执行 unzip xx.xlsx -d ./right 解压
  3. 将压缩包内 [Content_Types].xml 文件添加 XXE Payload。如果无法获取到请求,可以把 standalone 改为 flag。
    xlsx xxe.png
  4. zip -rq eval.xlsx right 将 right 目录理所有内容重新压缩回 eval.xlsx。
  5. 上传文件,查看是否收到 XXE Request 或者文件内容。

利用技巧 2,文件上传 svg 文件

<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]>
<svg width="500px" height="500px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1
<text font-size="40" x="0" y="16">&xxe;</text>
</svg>

Overlay File

覆盖文件最终结果是要执行你的上传的内容,能否执行要看启动 Web 服务的账户有没权限做操作。

  • 覆盖计划任务。当前是 root 权限可以覆盖计划任务文件直接反弹 Shell。
  • 上传公钥。 当前服务器开启了 SSH 服务,启动了公钥登录,你知道用户 home 目录 的情况下覆盖 /root/<UserName>/.ssh/authorized_keys 文件(只有当前用户和 root 能够访问自己 home 目录),用 SSH 登录。
  • 覆盖系统程序。有些应用存在任务调度功能,可以定时执行系统上某些程序,通过覆盖这些程序,下次运行时将自动执行恶意程序。

DoS

https://github.com/barrracud4/image-upload-exploits

应用不限制上传文件的大小,可以上传超大文件耗尽流量、写满磁盘、高IO导致应用运行缓慢或者瘫痪。

防御

  1. 代码采用白名单校验扩展名。
  2. 对前端传来的图片采用伪随机数命名(时间戳加上伪随机数),不返回上传后的路径,增加找 Shell 难度;要是头像这种在模板上调用图片,这种情况也没办法。
  3. 对图片二次处理(其他语言也有对应图片处理库),就算你上传脚本,渲染后图片中代码会被破坏掉无法正常解析。
  4. 限制上传文件大小,以避免服务器资源耗尽(最低成本 DDOS)。
  5. 取消上传目录执行权限(未测试),IIS 可以用 Web.config 配置,其他 Web 容器需要搜索下资料。
  6. 可以将放置图片单独放在一台服务器或云存储,脚本在图片服务器上没有执行环境不能被解析。
  7. 使用新版本 WebServer 做好安全配置;避免 Web 服务器低版本漏洞和不安全配置问题。

问题

后续需要把这些问题融合到文章中。

问:其他 WebServer 可以支持 htaccess 吗?还是说只有 Apache 能够使用。
答:

问:在实战中会遇到各种奇怪的情景,这里提供一个实际场景,有一个上传点只能 Upload DLL 文件,代码直接读取文件名来决定文件存储位置,这时候你如何利用?
答:CGI-BIN 目录能不能上传。其他没法子。

问:任意文件上传 PDF XSS 如何利用?
答:

问:现在应用有些用 SpringBoot 写完打包程 jar 包运行,现在只能上传 .jar 咋利用?
答:没法子。

问:文件上传测试步骤?
答:

  1. 文件上传功能正常。

    • 上传到 OSS
    • 自建服务器
  2. 能够上传脚本后缀文件。
  3. 能够找到文件路径并成功访问被解析。

    • 上传后返回文件 ID
    • 上传路径是动态的

问:找不到路径怎么办?
答:

  1. SQL 注入获取站点路径,路径下对应文件。
  2. 任意文件读取,获取源码分析怎么保存文件。
  3. 更改上传参数抛异常显示路径。基本不可能遇到。
  4. 通过 JS 有没可能写入目录拼接。
  5. 当前上传功能不显示,可以看看其他静态文件是否与上传文件目录一致。
  6. 扫目录

问:脚本不解析怎么办?
答:

  1. 上传 shtml 尝试执行 SSI。
  2. 上传 html
  3. 上传 .htaccess。上传后要被重命名基本凉凉,而且 WebServer 必须是 Apache。
  4. 更改目录或文件名参数,上传到其他目录。
  5. 上传文件后缀大小写更改,或者尝试其他后缀,因为有些 WebServer 能解析其他文件后缀。
  6. 宝塔配置漏洞,所有 php 命名的文件被解析。

问:什么是图片马
答:将代码放在图片尾部不会破坏图片展示,文件后缀还是脚本格式,这就是图片马,可以用作检测文件内容绕过。在文件包含中是指在后面添加 PHP 代码,但是不影响图片展示,去包含这张图片执行 PHP 代码。

问:遇到 LBS(负载均衡) 如何解决?
答:

  1. 多次上传,确保每台服务器上都有 WebShell
  2. 使用脚本流量转发到指定服务器。https://mp.weixin.qq.com/s/4Bmz_fuu0yrLMK1oBKKtRA
  3. 服务器如果在公网的情况下直接访问 IP(不过负载通常都是内网 IP)
  4. 一般访问应用后负载均衡中会颁发一个会话,可以通过会话固定来访问后面的服务器,避免随机。更通俗的来说,看看上传请求中有没标识可以选择后端应用,比如根据 Cookie 字段来决定使用那台服务器。
  5. 看看研发怎么解决这个问题,就能找到思路,搜索 “负载均衡 文件上传”。

参考链接

最近更新:

发布时间:

摆哈儿龙门阵