astrogilda/idna-ip-literal-smuggle-rules
GitHub: astrogilda/idna-ip-literal-smuggle-rules
针对 Go IDNA 处理中数字折叠导致 IP 字面量 smuggling 的漏洞,提供静态分析规则和自动修复工具。
Stars: 0 | Forks: 0
# idna-ip-literal-smuggle-rules
针对 Go 的一种主机名规范化漏洞类别的调用方静态分析规则和自动修复 codemod:UTS-46 IDNA 数字折叠 IP 字面量 smuggling。
## 漏洞类别概述
`golang.org/x/net/idna` 在 `Lookup`、`Display`、`Registration` 和 `MapForLookup` 构建的配置文件上执行 `(*Profile).ToASCII` 和 `(*Profile).ToUnicode` 时会进行 UTS-46 NFKC 映射。该映射会将 100 个非 ASCII 数字码位折叠为其 ASCII 等价物。这 100 个码位分为七个 Unicode 块范围:Latin-1 上标、数学上标、数学下标、圆圈数字、全角数字、数学字母数字符号块(粗体、双线、无衬线、无衬线粗体 和 等宽数字样式)以及段式数字。德文数字(U+0966..U+096F)不在范围内:根据针对 `golang.org/x/net/idna v0.53.0` 的经验验证,它们在所有 UTS-46 配置文件中都能通过 Punycode(`xn--*`),永远不会折叠为 ASCII。
该库不会检查结果是否为 IP 字面量。调用方如果对攻击者控制的主机字符串应用 UTS-46 映射并在网络 sink 中使用结果,而没有针对 IP 字面量解析器重新检查,就会收到一个有效的 ASCII IPv4 字面量作为"域名"输出。任何下游 allowlist、SSRF guard、NoProxy 匹配或 TLS-SNI 路由器如果不重新检查映射后的结果都会被绕过。
这种反模式也适用于那些在 IDNA 之前执行 `net.ParseIP` 检查并认为这就足够的调用方:smuggled 主机不是 ASCII,所以 IDNA 前的检查会将其作为非 IP 拒绝,而 IDNA 后的值(现在是数字字面量)会不受保护地到达 sink。修复方法是在 IDNA 调用后去除尾部点并使用 `net.ParseIP` 或 `netip.ParseAddr` 重新检查。范围仅限 IPv4;IPv6 冒号会在映射运行前被 IDNA 码位验证拒绝。
一个具体示例:输入 `"0.¹.0.0"`(全角零,数学上标一)通过 IDNA 前的 `net.ParseIP` 检查(它不是 ASCII,所以不是 IP),经过 `idna.Lookup.ToASCII`,变成 `"0.1.0.0"`,即 IPv4 环回相邻的字面量。同样的路径也适用于 `"192.168.1.1"`(全角 `192.168.1.1`)以及任何使用上述七个折叠范围内的码位组合的数字和点。尾部点增加了第二个变体:`"0.¹.0.0."` 映射到 `"0.1.0.0."`,`net.ParseIP` 本身会拒绝它,但在去除尾部点后对于路由目的仍然是 IP 字面量。
## 本仓库内容
三个独立的调用方检测或自动修复工具,各自位于自己的子目录中,每个工具都有独立的 README:
| 工具 | 子目录 | 功能 |
|---|---|---|
| CodeQL 查询 | [codeql/](codeql/) | 有状态污点追踪 Go 查询(`go/idna-ip-literal-smuggle`)。两个流状态(`TPreIdna`、`TPostIdna`),因此 IDNA 前的 `net.ParseIP` 不会被误读为屏障。包含内联期望测试用例(正例和负例)以及 `qhelp` 示例。 |
| Semgrep 规则 | [semgrep/](semgrep/) | 使用 `mode: taint` 的 YAML 规则,带有两个标签(PRE_IDNA、POST_IDNA)。提供三个层级:OSS 层级的过程内规则、Pro 层级支持跨文件污点流、以及一个实验性的可选规则,使用放宽的字段名源集合。严重级别为 `WARNING`;针对第三方 Go 代码的经验性误报密度不低且依赖于代码库形状,因此运维人员应计划使用满足 IDNA 后重新检查约定的项目本地 trim 辅助函数扩展 sanitizer 块。 |
| gopatch codemod | [gopatch/](gopatch/) | 两阶段 Uber-gopatch 自动修复,在每个 UTS-46 映射的 `ToASCII` 调用后插入规范的 `TrimRight(_, ".") + netip.ParseAddr` 重新检查守卫,以及一个 awk + gofmt 哨兵注入脚本。 |
展示该漏洞类别的独立概念验证位于 [poc/](
标签:CISA项目, codemod, CodeQL, EVTX分析, gopatch, Go安全, Go语言漏洞, IDNA, IP字面量 smuggling, NFKC映射, Punycode, Semgrep, SSRF防护绕过, Unicode安全, UTS-46, WordPress安全扫描, XSS注入, 云安全监控, 代码安全审计, 域名规范化, 域名验证, 安全评估工具, 日志审计, 服务器监控, 模块化设计, 网络安全, 自动化修复, 逆向工具, 隐私保护, 静态分析