Python 标准库 ipaddress 被发现存在严重的 IP 地址验证漏洞,与今年早些时候 "netmask" 库中报告的漏洞相同。
![]()
本周,发现 netmask 关键漏洞的研究人员也在 ipaddress 模块中发现了同样的漏洞,并获得了一个新的漏洞标识符:CVE-2021-29921。该漏洞于 Python 3.3 版本中随 ipaddress 标准库引入。Python 的 ipaddress 模块主要提供创建 IP 地址、网络和接口的功能,并可以对以不同格式输入的 IP 地址进行解析。
众所周知,IPv4 地址可以用多种格式表示,包括十进制、整数、八进制和十六进制,但最常见的格式是十进制,例如 localhost 127.0.0.1。但如果在它前面加上一个 0,浏览器会将整个字符串视为八进制格式的 IP 地址。比如在 Chrome 的地址栏中输入 0127.0.0.1,IP 实际上变成了十进制的87.0.0.1,这也是大多数应用程序应该处理这种模糊的 IP 地址的方式。
![]()
值得注意的是,127.0.0.1 并不是一个公共的 IP 地址,这种模糊的表述将它变成了一个公共的 IP 地址。根据 IETF 的原始规范,对于模糊的 IP 地址,如果前缀为 "0",IPv4 地址的部分内容可以用八进制解释。但是,在 Python 标准库 ipaddress 的情况下,任何前缀零都会被简单地丢弃,即 '010.8.8.8' 会被当作 '10.8.8.8',而不是 '8.8.8.8'。
由于 ipaddress 输入验证不当,攻击者能够对许多依赖 ipaddress 的程序进行服务器端请求伪造(SSRF)、远程文件包含(RFI)和本地文件包含(LFI)攻击,例如,如果反 SSRF 绕过的封锁名单一直依赖 ipaddress 来解析 IP 列表,那么这种模糊的 IP 就很容易被塞进去。不过,尽管 ipaddress 模块是在 Python 3.3 中引入的,但据研究人员说,这个漏洞从 Python 3.8.0 到 3.10 版本时才出现,因为此前有一些检查,完全拒绝以混合格式(即八进制和十进制)提供的 IP 地址。
![]()
目前,Python 的维护者们正在讨论解决方案,但具体细节以及何时修复仍未明确。关于该漏洞的更多细节,可以在研究人员的博文中查阅。