编码与转换 (Encoding and Transformations)
编码与转换是在不改变核心含义的情况下,改变数据的表示或传输方式的技术。常见的例子包括 URL 编码、Base64、HTML 实体编码和 Unicode 转换。攻击者利用这些方法作为“组件 (gadgets)”来绕过输入过滤器、避开 Web 应用程序防火墙 (WAF) 或破坏清理 (sanitization) 程序。
摘要 (Summary)
Unicode
Unicode 是一种通用字符编码标准,用于表示世界上几乎所有书写系统的文本。每个字符(字母、数字、符号、表情符号)都被分配了一个唯一的码点(例如,“A”的码点是 U+0041)。UTF-8 和 UTF-16 等 Unicode 编码格式指定了这些码点如何以字节形式存储。
Unicode 归一化 (Unicode Normalization)
Unicode 归一化是将 Unicode 文本转换为标准化、一致形式的过程,以便在内存中以相同的方式表示等效字符。
- NFC (Normalization Form Canonical Composition):尽可能将分解的序列组合成预组合字符。
- NFD (Normalization Form Canonical Decomposition):将字符拆分为其分解形式(基准字符 + 组合标记)。
- NFKC (Normalization Form Compatibility Composition):类似于 NFC,但还会将字符替换为兼容等效项(可能会改变外观/格式)。
- NFKD (Normalization Form Compatibility Decomposition):类似于 NFD,但也会分解兼容字符。
| 字符 | Payload | 归一化后 |
|---|---|---|
‥ (U+2025) |
‥/‥/‥/etc/passwd |
../../../etc/passwd |
︰ (U+FE30) |
︰/︰/︰/etc/passwd |
../../../etc/passwd |
' (U+FF07) |
' or '1'='1 |
' or '1'='1 |
" (U+FF02) |
" or "1"="1 |
" or "1"="1 |
﹣ (U+FE63) |
admin'﹣﹣ |
admin'-- |
。 (U+3002) |
domain。com |
domain.com |
/ (U+FF0F) |
//domain.com |
//domain.com |
< (U+FF1C) |
<img src=a> |
<img src=a/> |
﹛ (U+FE5B) |
﹛﹛3+3﹜﹜ |
{{3+3}} |
[ (U+FF3B) |
[[5+5]] |
[[5+5]] |
& (U+FF06) |
&&whoami |
&&whoami |
p (U+FF50) |
shell.pʰp |
shell.php |
ʰ (U+02B0) |
shell.pʰp |
shell.php |
ª (U+00AA) |
ªdmin |
admin |
import unicodedata
string = "ᴾᵃʸˡᵒᵃᵈˢ𝓐𝓵𝓵𝕋𝕙𝕖𝒯𝒽𝒾𝓃ℊ𝓈"
print ('NFC: ' + unicodedata.normalize('NFC', string))
print ('NFD: ' + unicodedata.normalize('NFD', string))
print ('NFKC: ' + unicodedata.normalize('NFKC', string))
print ('NFKD: ' + unicodedata.normalize('NFKD', string))
Punycode
Punycode 是一种仅使用有限的 ASCII 字符集(字母、数字和连字符)来表示 Unicode 字符(包括非 ASCII 字母、符号和文字)的方法。
它主要用于域名系统 (DNS),该系统传统上仅支持 ASCII。Punycode 允许使用国际化域名 (IDN),通过将其转换为安全的 ASCII 形式,使域名可以包含来自许多语言的字符。
| 浏览器中可见 (支持 IDN) | 实际 ASCII (Punycode) |
|---|---|
| раypal.com | xn--ypal-43d9g.com |
| paypal.com | paypal.com |
在 MySQL 中,相似字符被视为相等。这种行为可以在密码重置、忘记密码和 OAuth 提供程序部分被利用。
如果 SQL 查询使用 COLLATE utf8mb4_0900_as_cs,则此技巧不成立:
SELECT 'a' = 'ᵃ' COLLATE utf8mb4_0900_as_cs;
+----------------------------------------+
| 'a' = 'ᵃ' COLLATE utf8mb4_0900_as_cs |
+----------------------------------------+
| 0 |
+----------------------------------------+
Base64
Base64 编码是将二进制数据(如图片或文件)或包含特殊字符的文本转换为仅使用 ASCII 字符(A-Z, a-z, 0-9, +, 和 /)的可读字符串的方法。输入的每 3 个字节分为 4 组,每组 6 位,并映射到 4 个 Base64 字符。如果输入不是 3 字节的倍数,则输出使用 = 字符进行填充。