Growtika / Unsplash
Editor’s note: In this installment of Exploits Explained, security researcher Malcolm Stagg recounts his discovery of CVE-2024-0333, a vulnerability in Google Chrome that could have been exploited to enable the installation of malicious extensions. Be sure to follow README on LinkedIn to keep up with future additions to this series.
编者按:在本期的《漏洞利用解释》中,安全研究员 Malcolm Stagg 讲述了他发现的 CVE-2024-0333,这是 Google Chrome 中的一个漏洞,可能已被利用来安装恶意扩展程序。请务必在 LinkedIn 上关注 README,以跟上本系列的未来新增内容。
Google Chrome is the most widely used browser in the world. It has been carefully designed with multiple layers of protections to mitigate most vulnerabilities, and those protections have been carefully reviewed to ensure their efficacy.
谷歌浏览器是世界上使用最广泛的浏览器。它经过精心设计,具有多层保护措施,以缓解大多数漏洞,并且已经仔细审查了这些保护措施以确保其有效性。
One of those protections includes the requirement that any internet protocols used in browser component updates, even when strong encryption is present, shouldn’t be absolutely trusted. Otherwise a government or employer with control over a device’s root certificates could tamper with components or extensions before they are installed, which would represent a significant threat to the browser’s users.
其中一项保护措施包括要求浏览器组件更新中使用的任何互联网协议,即使存在强加密,也不应绝对信任。否则,控制设备根证书的政府或雇主可能会在安装组件或扩展之前篡改它们,这将对浏览器用户构成重大威胁。
Chromium prevents such attacks by validating cryptographic signatures for each installed file. All extensions and most browser component updates use the CRX file format, which is effectively a ZIP file prepended with a header containing signatures and other metadata to guarantee file integrity.
Chromium 通过验证每个已安装文件的加密签名来防止此类攻击。所有扩展和大多数浏览器组件更新都使用CRX文件格式,该格式实际上是一个ZIP文件,前面加上包含签名和其他元数据的标题,以保证文件的完整性。
I started looking at the CRX file format after working on a Synack special project to find privilege escalations on a virtual machine target. On a similar target the previous year, I performed binary static analysis and found three zero-day vulnerabilities, including CVE-2022-32427 and CVE-2022-32972, on three different background services. These vulnerabilities varied in cause and complexity to exploit, but they all had one thing in common: insufficient input validation when data was sent from a low-privileged executable to the high-privileged service, allowing the low-privileged user to take control of the computer.
在完成Synack特殊项目以查找虚拟机目标上的权限升级后,我开始查看CRX文件格式。在前一年的类似目标上,我执行了二进制静态分析,并在三个不同的后台服务上发现了三个零日漏洞,包括 CVE-2022-32427 和 CVE-2022-32972。这些漏洞利用的原因和复杂性各不相同,但它们都有一个共同点:当数据从低特权可执行文件发送到高特权服务时,输入验证不足,从而允许低特权用户控制计算机。
Looking at the services running on the virtual machine, one caught my eye: the Google Chrome Elevation Service. The name of this service implies that it is designed to take a low-privileged executable file and run it at a higher privilege, as might be necessary for installing certain updates. Although I realized it would be difficult to find a flaw in code as carefully reviewed as Chromium, I was curious to see how the service was designed to ensure that only trusted executable files were elevated.
在虚拟机上运行的服务中,有一个引起了我的注意:Google Chrome Elevation Service。此服务的名称意味着它旨在获取低特权可执行文件并以更高的权限运行它,这是安装某些更新所必需的。虽然我意识到很难在像 Chromium 这样仔细审查的代码中找到缺陷,但我很好奇该服务是如何设计的,以确保只有受信任的可执行文件才会被提升。
As expected, the service followed a well-designed procedure to prevent tampering: it would first copy a user-specified CRX file to a trusted location, perform signature validation on the file, decompress it, then finally run the extracted executable. A low-privileged user would not have permission to inject any additional files into the trusted location, and any attempt to tamper with the compressed executable would invalidate the signature and prevent it from running.
正如预期的那样,该服务遵循精心设计的程序来防止篡改:它首先将用户指定的CRX文件复制到受信任的位置,对文件执行签名验证,解压缩它,然后最终运行提取的可执行文件。低特权用户将无权将任何其他文件注入受信任位置,并且任何篡改压缩可执行文件的尝试都会使签名失效并阻止其运行。
It seemed impossible to elevate a malicious executable file using this service – unless the CRX signature verification could somehow be bypassed. After researching the CRX file format, I realized that injecting extra data into the header might be possible. The header is what contains signatures for the rest of the file, so most of the data contained within the header itself is not subject to any verification.
使用此服务提升恶意可执行文件似乎是不可能的 – 除非可以以某种方式绕过CRX签名验证。在研究了CRX文件格式之后,我意识到将额外的数据注入标题可能是可能的。标头包含文件其余部分的签名,因此标头本身包含的大多数数据都不需要经过任何验证。
I first tried injecting a full ZIP archive into the CRX header. Nothing happened – my injected data had no effect. To find out why, I began to research the ZIP file format, and specifically the EOCD (end of central directory) token which is present at the end of the ZIP file, interestingly enough as a remnant of the days when ZIP files would span many floppy disks. By placing this token at the end of the archive, files could be added to the archive without the need to modify a previous floppy disk. Since the ZIP file format requires the search for the EOCD token to start at the end of the archive and go backwards, a CRX file header can be prepended to the archive without affecting its contents.
我首先尝试将完整的ZIP存档注入CRX标头。什么也没发生——我注入的数据没有效果。为了找出原因,我开始研究ZIP文件格式,特别是ZIP文件末尾的EOCD(中央目录末尾)令牌,有趣的是,ZIP文件将跨越许多软盘的时代的残余。通过将此令牌放在存档的末尾,可以将文件添加到存档中,而无需修改以前的软盘。由于ZIP文件格式要求搜索EOCD令牌从存档末尾开始并向后移动,因此CRX文件头可以附加到存档中,而不会影响其内容。
The Minizip library is used by Chromium to decompress ZIP archives. I started looking at its unzOpenInternal function, which will first open the ZIP archive and find any EOCD tokens. I noticed something interesting while reviewing this code: Minizip uses two separate functions, unz64local_SearchCentralDir64 and unz64local_SearchCentralDir, to find EOCD tokens.
Chromium 使用 Minizip 库来解压缩 ZIP 存档。我开始查看它的 unzOpenInternal 函数,它将首先打开 ZIP 存档并找到任何 EOCD 令牌。在查看此代码时,我注意到了一些有趣的事情:Minizip 使用两个独立的函数 unz64local_SearchCentralDir64 和 unz64local_SearchCentralDir 来查找 EOCD 令牌。
In my research of the ZIP file format I had found that ZIP64 archives, which are an extension of the ZIP format to support file sizes above 4GB, use a different EOCD token referred to as EOCD64. It appeared that Minizip would first attempt to find an EOCD64 token, and then only if that failed, find an EOCD token as a fallback.
在我对ZIP文件格式的研究中,我发现ZIP64档案是ZIP格式的扩展,支持4GB以上的文件大小,使用不同的EOCD令牌,称为EOCD64。Minizip 似乎会首先尝试查找 EOCD64 令牌,然后只有在失败时才找到 EOCD 令牌作为后备。
This gave me an idea: maybe I could inject an EOCD64 token into the CRX file header. When Minizip decompresses the file, it might first find my malicious EOCD64 token instead of the intended EOCD token. There was one limitation, though, which was that Minizip only searches the last 64kB of the archive file for either token. My attack only had a chance of working with an archive under 64kB in size.
这给了我一个想法:也许我可以将 EOCD64 令牌注入 CRX 文件头。当 Minizip 解压缩文件时,它可能会首先找到我的恶意 EOCD64 令牌,而不是预期的 EOCD 令牌。但是,有一个限制,即 Minizip 只搜索存档文件的最后 64kB 以查找任一令牌。我的攻击只有机会处理大小小于 64kB 的存档。
Figure 1: A malicious Chrome extension could be injected inside a valid Chrome extension (left) to create a malicious extension with a valid signature (right)
图 1:可以在有效的 Chrome 扩展程序(左)中注入恶意 Chrome 扩展程序,以创建具有有效签名的恶意扩展程序(右)
Nevertheless, I now had a plan. I created a Python script to inject a ZIP payload, containing a valid EOCD64 token, into a CRX file header, and created a small Chrome extension to attack. This extension simply displays a banner on any page visited. Next, I created the ZIP payload corresponding to a malicious extension that displays a different banner. The attack worked! I could embed my payload into the CRX file and change the banner.
尽管如此,我现在有了一个计划。我创建了一个 Python 脚本,将包含有效 EOCD64 令牌的 ZIP 有效负载注入 CRX 文件头,并创建了一个小型 Chrome 扩展程序进行攻击。此扩展程序只是在访问的任何页面上显示横幅。接下来,我创建了与显示不同横幅的恶意扩展相对应的 ZIP 有效负载。攻击奏效了!我可以将我的有效负载嵌入到CRX文件中并更改横幅。
Although this looked like an interesting attack, I needed to figure out its potential impact. Could this still be used for local privilege escalation? What about attacking Chrome Web Store extensions? Or internal Chrome components?
虽然这看起来像是一次有趣的攻击,但我需要弄清楚它的潜在影响。这仍然可以用于本地权限提升吗?攻击 Chrome 网上应用店扩展程序怎么办?还是内部 Chrome 组件?
For a local privilege escalation, I would need a valid, signed CRX file containing a ZIP archive under 64kB. I began to search the internet for any files signed with that specific key. The smallest I could find was 73kB. Close call, but roughly 7000 bytes too large for my attack. It also looked like Chrome components and Chrome Web Store extensions were quite well protected. When Chrome components are updated, the Client Update Protocol signs each request and response. Even if an attacker could intercept HTTPS traffic, they could not tamper with these signed responses.
对于本地权限提升,我需要一个有效的签名CRX文件,其中包含64kB以下的ZIP存档。我开始在互联网上搜索使用该特定密钥签名的任何文件。我能找到的最小的是 73kB。关闭呼叫,但对于我的攻击来说大约7000字节太大了。看起来 Chrome 组件和 Chrome 网上应用店扩展程序也得到了很好的保护。更新 Chrome 组件后,客户端更新协议会对每个请求和响应进行签名。即使攻击者可以拦截 HTTPS 流量,他们也无法篡改这些签名的响应。
I did find one area that was largely unprotected. Chrome allows companies to define policies for their enterprise extensions. These extensions can be automatically installed and updated from an internal company update server. I came up with an attack scenario for these extensions involving a coffee shop.
我确实发现了一个基本上没有受到保护的区域。Chrome 允许公司为其企业扩展程序定义政策。可以从内部公司更新服务器自动安装和更新这些扩展。我想出了一个涉及咖啡店的扩展的攻击场景。
In this scenario, an employee heads over to a coffee shop with their laptop. A local attacker, also in this coffee shop, sets up their IP or host name to match the company’s internal update server. The next time Chrome runs extension updates on the employee’s device, it will download the maliciously modified extension from the attacker’s device. Because it still contains a valid signature, the employee’s laptop will upgrade to the malicious extension. The attacker could use this extension to perform a variety of attacks, including monitoring the employee’s web activity and modifying visited pages to steal passwords and session cookies, potentially gaining access to private servers and devices on the company’s internal network.
在此方案中,员工带着笔记本电脑前往咖啡店。本地攻击者也在这家咖啡店中,设置其 IP 或主机名以匹配公司的内部更新服务器。下次 Chrome 在员工的设备上运行扩展程序更新时,它会从攻击者的设备上下载经过恶意修改的扩展程序。由于它仍然包含有效的签名,因此员工的笔记本电脑将升级到恶意扩展。攻击者可以使用此扩展程序执行各种攻击,包括监控员工的 Web 活动和修改访问的页面以窃取密码和会话 cookie,从而可能访问公司内部网络上的私人服务器和设备。
Here’s a video walkthrough showcasing the vulnerability:
下面是一个视频演练,演示了该漏洞:
After proving that this scenario could be exploited using a local HTTP update server, I finished my report to Google describing the issue. Within 24 hours, they had patched the Chromium source code to fix the issue and soon released the fix publicly in the 120.0.6099.216 browser release. Although I never got the privilege escalation working, it led me on a path to find a very interesting Chromium vulnerability which had gone unnoticed for over six years.
在证明可以使用本地 HTTP 更新服务器利用此方案后,我完成了向 Google 提交的报告,描述了该问题。在 24 小时内,他们修补了 Chromium 源代码以修复该问题,并很快在 120.0.6099.216 浏览器版本中公开发布了该修复程序。虽然我从未让权限升级起作用,但它让我走上了一条发现非常有趣的 Chromium 漏洞的道路,该漏洞在六年多的时间里一直被忽视。