
该PHP脚本未过滤用户输入的token参数,直接拼接到Content-Disposition响应头中,导致攻击者可通过构造恶意文件名实现HTTP头部注入,进而触发浏览器端XSS。
该php脚本未过滤用户输入的`token`参数,直接拼接到`content-disposition`响应头中,导致攻击者可通过构造恶意文件名实现http头部注入,进而触发浏览器端xss。
这段代码存在典型的HTTP头注入(Header Injection)引发的反射型XSS漏洞,核心问题在于:$input未经任何校验或编码,被直接拼入header()函数的Content-Disposition字段中:
$input = $_GET['token'];
$input = str_replace(array("\n", "\0"), '', $input); // 仅过滤换行符和空字节,防护严重不足
header("Content-Disposition: attachment; filename='$input'"); // ⚠️ 危险拼接!
虽然代码移除了\n和\0,但仍允许注入回车符(\r)、单引号、双引号、分号及HTML特殊字符。关键在于:当Content-Disposition值被浏览器解析时,若服务端返回的响应头中存在换行(如通过\r\n绕过),攻击者可注入额外HTTP头(如X-XSS-Protection、Content-Type)甚至将<script>载荷写入响应体——但更常见且可靠的利用路径是:<strong>诱导浏览器将附件名解析为可执行的HTML上下文。</script>
✅ 正确的PoC示例(需配合浏览器行为):
http://www.site.com/test/2.php?token=test'%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<script>alert(1)</script>
说明:
- %0d%0a 是 \r\n 的URL编码,用于在filename=后注入新HTTP头;
- Content-Type: text/html 强制浏览器以HTML方式渲染响应体;
- 后续的两个 %0d%0a(即\r\n\r\n)分隔响应头与响应体;
- <script>alert(1)</script> 成为响应正文,被当作HTML执行。
⚠️ 注意事项:
- 并非所有浏览器都支持Content-Disposition头中注入HTML MIME类型并执行脚本(现代Chrome/Firefox对附件响应的JS执行有严格限制),但IE、旧版Edge及部分配置宽松的环境仍可能触发;
- 更稳定利用方式是结合filename="test.html"+响应体内容(如print "<script>..."),但本例中print "Hello. $input"已将$input输出到HTML正文——因此若token=<script>alert(1)</script>,且响应未设置Content-Type: text/html,浏览器可能因MIME嗅探误执行(不推荐依赖);
-
根本修复方案是:禁止用户控制文件名中的任意字符。应使用白名单过滤(如仅允许字母、数字、下划线、短横线)并强制添加安全扩展名:
$filename = preg_replace('/[^a-zA-Z0-9_-]/', '_', $_GET['token']) . '.txt'; header("Content-Disposition: attachment; filename=\"$filename\""); - 始终对输出到HTTP头的变量进行严格编码(如rawurlencode()仅适用于URL路径,不适用于header());更安全的做法是完全避免动态文件名,或使用固定名称+服务端映射ID。
总结:XSS不仅存在于HTML标签内,也潜伏于HTTP响应头中。任何将用户输入拼接到header()、setcookie()、Location等函数的行为,都必须经过严格白名单校验与上下文编码——信任用户输入,永远是Web安全的第一道失守防线。










