BlackHat-2025-US-会议笔记-全-

BlackHat 2025 US 会议笔记(全)

可能终结你太空任务的漏洞集合 🛰️💥

在本节课中,我们将学习太空系统面临的安全威胁。我们将了解太空系统的构成、其软件生态中存在的普遍漏洞,并通过实际演示来展示攻击者如何利用这些漏洞控制航天器或地面系统。

概述:为何关注太空系统安全?

太空系统近期在媒体中频繁出现。冷战时期,在国防工业的推动下,观测或通信卫星被大量发射入轨。进入21世纪后,这一趋势有所放缓。但近年来,发射到地球轨道的卫星数量激增,这主要由星链等商业卫星星座驱动。与此同时,国防领域也在重新军事化,各国政府发射了更多用于情报收集和通信的任务。此外,双重用途日益普遍,例如星链终端在乌克兰前线的使用。

随着轨道上高价值目标数量的增加,攻击面也随之扩大。

太空系统架构简介

上一节我们提到了太空系统的重要性,本节中我们来看看一个典型的太空系统是如何工作的。从高层次看,一个太空系统包含三个主要部分:

  1. 航天器段:这是最明显的部分,可以是单个航天器,也可以是星座中的数十、数百甚至数千个航天器。
  2. 地面段:这是支持太空任务的所有地面基础设施,包括地面站天线、任务控制中心、科学数据中心以及光纤网络等支持设施。
  3. 用户段:这是任务产出的部分,例如星链用户终端,或合成孔径雷达任务生成的数据产品。

一个典型的科学任务流程如下:轨道上的多个航天器通过射频链路与地面站网络通信。任务控制中心连接到地面站网络,并将数据分发到科学数据中心进行后处理和精炼,最终提供给终端用户或科学家。

为了控制航天器,需要操作员介入,这意味着并非全自动化,人类仍然深度参与其中。特别是在新冠疫情之后,远程工作变得普遍,传统的基于边界的安全模型已不再适用,原本为此设计的系统现在暴露在互联网和新的威胁之下。

地面软件漏洞

在任务控制中心这个任务核心,存在大量IT基础设施和定制软件,用于支持任务自动化。其中包括计算卫星轨道的航天动力学软件、规划未来步骤的任务规划软件,以及航天器操作员用来控制航天器的人机界面——任务控制软件。

我们研究了一些流行的开源任务控制软件:

  • YaMCS:用于许多小型卫星任务,并计划用于月球车和国际空间站上的欧洲机械臂。
  • NASA OpenMCT:用于控制火星车。
  • Open C3 COSMOS:在小型卫星任务中日益流行。

航天器软件漏洞

我们同样关注航天器上的软件,特别是那些可能影响多个任务或操作员的通用框架:

  • 核心飞行系统:NASA开发,拥有超过20年历史,用于构建小型卫星任务,也是詹姆斯·韦伯太空望远镜有效载荷的组成部分,目前正为月球门户载人飞行进行认证。
  • F Prime:NASA的一个小型框架,用于控制机智号火星直升机。
  • I A T Core:一个用于在国际空间站上运行实验的Python应用程序工具包。

传统上,在20世纪80、90年代,摧毁一颗卫星意味着向它发射火箭。但我们的研究发现,结合并利用在地面或太空段软件中找到的漏洞,可以更容易地终结一个太空任务。

需要指出的是,许多这类软件历史悠久,传统上并非为安全而设计。开发人员没有要求实施严格的安全措施、零信任架构,或让软件准备好暴露在互联网下。因此,一旦开始审查这些软件,就很容易发现漏洞,其中一些甚至是唾手可得的低级漏洞。

漏洞演示

以下将通过几个演示展示不同的漏洞、攻击向量和利用技术。本质上,我们的目标是接管航天器或控制航天器的系统。

演示一:利用YaMCS的XSS漏洞发送指令

第一个演示针对YaMCS任务控制系统。该系统存在跨站脚本漏洞,使攻击者有机会代表用户向航天器发送任意指令。

为了利用这个XSS漏洞,我们需要通过钓鱼文件诱骗用户。结合XSS利用,我们将能够以用户身份发送指令。

在演示中,左侧是标准的YaMCS任务控制系统界面,用于处理、显示遥测数据和发送指令。右侧是一个运行在低地球轨道的航天器模拟器,其运行速度远快于实时,以便观察结果。

YaMCS有一个实用功能,允许用户使用JavaScript基于原始参数值或系统内任何其他功能定义工程值。正是这个组件存在XSS漏洞。

为了演示,我们定义了一个指令,一旦触发,将使航天器执行轨道机动,转移到中地球轨道。我们将看到航天器向更高轨道移动。

我们不会直接发送这个指令,而是展示如何利用XSS发送它。

YaMCS的脚本功能允许在HTML标签中嵌入载荷。一旦脚本加载,它就会执行,并且由于没有编码,我们可以观察其行为。我们的目标是通过YaMCS提供的API发送指令到航天器。

假设用户收到了来自同事的文件(这可能是内部钓鱼活动)。用户加载并打开该文件。此时,航天器开始偏离原始轨道。但代码中没有任何可疑之处,因为恶意载荷在显示时被隐藏了。然而,Web浏览器执行了这些隐藏的HTML标签中的JavaScript,从而以用户身份向航天器发送了指令。用户唯一能察觉异常的方式是通过遥测数据看到航天器移动,或是在指令历史记录中查看。

核心概念:攻击通过诱使用户加载一个包含恶意JavaScript的脚本文件实现。该脚本利用YaMCS的API,在用户不知情的情况下发送预定义的航天器指令。

// 示例:隐藏在看似正常的脚本文件中的恶意载荷
// 实际文件内容可能包含类似以下结构的隐藏标签
<img src=x onerror="fetch('/api/command', {method:'POST', body:'DESTRUCT_SEQUENCE'})">

演示二:利用Open C3 COSMOS的XSS漏洞获取RCE

下一个演示针对另一个任务控制系统Open C3 COSMOS。该系统同样存在XSS漏洞,但这次攻击将试图获取远程代码执行权限,从而完全接管整个任务控制系统。

由于是XSS攻击,我们再次以航天器操作员为钓鱼活动目标。一旦用户访问我们的钓鱼URL,我们应该能获得一个反向shell连接到运行任务控制系统的服务器。

Open C3 COSMOS界面与之前的系统功能相似,具备遥测、指令发送和脚本运行引擎等功能。

利用这个XSS漏洞更具技巧性,因为它需要多阶段攻击:首先通过API调用获取会话令牌,然后利用令牌部署恶意脚本,最后通过另一次调用触发脚本。

我们编写了一个脚本,用于生成包含我们载荷和想要执行的命令的URL。我们将用这个URL对用户进行钓鱼。

启动监听器后,模拟用户访问了钓鱼URL。界面看起来一切正常,但我们的监听器已经收到了来自运行Open C3 COSMOS系统的反向shell连接。这表明攻击成功,我们获得了系统的远程代码执行权限。

核心概念:多阶段XSS攻击通过窃取会话令牌,进而部署并执行恶意脚本,最终在目标系统上获得反向shell。

# 概念性攻击步骤
1. 钓鱼链接诱导用户访问:`http://target/open-c3/malicious_page?payload=<script>...`
2. 脚本窃取用户的会话Cookie或令牌。
3. 攻击者使用窃取的令牌通过API部署恶意脚本。
4. 触发恶意脚本执行,建立反向Shell连接。

演示三:直接攻击航天器上的CFS软件

第三个演示有所不同,我们不针对地面系统,而是直接攻击航天器本身。

假设你是一个国家行为体,拥有自己的地面站和任务控制中心,并且对目标航天器可见,可以向其发送数据。同时假设该航天器运行着较旧版本的NASA核心飞行系统软件。

我们将尝试直接在航天器上获取远程代码执行权限。出于演示目的,我们将获取一个反向shell,但这在实际中可能不实用。

攻击方法是向航天器发送恶意数据,针对CFS的内存管理模块的弱点。这个攻击也更高级,是多阶段的,需要地面站和航天器之间来回通信,因为我们需要发送一些指令,并从航天器内存中泄露信息。

CFS内存管理模块的主要问题是,攻击者可以在整个CFS进程的内存空间内进行读写,而不仅限于该模块本身。由于CFS运行在基于Linux的操作系统上,可以想象有很多方法可以滥用这个弱点。

在我们的研究中,我们决定利用全局偏移表。我们获取感兴趣函数的地址,然后将这些地址替换为我们想要的地址并执行。通过研究,我们基于某些指令找出了接下来将要执行的CPU指令或函数调用,并将该函数的地址替换为我们感兴趣的函数的地址。

由于这个过程比较复杂,需要来回通信,我们开发了一个脚本来处理与航天器的所有通信。最终,为了演示,这个脚本将让我们执行代码以获得反向shell。

在演示中,我们启动了监听器。脚本开始从链接库泄露内存地址,然后转储航天器内存内容,寻找system函数的地址,因为我们的目的是用该地址替换某个函数地址以获得代码执行权限。

遥测数据传回后,我们获得了内存地址。接着,我们通过指令覆盖了航天器上的全局偏移表。最终,函数被执行,我们获得了航天器上的shell。

核心概念:利用航天器软件(CFS)内存管理模块的漏洞,通过精心构造的指令序列,实现内存读写、信息泄露,最终劫持函数指针(如GOT表项)执行任意代码。

// 概念性漏洞利用步骤(基于内存损坏)
1. 发送恶意指令触发漏洞,实现任意内存读(泄露GOT表地址和libc函数地址)。
2. 计算目标函数(如system)在内存中的实际地址。
3. 发送恶意指令触发漏洞,实现任意内存写,将GOT表中某个即将被调用的函数地址覆盖为system地址。
4. 触发该函数调用,从而执行system("/bin/sh")等命令。

研究发现总结

以上只是我们发现的部分漏洞。实际上,我们在Open C3 COSMOS、YaMCS以及OpenMCT中发现了更多问题。尤其令人担忧的是,我们不仅发现了XSS,还在所有这些系统中发现了更高危的漏洞:

  • 在基于Java的OpenMCT中发现了原型污染漏洞。
  • 在YaMCS中可以实现操作系统上的任意文件删除。
  • 在COSMOS中可以获得远程代码执行并接管运行系统的容器。

航天器上的软件也是如此:

  • 核心飞行系统存在多个漏洞。
  • CryptoLib(CFS的加密插件模块)存在漏洞,允许通过未经认证的指令使整个星载软件崩溃并重启。如果配置不当,CryptoLib会在重启后重置所有密钥,导致航天器使用全零密钥,从而使后续通信失去保护。
  • F Prime中存在可导致远程代码执行的漏洞。
  • I A T Core在其网络通信中使用了不安全的pickle模块,同样存在漏洞。

简而言之,在这些系统中普遍存在大量高危和严重漏洞。

后续影响与最终思考

我们过去几年公开发表了这些研究成果,并引起了其他研究人员的关注。这很好,但人们总会想,为什么之前没有发现这些问题。

特别值得一提的是CryptoLib,其他研究人员随后发现了如何绕过其认证机制,以及如何利用该软件破坏航天器上的密钥库。甚至在该库中还发现了导致系统高危漏洞的内存问题。

我们的最终思考如下:

  1. 冰山一角:所有这些都是在开源软件中发现的。而航天工业99.9%是闭源软件。我们的问题是:在那里还能发现什么?
  2. 激励研究:我们希望看到更多针对研究人员的奖励计划。我们是利用业余时间进行这项研究的,如果任务方本身能提供一些激励,促使人们为任务安全做这类工作,那将是有益的。
  3. 安全与安全的权衡:任务方需要更深入地审视安全性与可靠性之间的权衡。特别是在考虑航天器的认证和恢复机制时,由于无法轻易飞抵航天器进行修复,人们对为任务增加过多安全措施非常谨慎。对于那些已经上天、无法得到妥善维护的任务,需要有缓解策略。当面临一个不安全且无法修复的任务时,需要做出艰难的决定。
  4. 应用最佳实践:我们认为,虽然航天很难,但航天安全不必如此艰难。有很多传统的IT安全规则和最佳实践可以应用,只是仍需推广。

总而言之,即使在太空系统中,水也是湿的——基础的安全问题普遍存在。

本节课中,我们一起学习了太空系统的基本架构、其软件生态中普遍存在的安全漏洞,并通过具体演示了解了攻击者如何利用XSS、内存损坏等漏洞,从地面控制软件和航天器本体两个层面威胁太空任务的安全。关键要点在于,许多太空软件历史悠久且设计时未充分考虑安全,导致大量可被利用的漏洞存在。确保太空安全需要行业重视、应用传统IT安全最佳实践,并认真权衡安全措施与任务可靠性之间的关系。

AppleStorm - 揭露 Apple Intelligence 的隐私风险 🍎⚡

在本节课中,我们将学习 Apple Intelligence 这一苹果公司新推出的 AI 套件,并深入探讨其背后可能存在的隐私风险。我们将通过实际的技术分析,了解用户数据在本地设备与苹果服务器之间是如何流动的。


概述

Apple Intelligence 是苹果公司于去年九月推出的新 AI 功能套件,旨在提升生产力并承诺保护用户数据隐私。它包含写作工具、图像工具,并大幅增强了 Siri 的能力。然而,这些新功能在实际运作中,用户数据是否真的如宣传所言得到妥善保护?本节课将带你一探究竟。

上一节我们介绍了课程主题,本节中我们来看看 Apple Intelligence 的基本架构。

Apple Intelligence 的架构

根据苹果的隐私政策,其 AI 架构主要包含两组模型:

  1. 设备端模型:这些模型直接在用户的 Mac 或 iOS 设备上运行,无需网络通信。
    • 模型推理(用户设备)
  2. 云端模型:这些是更强大的语言和图像模型,运行在苹果的“私有云计算”服务器上。
    • 模型推理(苹果服务器)

这两组模型协同工作。一个运行在用户设备上的“路由模型”会判断当前任务能否完全在本地处理。如果不能,它会将相关数据发送到云端,利用更大的模型来完成用户请求。

然而,苹果的 AI 生态系统不仅包含私有云计算。以下是其三大核心基础设施组件:

  • 私有云计算:处理复杂的 AI 任务。
  • Siri 基础设施
    • 听写服务器 (guzzoni.apple.com):负责语音听写。
    • 搜索服务 (smoothth.apple.com):处理在线或苹果生态内的搜索请求。
  • Apple Intelligence 扩展:用于集成第三方服务,例如 ChatGPT。

了解了基本架构后,接下来我们将聚焦于潜在的风险。

隐私风险研究方法

为了评估风险,我们需要明确两点:

  1. 哪些功能完全在设备端运行,无需网络通信。
  2. 哪些功能需要借助私有云计算或其他苹果基础设施(如 Siri 服务器)来完成。

当功能需要联网时,最关键的问题是:哪些数据从我们的设备发送到了苹果的服务器?

我的研究方法是通过技术手段,拦截 Siri、写作工具、图像工具与苹果服务器之间的所有通信,并分析外传的数据内容。

但这并非易事。虽然 Apple Intelligence 核心功能会记录发送到私有云计算的请求,便于在设备上查看,但 Siri 的通信分析则困难得多。

Siri 使用了一种称为 证书锁定SSL Pinning 的安全技术。这项技术使应用程序能够验证远程服务器确实是苹果的官方服务器,从而拒绝任何其他服务器(例如用于中间人攻击的服务器)的连接。这使得直接解密和分析 Siri 的通信流量变得非常困难。

经过数月的努力,我成功绕过了苹果的证书锁定机制(仅在我自己的设备上),并解密了其背后的所有通信协议。在接下来的演示中,我们将看到发送到苹果服务器的实际数据。

在开始演示前,需要设定一个基线:在研究的初始阶段,我确保关闭了所有“从此 App 学习”的设置选项,以避免预期之外的数据共享。

风险演示与分析

1. Siri 与上下文数据泄露

我们首先测试 Siri。借助 Apple Intelligence,Siri 新增了打字输入功能。我尝试了一个简单的、必须联网才能回答的问题:“拉斯维加斯今天的天气怎么样?”

以下是发送到搜索服务 (smoothth.apple.com) 的数据包内容分析:

  • 精确位置信息:即使用户只是询问天气,Siri 也会在每个请求中默认发送设备的位置信息。用户可以在设置中关闭此功能。
  • 已安装的应用列表:Siri 会在设备上进行“主题建模”,根据用户询问的话题(如天气、邮件、编码),查找设备上所有相关的应用(包括虚拟机内的应用),并将应用名称发送给服务器。
  • “正在播放”队列的元数据:如果用户正在通过任何应用(如 YouTube、VLC)播放音频或视频,该媒体文件的元数据(如歌曲名、视频标题)也会被发送到苹果的听写服务器和搜索服务。即使你只是暂停播放并切换到其他应用,只要该媒体仍在“正在播放”队列中,其信息就可能被发送。

总结:一个简单的天气查询,触发了大量与核心问题无关的上下文数据(位置、应用列表、媒体元数据)被发送至苹果服务器。

2. Siri 与消息应用集成

接下来测试 Siri 与第三方应用的集成,例如通过 Siri 发送 WhatsApp 消息。

研究发现,当使用 Siri 发送 WhatsApp 或 iMessage 时,消息内容、联系人姓名和电话号码会被发送到苹果的听写服务器。然而,当我完全阻断设备与苹果服务器的通信后,Siri 仍然能成功发送消息。这表明,向服务器发送消息数据并非核心功能所必需

相比之下,使用 Siri 撰写邮件或查看日历时,邮件正文或日历事件内容并未被发送到服务器。

3. 写作工具与图像工具

与 Siri 相比,Apple Intelligence 的写作工具和图像工具在隐私保护方面表现更好。

  • 写作工具:大部分功能(如重写、总结)都在设备端完成。少数需要联网的功能(如“从主题生成”)会明确标识,并且只将必要数据发送至私有云计算,没有发现无关数据泄露。
  • 图像工具:所有图像生成和编辑功能都完全在设备端运行,未发现任何图像或提示词被发送至苹果服务器。

4. ChatGPT 扩展

当通过 Apple Intelligence 使用 ChatGPT 时,需要注意两点:

  1. 所有请求并非直接发送给 OpenAI,而是先经过苹果的“Apple Intelligence 扩展”服务器。
  2. 即使用户已登录 ChatGPT 账户,所有通信仍需经过苹果服务器。
  3. 更令人担忧的是,发送给 ChatGPT 的提示词会被同时发送给两个端点:Apple Intelligence 扩展服务器和 Siri 的搜索服务。用户只能看到前者的回复,不清楚后者为何需要这些数据。

与苹果的沟通及现状

我将所有发现披露给了苹果公司。他们的回应可以概括为:

  1. 承认部分 Siri 行为异常(如发送不必要的数据),并承诺由工程团队调查修复。
  2. 强调许多问题(如听写服务器、搜索服务的数据收集)属于 Siri 核心服务 的范畴,而非 Apple Intelligence 的一部分,尽管在用户体验上二者已深度整合。
  3. 表示将改进关于 ChatGPT 集成和私有云计算架构的文档清晰度。

风险缓解建议

在苹果彻底解决问题之前,用户可以采取以下措施来降低风险:

  1. 阻断听写服务器:由于听写服务器的部分数据收集似乎非必需,用户可以通过网络设置阻止设备与 guzzoni.apple.com 的通信,这能在不影响核心功能的情况下减少部分数据泄露。
  2. 审阅隐私设置:立即检查“Siri 与 Apple Intelligence”设置,关闭所有你不想共享数据的应用下方的“从此 App 学习”选项。

总结与思考

本节课中我们一起学习了 Apple Intelligence 的架构,并通过实际技术分析,揭示了其生态中(特别是 Siri 服务)存在的隐私风险,包括不必要的位置信息、应用列表、媒体元数据乃至消息内容的泄露。

本次研究带来几点重要启示:

  1. 隐私政策的重要性:在 AI 时代,我们必须更关注我们共享了哪些数据。可以尝试利用 AI 工具快速总结冗长的隐私政策。
  2. 企业治理与透明度:组织需要工具来监控离开其网络的数据。而像证书锁定这样的安全技术,在保护通信的同时,也阻碍了研究和企业进行必要的安全监控。在涉及 AI 和数据上传的场景中,需要在安全与透明度之间找到平衡。
  3. 功能界线的模糊性:苹果将 Siri 与 Apple Intelligence 在技术上区分开来,但用户体验上它们是一体的。用户可能无法区分一次查询是由“旧版 Siri”处理,还是由“新版 Apple Intelligence”或“集成的 ChatGPT”处理,而这背后对应着不同的数据处理策略和隐私条款。

最终,作为用户,我们需要在享受 AI 带来的便利时,保持对数据隐私的清醒认识。作为行业,则需要推动更高的透明度和更清晰的责任界定。

Azure 的最薄弱环节?API 连接如何泄露秘密 🔓

在本课程中,我们将学习 Azure 逻辑应用中的 API 连接如何成为安全漏洞的源头。我们将探讨一个由安全研究员发现的漏洞链,了解其原理、影响以及微软的修复方式。课程内容基于一次真实的安全研究,旨在帮助初学者理解云基础设施中可能存在的安全隐患。

概述

大家好,我是 Hocomb,一名在挪威一家二进制安全咨询公司工作的安全顾问和研究员。我们主要进行白盒应用渗透测试,这意味着我们在拥有客户源代码、用户权限、管理权限以及基础设施配置完全访问权的情况下测试其应用程序。

在一次客户测试中,我发现了一个 Azure 逻辑应用相关的漏洞。虽然该应用本身防护良好,但通过检查其 Azure 门户中的逻辑应用,我发现了 API 连接中潜藏的风险。

API 连接的初步发现

上一节我们介绍了研究背景,本节中我们来看看 API 连接是什么。

通常,在逻辑应用中寻找漏洞时,我们会尝试寻找未掩码的密钥。逻辑应用本质上是一个响应特定输入(如 HTTP 请求)的 Web 应用。开发者有时会忘记掩码密钥,导致低权限用户可以读取并提升权限。

但在这次案例中,并未发现此类问题。这促使我进一步探索逻辑应用界面中一些特殊符号的含义。这些符号表明存在一个“API 连接”。

API 连接是 Azure 中一个可能不为人知的组件。每当创建一个需要外部连接的操作时,系统会自动创建 API 连接。即使删除了相关操作或逻辑应用,这些连接也可能不会被删除,久而久之就会堆积起来。

点击一个 API 连接(例如一个 Slack 连接器),界面本身信息有限。但有趣的是,通过 HTTP 请求查看其响应时,我们得到了包含关键信息的数据。

其中,第一个红色方框内的“测试链接”引起了我们的注意。这是一个指向 Azure 资源管理器的 URI。

深入分析“测试链接”

上一节我们发现了可疑的测试链接,本节我们来分析它的结构和含义。

该 URI 格式如下:

https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/{connection-name}/extensions/proxy/conversations.list

这是一个对 Azure 资源管理器的请求。Azure 资源管理器是管理 Azure 中所有资源的服务。URI 的构建方式遵循固定模式:包含订阅 ID、资源组、资源类型(此处为 Microsoft.Web/connections)、资源名称以及要执行的操作。

这个操作有几个有趣的点:

  1. 路径中包含 extensions/proxy,表明它正在代理请求到某个后端。
  2. 它以 conversations.list 结尾,熟悉 Slack API 的人会知道,这确实是 Slack 中用于列出频道的端点。
  3. 最重要的是,这个 API 在 Azure 官方文档中并未记载。根据经验,未记录的 API 往往充满漏洞。

以读者权限调用此端点,会返回一个频道列表,这与直接调用 Slack API 的预期结果一致。但问题来了:是谁在发起这个调用?是我吗?我在该租户中有一个 Slack 用户。但测试发现并非如此。

当我们尝试另一个端点 doNotDisturb.setSnooze(设置免打扰状态)时,它返回“snooze enabled”。然而,检查客户的 Slack 后发现,我自己的状态并未改变。那么,是谁的状态被改变了?

我们尝试通过 conversations.join 加入频道来查看谁加入了,但收到了“访问被拒绝”的响应。

至此,我们可以得出一个初步结论:任何对 API 连接的 GET 请求操作,都可以被拥有“读者”角色的用户调用。接下来的核心问题是:我们可以执行哪些操作?以及,真正在执行操作的主体是谁?

API 连接的工作原理

为了回答上述问题,我们需要理解 API 连接的工作原理。微软提供了一张非常清晰的架构图。

架构流程如下:

  1. 逻辑应用收到输入,并携带用户令牌、连接器 ID、操作 ID 和连接 ID,与 Azure API 管理服务通信。
  2. Azure API 管理服务有一份 Swagger 文档,定义了所有可执行的操作,因此访问范围受其限制。
  3. API 管理服务使用输入的用户令牌连接 ID,查询一个“凭据和元数据存储”,以检索连接令牌
  4. 这个连接令牌就是最终调用后端服务(如 Slack)时使用的凭据。它是在最初设置 API 连接时配置的,可以是 OAuth 参数、API 密钥等任何形式的秘密。

然而,如果我们直接尝试调用这个全局的 API 管理主机端点,会被拒绝,因为我们的读者用户不在该连接的访问控制列表中。

但矛盾点在于:我们之前明明通过 Azure 资源管理器成功调用了 Slack 并得到了响应。这是如何发生的?

漏洞的关键:ARM 的访问权限

答案在于连接 ACL 有另一个入口:Azure 资源管理器本身拥有访问权限

这解释了为何通过 Azure 资源管理器发起请求时,我们能够调用 Slack。要理解微软为何这样设计,需要了解 Azure 的一些安全模型特性(这些可能不是官方声明,但实践中确实如此):

  1. 简单的安全模型:在与 Azure 资源管理器 API 交互时,有一个基本规则——拥有“读者”角色的身份可以执行所有 GET 请求。如果尝试执行 POST 请求,则会立即因权限不足而被拒绝。
    • 代码示例:一个不存在的资源 GET 请求返回“未找到”,而 POST 请求则直接返回“授权失败”。
  2. ARM 统一处理认证授权:ARM 在所有端点上进行身份验证和授权检查。通过检查后,ARM 会使用一个拥有该资源完全控制权的系统令牌去查询后端服务。
    • 公式表示:用户请求 -> ARM(角色检查)-> 后端服务(使用高权限系统令牌)

这种模型有时会出错,例如过去存在的漏洞:GET /functions/admin/token 端点。本应需要管理员权限,但由于 ARM 开发者直接复制了后端 API 而忘了添加权限检查,导致读者角色也能调用并获取到 Web 应用的管理员令牌,从而获得远程代码执行权限。

漏洞利用:敏感的 GET 请求

回到 API 连接的问题。我们现在知道:

  1. 我们通过 API 连接建立时的令牌来查询后端服务。
  2. 我们可以执行所有 GET 请求。

那么,关键就在于:世界上是否存在一些后端服务,其 GET 请求本身是敏感的? 答案是肯定的。

以下是几个例子:

  • Azure SQL 数据库:通过特定 GET 请求,可以读取数据库中的所有数据。
  • Jira:Jira 连接器需要知道 Jira 实例的地址。这个地址不是设置在连接中,而是通过一个特殊的 HTTP 头 X-Atlassian-Host 在每次请求中传递。通过构造 GET 请求获取此信息,攻击者就能获得 API 密钥,从而完全控制 Jira 实例。
  • Azure Key Vault:这是最严重的案例。Key Vault 用于存储最敏感的密钥、密码和证书。通过 API 连接的 GET 请求,低权限的“读者”可以直接读取 Key Vault 中的所有秘密

我将通用案例和 Jira 的特殊案例分别报告给微软。一周后,他们修复了通用案例,并关闭了 Jira 的报告称无法复现。几周后,他们告知已知晓此漏洞数月。

他们的修复方式是:现在尝试调用 extensions/proxy/{endpoint} 会被阻止,只允许调用明确定义的“测试连接”URL(例如 Slack 的 conversations.list)。他们采用了白名单机制来限制路径。

发现更严重的漏洞:动态调用端点

通用漏洞被修复后,我们思考能否发现更严重的问题。回顾架构图,我们发现另一个有趣的未文档化端点:dynamicInvoke

这是一个 POST 请求。根据 Azure 安全模型,执行 POST 请求需要“所有者”或“贡献者”权限。这意味着它不能用于租户内的本地权限提升(因为如果你已经是所有者,权限本来就很高)。其请求体如下:

{
  "method": "GET",
  "path": "/conversations.list"
}

以所有者身份调用,会返回与测试链接相同的结果。但核心问题是:我们是否仍被限制在“测试连接”的范围内? 幸运的是,答案是否定的。我们可以调用 Swagger 中定义的任何端点。

虽然这本身可能是一个漏洞(例如,贡献者角色就能读取 Key Vault 所有秘密,这通常需要特定角色),但严重性有限,因为攻击者已经需要是资源的所有者/贡献者。

然而,这个端点有一个危险特性:它允许在请求体(而非 URI)中指定路径参数。这在 Azure 中很罕见,因为一旦被利用,后果可能是灾难性的。

路径遍历与跨租户攻击

攻击者可以创建一个自定义连接器,并定义一个包含路径参数的端点,例如 /extensions/path/{parameter}

攻击思路是进行路径遍历:在 {parameter} 中注入类似 ../../../{victim-connection-id}/secrets 的路径。攻击流程如下:

  1. 攻击者在自己的租户中创建自定义连接器。
  2. 攻击者构造请求,通过 dynamicInvoke 调用自己的连接器,并在路径参数中注入指向受害者租户中某个 API 连接(如 Key Vault 连接器)的路径。
  3. Azure 资源管理器进行角色检查(攻击者是自定义连接器的所有者,通过)。
  4. ARM 进行路径验证(路径在 Swagger 中定义,通过)。
  5. ARM 将拼接后的路径(包含攻击者的连接 ID 和遍历后的受害者路径)发送给 Azure API 管理服务。
  6. API 管理服务解析路径,错误地将其路由到受害者的连接,并使用受害者连接的令牌执行操作(如列出 Key Vault 秘密)。

实际利用演示:

  1. 受害者租户中有一个 Key Vault 和一个连接到它的 API 连接。
  2. 攻击者在自己的租户中创建自定义连接器。
  3. 攻击者调用 dynamicInvoke,路径参数为:../../../{victim-connection-id}/secrets
  4. 成功列出受害者 Key Vault 中的所有秘密名称。
  5. 进一步,可以获取特定秘密的值。


这实现了一种完全未经认证的跨租户密钥/秘密泄露。

我将此漏洞报告给微软,他们在约两天内修复了它,并最终奖励了 40,000 美元。修复方式是黑名单机制,阻止了包含 ../ 的路径遍历。

总结与启示

本节课中我们一起学习了 Azure API 连接中一系列安全漏洞的发现与利用过程。

核心要点总结:

  1. 初始漏洞:低权限“读者”角色可通过 ARM 代理调用 API 连接的“测试”端点,从而以连接建立时的身份访问后端服务(如 SQL、Jira、Key Vault),导致敏感信息泄露。
  2. 深层漏洞:“所有者/贡献者”可用的 dynamicInvoke 端点存在路径遍历缺陷,允许攻击者跨租户访问其他用户的 API 连接,造成严重的跨租户数据泄露。
  3. 根本原因:Azure 安全模型(读者可执行所有 GET 请求)与 API 连接架构(ARM 拥有连接 ACL 访问权、后端服务存在敏感 GET 操作)的结合缺陷。
  4. 修复方式:微软采用了白名单(限制可调用的测试路径)和黑名单(阻止路径遍历字符)的方式进行修补,但未发布安全公告或 CVE。

重要启示:

  • 理解架构是关键:攻击云服务并非黑魔法。深入理解其安全模型和常见架构模式,能帮助你快速识别潜在漏洞。
  • 沉默的修复:此类严重漏洞的修复可能是静默的,没有公告、没有 CVE。用户无法知晓自己是否曾受影响,或是否需要轮换凭据。这凸显了主动安全评估和监控的重要性。


Q&A 环节

问: 当攻击者读取受害者密钥时,受害者的日志会如何记录?受害者能否察觉到异常?

答: 日志会显示 API 连接访问了 Key Vault。但这看起来是预期的行为,因为受害者的逻辑应用本身运行时也可能访问 Key Vault。关键在于,日志会记录是哪个身份执行了访问。在这个漏洞中,访问会显示为受害者自己的逻辑应用或 API 连接身份进行的,因此从日志上看,就像是一次合法的、由受害者自身资源发起的访问,很难直接区分恶意行为。

回到未来:基于连接的OAuth架构的攻击与防护 [__NtTfL0oPw]

在本课程中,我们将学习一种新兴的、基于连接的OAuth架构。这种架构被广泛应用于AI代理和集成平台,旨在简化第三方开发者的OAuth集成工作。然而,我们将看到,这种新架构也带来了新的安全挑战,使得一些经典的Web攻击(如会话固定、开放重定向和混淆代理)得以重现,可能导致严重的账户接管和数据泄露。

背景:AI代理与集成平台生态

在生成式AI兴起之前,用户已经可以使用由亚马逊、谷歌、微软等大型提供商构建的集成平台来控制外部应用程序或工具,以完成任务或编排更复杂的流程。

如今,随着我们进入AI代理时代,除了少数大型集成平台,还将出现大量由第三方开发者开发的AI代理。许多公司正忙于构建所谓的“AI代理平台”,以帮助第三方开发者开发这些AI代理。

在这种背景下,用户可以将控制和编排任务委托给大型集成平台以及第三方AI代理,以自动化日益复杂的任务。但我们必须确保只有经过授权的代理或集成平台才能代表用户访问和控制这些工具。这就需要委托授权机制。

在业界,OAuth是委托授权的标准。因此,无论是集成平台还是第三方代理,都需要依赖OAuth来实现授权。然而,众所周知,OAuth并不简单。特别是在将这些新用例应用于构建安全系统时,并不像看起来那么容易。

事实上,在去年的Black Hat USA 2024上,我们已经分享了我们的发现:当OAuth被应用于集成平台时,出现了许多新的相关漏洞。我们发现了三种基于虚假账户或账户错误链接的新型攻击,可能导致一键账户接管或隐私泄露。在我们研究的25个平台中,有24个被发现至少存在一种新型漏洞。这些受影响的平台横跨不同应用领域,包括智能家居、物联网、虚拟语音助手、工作流自动化以及支持低代码/无代码的服务。许多易受攻击的平台拥有超过1亿的活跃用户。这实际上表明,即使是大公司,要正确实施OAuth也并不容易。

随着AI代理的激增,我们将看到更多由第三方开发者开发的代理,问题可能会变得更糟。毕竟,第三方开发者可能不像大型集成平台提供商那样资源丰富或拥有OAuth方面的技术专长。

为了将第三方开发者从OAuth的复杂性中解放出来,业界出现了一种向“OAuth即服务”架构的范式转变。在这种方法下,我们可以将OAuth令牌管理的复杂性从大量第三方代理卸载到一个由AI代理平台运营的安全令牌管理器上。

在业界,我们已经看到了例子。例如,微软现在至少提供两种安全令牌管理器,分别名为Bot Framework令牌服务和凭证管理器,用于支持AI代理平台和集成平台。其他地方也有其他公司和初创公司提供类似的OAuth即服务架构,以方便第三方开发者更容易地构建他们的代理。典型的服务包括软件开发工具包、开发门户以及由公司运营的令牌管理器。通常,这些服务还包括支持流行工具的预构建软件模块。有些平台还在其平台下拥有自己的第一方代理应用程序。

这种OAuth即服务架构也与流行的模型上下文协议相关。毕竟,MCP最初是由Anthropic提出的,旨在支持在大型语言模型中使用。在原始的MCP架构中,由Claude Desktop等托管的MCP密钥库负责存储和管理所有工具的OAuth复杂性。但现在,在MCP社区中已经有一个新的提议,建议将令牌管理从MCP客户端卸载到由单个MCP服务器实现的令牌管理器。从这个意义上说,这种OAuth即服务架构无处不在。

听起来,OAuth即服务似乎很好。我们可以集中处理一些复杂性,并将其交给更有资源的构建者来实现。一切听起来都不错,但实际上并非如此。因为新的OAuth即服务架构也带来了自身的安全挑战。

具体来说,在这种架构出现之前,集成平台只需要扮演OAuth客户端的角色并在标准框架下实现OAuth。开发者基本上可以遵循OAuth标准来构建安全系统以管理OAuth授权。然而,在新的OAuth即服务架构下,标准框架中OAuth客户端的功能被拆分到了两个实体之间:第三方AI代理和安全令牌管理器。问题在于,如何拆分这些功能超出了OAuth标准的范围。因此,不同的AI代理平台需要推出自己的专有设计。不出所料,我们发现它们犯了错误,实际上引入了新的、关键的OAuth相关漏洞。

事实上,我们将与大家分享和解释的是我们的新发现。我们发现,一些被OAuth标准仔细处理的经典Web攻击,现在在这种OAuth即服务架构下重新显现。特别是,这些经典Web攻击包括会话固定、开放重定向以及不同类型的混淆代理。在我们的研究中,我们调查了七家不同的AI代理平台供应商,发现了许多漏洞实例,涉及跨用户攻击、跨代理攻击和跨工具攻击。所有这些都可能导致受害者的账户被接管。

技术细节:OAuth基础与基于连接的架构

现在,让我们深入了解技术细节。首先,从一些基本的OAuth术语开始。

传统上,如果你构建一个需要从工具(如Dropbox)获取令牌的代理,你需要设置一个OAuth客户端来管理令牌,而工具方则运行一个授权服务器来颁发这些令牌。你的代理(OAuth客户端)会将令牌发送回Dropbox的资源服务器以进行API调用。

但在这种新的OAuth即服务范式中,OAuth的角色保持不变。但由于OAuth客户端角色在代理和令牌管理器之间被拆分,关键问题在于:这两个实体如何协商?它们如何协调?

这里有两种潜在的解决方案。第一种解决方案是,我们只是将OAuth流程并排链接起来。我们在令牌管理器与工具之间重复OAuth模式,并让代理和令牌管理器之间也进行OAuth通信。这种方法的好处是,代理现在只需要与令牌管理器建立OAuth关系。但其局限性也很明显:代理仍然需要实现OAuth客户端并安全地管理令牌。人们称这种模式为“代理OAuth”。

另一种解决方案是,人们尝试发明一些基于OAuth连接概念的新东西,这是一些OAuth服务提供商引入的专有附加组件。其高层次思想是:令牌管理器不返回令牌(这是代理需要保密的密钥),而是简单地返回每个令牌的ID,即连接ID。这种架构的关键好处是,OAuth逻辑完全从代理端抽象出来,令牌管理器将为代理完全处理令牌的整个生命周期。我们称这种架构为基于连接的OAuth架构,这也将是我们讨论的重点。实际上,我们到目前为止提到的所有供应商示例都采用了这第二种方法。

更正式地说,连接被定义为一个用于管理OAuth令牌的预配置句柄。至少,它将包含一个三元组的信息:工具、代理和用户。这是因为这些是满足基本用例(代理代表任何用户调用工具如Dropbox)所必需的信息。这个三元组作为元数据在连接中被跟踪,并由一个连接ID(如数据库主键)管理。连接内部就是这个被管理的OAuth令牌。

在我们深入探讨OAuth如何与这个连接概念协同工作之前,让我们先退一步,弄清楚在没有连接的情况下,OAuth流程应该如何工作。

在幕后,它是这样进行的:首先,最终用户通常会通过Web浏览器参与OAuth。当用户点击连接按钮开始OAuth时,实现OAuth客户端的代理后端会发出一个OAuth授权URL并将其传回浏览器。这简称为OAuth URL。遵循OAuth URL,浏览器将访问Dropbox.com/authorize,这是Dropbox的授权服务器。最终用户需要登录Dropbox并提供其同意,点击授权按钮。但这种显式授权并不总是必需的。例如,如果你之前已经登录并授权过,那么下次遇到同一个工具时,同意很可能会自动完成。请记住这个设置,因为它将是许多强大隐蔽攻击的基石。在这个授权步骤之后,Dropbox将获取一个授权码,并通过浏览器重定向将其传递到由代理后端设置的回调地址。在这个过程中,还会涉及另一个名为state的OAuth参数,用于跟踪会话状态。然后是代码交换阶段,授权码将被交换为访问令牌,该令牌存储在代理后端。这样就完成了OAuth流程。因为每个代理都可以有自己的最终用户,所以浏览器中的用户会话将用于将令牌绑定到特定用户的身份。

现在,让我们转向新的基于连接的OAuth架构。在基于连接的OAuth中,有三个阶段:OAuth前、OAuth中和OAuth后。在OAuth前阶段,代理首先请求新连接,并将三元组(工具、代理、用户)的信息传递给令牌管理器。令牌管理器将生成一个新连接,但由于OAuth尚未完成,它将是一个空连接。这个新的连接ID和OAuth URL将在响应中返回。遵循OAuth URL,将建立OAuth流程,最终,一个访问令牌将占据连接中的这个空位。在OAuth后阶段,代理将使用此连接进行授权的API调用。

将连接概念融入OAuth后,整个流程如下所示:这是传统的OAuth流程(步骤1到5)。现在,我们将连接部分置于OAuth流程中。我们得到的就是基于连接的OAuth在正常协调下的工作方式。

从代理的角度来看,每当它收到最终用户开始OAuth的请求时,它只需查询令牌管理器以生成OAuth URL,然后将URL传回给用户,并等待用户完成OAuth流程。

从令牌管理器的角度来看,连接概念在OAuth流程中体现为授权会话,以便即使在用户的浏览器中也能跟踪连接。通常,这个授权会话由OAuth中的state参数维护。

从最终用户的角度来看,用户体验与传统OAuth没有区别。

但事实证明,这种正常的协调在设计上也是不安全的。为什么会这样?现在,我们从第一种攻击开始。

攻击一:会话固定

作为代理的最终用户,我期望我的授权不会流向由同一代理服务的另一个最终用户。但在现实中,这种期望会被一种称为会话固定的攻击所打破。

会话固定是Web安全中的一种经典攻击,攻击者可以将其自己的会话ID固定给受害者,并迫使受害者在该会话ID下进行身份验证。这样,攻击者就可以接管受害者的账户。在基于连接的OAuth中,回想一下,连接在OAuth期间体现为授权会话。所以我们实际上已经有了会话的概念。但固定部分呢?

当攻击者发起OAuth时,会返回一个OAuth URL,这标志着攻击者的连接和会话。现在攻击者要做的是:简单地将这个OAuth URL分享给受害者。例如,Dropbox.com/authorize 带有一些OAuth参数,然后让受害者自动完成剩余的OAuth流程。因为这里的授权会话属于攻击者,所以受害者的OAuth令牌最终会链接到攻击者的连接。结果,攻击者可以接管受害者的工具账户(如Dropbox访问权限)。这就是会话固定攻击的工作原理。

我们发现有五家供应商容易受到这种攻击。

在会话固定攻击中,是攻击者发起OAuth,但却是受害者实际完成OAuth。因此,为了防御这种漏洞,高层次的想法是:我们需要验证发起OAuth的用户与完成OAuth的用户是同一人。更具体地说,就是强制要求尝试生成此OAuth URL并进行后续OAuth流程的始终是同一个人。

但要实际实现这个高级防御思想,仍然有点棘手。因为,我们再次面临令牌管理器和代理后端之间的拆分。我们所知的原始重定向无法确定哪个用户实际完成了OAuth,因为它会重定向到这个令牌管理器。令牌管理器被设计为仅处理OAuth。它对所有其他代理特定逻辑(例如用户会话)是不可知的。

所以,这里的修复思路是:令牌管理器需要额外重定向回代理后端。然后代理后端可以从用户会话中提取用户ID以进行验证。我们称这种防御为“后重定向”模式。

这里我们提供了两种实现相同防御思路的替代方案。现在先跳过最终细节,但欢迎稍后回顾。

这里的关键要点是:正如你所见,即使在这个旨在完全解耦OAuth的基于连接的OAuth架构中,出于安全目的,代理后端仍然需要承担一些OAuth责任。

总结一下,我们在基于连接的OAuth中看到了会话固定的可能性。实际上,如果下游工具授权是通过简单地分发OAuth URL启用的,那么在MCP中也可以观察到类似的模式。如果你不验证用户身份的一致性,会话固定攻击也同样适用。

攻击二:开放重定向

开放重定向是另一种经典的Web攻击,其中网站的重定向功能会接受用户控制的输入,攻击者可以利用它将最终用户重定向到不受信任的位置。

在基于连接的OAuth中,当令牌管理器试图缓解会话固定攻击时,可能会出现开放重定向漏洞。它试图缓解之前的攻击。

回想一下,会话固定防御的实现要求令牌管理器向代理后端发出第二次重定向。但令牌管理器如何知道应该重定向到代理后端的哪个确切端点?一种常见的方法是从浏览器传递此信息。这可能会打开开放重定向的可能性,因为现在我们有了一个用户控制的输入。

攻击者会这样做:它会发起OAuth。但对于会话固定防御部分,它会指定一个攻击者控制的位置作为后重定向URL,而不是任何预定义的值。然后,像会话固定攻击一样,攻击者会简单地将OAuth链接分享给受害者,受害者将完成OAuth流程。现在,由于会话固定防御,这个令牌管理器将重定向到攻击者控制的位置。这就是OAuth凭证可能泄露给攻击者的方式。

对于开放重定向,我们在微软发现了两个攻击实例。事实证明,微软只使用通配符检查了后重定向URL。因此,我们可以将后重定向指向一个在微软域上存在跨站脚本漏洞或postMessage漏洞的地方,这都将允许攻击者最终窃取受害者的OAuth凭证。

现在,让我们看看如何利用这个开放重定向与跨站脚本来窃取Microsoft Power Automate和Power Apps中的Outlook电子邮件。

首先,我们幸运地在ideas.powerapps.com上发现了一个跨站脚本漏洞。这是Power Apps社区论坛的域名。它与OAuth后重定向URL共享相同的根域,但子域不同。攻击者可以将恶意脚本作为帖子评论注入。但在这里,我们不会直接窃取这个问答网站的cookie,因为影响较小。相反,我们会将任何URL参数转发到攻击者的站点。

然后,我们将它与OAuth漏洞结合起来。在OAuth期间,我们启动一个新连接。攻击者会将此后重定向URL设置为那个跨站脚本页面的URL。由于微软的令牌管理器只进行通配符匹配,这个新的、被操纵的后重定向URL也会被接受。

现在攻击者要做的是:复制那个OAuth URL,然后撰写一封钓鱼邮件,发送给受害者。然后,受害者会被诱骗点击。受害者将自动跳转到被操纵的后重定向位置,这将触发恶意JavaScript,将受害者的授权码泄露给攻击者。这就是受害者的授权码可能泄露的方式。之后,攻击者可以用这个被盗的代码兑换访问令牌,并导致这个带有受害者令牌的被盗连接。

接下来,攻击者将使用这个被盗的连接与Outlook电子邮件工具,从受害者的邮箱中泄露电子邮件。我们可以看到电子邮件被泄露。现在,任务完成。

作为防御,它要求令牌管理器严格验证后重定向是否被允许,或者甚至不将此后重定向URL暴露给前端,而是将其预配置在后端,这样就不会有用户控制的输入用于重定向。

反思一下OAuth中的开放重定向攻击,在OAuth中实际上已经存在一个常见的开放重定向来源,即从Dropbox到令牌管理器或OAuth客户端的第一次重定向。但在这里,我们想强调这第二次从令牌管理器到代理后端的后重定向。在实现这种会话固定防御时,可能会进一步暴露开放重定向漏洞。

攻击三:混淆代理

接下来,让我们转向一种新的攻击类别:混淆代理。在传统的Web安全中,混淆代理是一种非常广泛的攻击类型,其中特权实体会被攻击者混淆,并有意地转发请求。在这个服务中,我们确定了两种混淆场景。如果原本打算授权给一个代理的授权,却被授予并仅授予了另一个代理,会怎样?同时,如果我对一个工具的授权被令牌管理器转发给了另一个工具,又会怎样?

让我们首先关注不同代理之间的混淆。

从这个服务的商业模式角度思考:它能帮助代理开发者减轻OAuth负担越多越好。除了管理OAuth令牌,我还能提供什么?

这就引出了OAuth中预注册的概念。传统上,在用户实际运行OAuth流程之前,代理开发者需要首先与工具方沟通,例如与Dropbox沟通,请求一对唯一的ID和密钥。这个由工具方颁发的客户端ID用于在OAuth流程中识别代理。

但你知道吗?作为一种服务,我们在这里看到的是,一些提供商会与许多常见工具(如Dropbox、Outlook、GitHub或Google Calendar)进行OAuth注册,而代理开发者则不需要这样做。现在,不是每个代理都注册运行自己的客户端ID,而是多个代理共享由令牌管理器提供的相同客户端ID。

但这种设计存在一个关键缺陷,可能被升级为一种攻击,我们称之为“客户端ID混淆”。假设我作为一个最终用户,首先在一个我信任的代理中授权了Dropbox。但在幕后,我实际上是将访问权限和同意授予了令牌管理器上的那个Dropbox客户端ID。

后来,当我遇到一个也想要Dropbox访问权限的恶意代理时,尽管我本意上想保持警惕,但在幕后,我仍然在授权同一个令牌管理器的客户端ID,而我已经授予了同意。因此,Dropbox访问权限将自动授予这个恶意代理。

作为防御,我们要求令牌管理器最好不要为代理提供共享的客户端ID,而是让每个代理自己注册客户端。

攻击四:跨工具混淆

最后的攻击形式是不同工具之间的混淆。去年在黑帽大会上,我们展示了集成平台中的一个攻击向量,称为“跨应用OAuth账户接管”。其高层次思想是:在集成平台中,一个混淆代理可能会将受害者对良性工具(如Dropbox)的授权代码泄露给恶意工具。这种攻击要求平台本身有一个开放的市场,以便攻击者可以渗透一个恶意工具。

但现在,有了OAuth即服务支持的多个第三方代理,攻击者总是可以使用一个携带恶意工具的恶意代理来针对受害者代理中的良性工具。因此,现在恶意工具的存在不再依赖于受害者代理或平台的开放市场。

我们在业界发现了六个易受攻击的实例,它们容易受到这种跨代理版本的代码攻击。

作为这种代码攻击的案例研究,我们在Microsoft Copilot Studio中发现了一个严重的漏洞。在Copilot Studio中,每个代理被称为一个“copilot”。有趣的是,微软已经扩展了这个令牌管理器以支持用户身份验证。换句话说,你可以使用这个令牌管理器进行更细粒度的访问控制,以配置谁可以访问你的代理。

因此,这种跨代理代码攻击会变成:我可以使用一个恶意copilot并配置一个恶意身份提供商,来登录互联网上任意经过良好身份验证的copilot。

要发起此攻击,首先,攻击者会尝试登录受害者的Copilot碰碰运气。不幸的是,他会被阻止,因为受害者的Copilot只配置为在受害者自己的租户或组织内使用。所以攻击者是外部人员,自然无法登录。

但攻击者会这样做:他会在他的恶意copilot中设置这些恶意的授权服务器端点,这些端点将针对受害者copilot中的受害者工具或身份提供商。这与跨代理代码攻击的设置相符。

现在,攻击者将获取一个新的OAuth URL,使用他的恶意copilot与他的恶意身份提供商进行OAuth。他会将他的URL发送给受害者并诱使他点击。一旦受害者点击,他将被自动重定向,并将其copilot的OAuth凭证泄露给攻击者。然后,利用这个被盗的OAuth凭证,攻击者可以获得一个访问令牌,从而以受害者的身份登录到受害者的copilot中。

本质上,受害者只需点击一次超链接,没有任何特殊权限的攻击者就可以发起跨代理、跨工具的账户接管。在微软的背景下,这就是用于在受害者租

BitUnlocker:利用Windows恢复环境提取BitLocker密钥 [课程 2CJl6mTtgws] 🔓

在本课程中,我们将学习如何通过攻击Windows恢复环境来绕过BitLocker加密,并提取受保护的数据。我们将从研究背景开始,概述BitLocker和Windows恢复环境,然后深入探讨我们发现的漏洞、利用方法,最后总结研究成果、修复措施以及可行的BitLocker防护对策。

研究背景

今天,我们将探讨一项旨在保护设备上敏感数据的安全功能。它旨在防御攻击者窃取笔记本电脑、提取敏感信息、入侵机器甚至植入后门的场景。

数据静止保护功能确保即使您的笔记本电脑被盗,您的数据也保持加密和不可访问状态,您的系统也保持未被篡改。

统计数据表明,笔记本电脑失窃的风险和成本不容忽视,这凸显了数据静止保护功能的重要性。因此,我们开始了攻击和保护BitLocker的旅程,这是Windows的数据静止保护功能。

BitLocker是一种全卷加密技术,旨在保护单个磁盘卷。启用后,它会加密目标磁盘卷,保护存储在该卷上的所有数据。默认情况下,BitLocker以操作系统卷为目标,确保存储在操作系统环境中的所有数据都受到保护。

在BitLocker加密下,即使您的笔记本电脑被盗,受保护的数据也因加密而无法读取。BitLocker的威胁模型假设攻击者类似于普通窃贼,即拥有对设备的完全物理访问权限,但没有高级凭据(如用户名或密码)。

自然地,BitLocker的攻击面是由在此威胁模型内可访问的接口所塑造的。在我们检查不同的攻击面时,有一个攻击面因其巨大的漏洞潜力而脱颖而出,但在先前的研究中却很少受到关注。

这个攻击面就是Windows恢复环境,也称为WinRE。

任何BitLocker攻击者都可以通过在登录屏幕选择重启时按住Shift键,直接启动到WinRE。这使其成为一个值得深入检查的潜在目标。

鉴于WinRE符合BitLocker的威胁模型、先前研究的缺乏以及其高漏洞潜力,我们决定进行一次专门的安全审查,旨在发现新漏洞、利用它们、修复它们,然后加固WinRE并减少其暴露的攻击面。

我们安全审查的目标是使WinRE和BitLocker都更加安全和具有弹性。

深入了解WinRE

上一节我们介绍了研究背景,本节中我们来看看WinRE是什么、它如何运作,以及哪些领域为漏洞研究提供了最有希望的机会。

WinRE是Windows的恢复平台。它旨在解决关键系统问题,例如启动失败、系统崩溃、BitLocker错误等。例如,如果您的机器崩溃,WinRE负责分析问题、识别损坏并使用其恢复工具进行解决。

从架构上讲,WinRE运行在自己的独立操作系统上,称为恢复操作系统。恢复操作系统是Windows的精简版本,具有恢复特定的自定义设置。这些自定义设置包括一组独特的恢复工具,这些工具都集成在众所周知的蓝色屏幕恢复用户界面中。

在存储方面,整个恢复操作系统,包括所有可执行文件、DLL和驱动程序等系统文件,基本上都被压缩到一个名为Winre.wim的单个WIM文件中。

这个WIM文件存储在磁盘上。当WinRE启动时,整个WIM文件被解压缩到内存中,创建一个承载恢复操作系统运行时的临时内存盘。

在此环境中进行的任何更改都不会保存回原始的winre.wim文件,使得恢复操作系统运行时本质上是易失的。对内存盘的修改在重启时会被丢弃。

当BitLocker首次引入时,WinRE必须演进以支持从BitLocker相关故障中恢复。这导致了一些架构和设计上的更改,以实现BitLocker恢复功能。我们想知道这些更改产生了什么影响。让我们更仔细地看看它们。

第一个设计更改侧重于winre.wim文件的位置。它从位于操作系统卷(现在被BitLocker加密)中,移到了位于一个专用的恢复卷中。

这个变更是必要的,因为WinRE必须能够从BitLocker相关故障中恢复。如果操作系统卷被加密并因解密失败而变得不可访问,将WinRE存储在那里会阻碍恢复。

由于WinRE是一个必须始终可用的关键组件,它被移到了一个单独的恢复卷。这确保了即使操作系统卷不可访问,WinRE也能正常运行。

第二个设计更改侧重于Winre.wim文件的完整性。为了支持对winre.wim的完整性验证,引入了名为“可信WinRE启动”的功能。它通过将其哈希值与已知的可信哈希值进行比较来验证WinRE的完整性。

如果哈希值匹配,操作系统卷会自动解锁。如果哈希值不匹配,操作系统保持锁定。这两种状态——自动解锁和锁定——定义了WinRE对操作系统卷的访问级别。

在自动解锁状态下,WinRE对操作系统卷拥有完全访问权限,无需任何用户干预即可执行恢复操作。而在锁定状态下,WinRE对操作系统卷完全没有访问权限。

这个变更,即引入可信WinRE启动,是必要的,因为WinRE现在位于不受保护的恢复卷上,不能再被盲目信任。可信WinRE启动确保对winre.wim的任何未经授权的修改(例如由物理攻击者进行的修改)都会破坏信任,从而有效阻止任何篡改。

第三个设计更改侧重于限制那些对BitLocker来说本质上具有风险的恢复工具。例如,在恢复工具中有一个命令提示符。

为了防止攻击者滥用命令提示符访问BitLocker保护的数据,在WinRE中添加了卷重新锁定功能。每次选择有风险的恢复工具时都会触发此功能,它会重新锁定操作系统卷。

因此,要重新获得对操作系统卷的访问权限,用户必须手动插入BitLocker恢复密钥。否则,所有内容都完全无法访问。

总结这些设计更改的影响:只要winre.wim是可信的且没有触发有风险的恢复工具,操作系统卷就会自动解锁,允许WinRE无需用户干预即可恢复它。

相反,如果winre.wim被未经授权地修改,或者触发了有风险的恢复工具,操作系统卷就会被重新锁定,阻止WinRE访问它。

现在,关键问题出现了:由于这些设计调整,暴露了哪些攻击面?事实证明,在自动解锁状态下,WinRE会解析来自不受保护卷(特别是EFI系统分区和恢复卷)的文件。这种解析呈现了一个非常有趣的攻击面,在BitLocker引入之前,这个攻击面没有多大价值,因为在BitLocker之前,即使在WinRE内获得完全代码执行,也不会赋予物理攻击者任何新能力。

相比之下,有了BitLocker,在自动解锁状态下,WinRE内的任何代码执行都可以被用来绕过BitLocker并提取所有受保护的密钥。

我们决定更深入地研究这些外部文件并检查解析过程。具体来说,我们今天将重点关注的这些文件是位于恢复卷中的raagent.xmlboot.sdi文件,以及位于EFI系统分区中的启动配置数据存储。

攻击外部文件解析

上一节我们介绍了WinRE的设计和潜在攻击面,本节中我们来看看针对这些外部文件的研究过程。

让我们从boot.sdi开始。SDI代表系统部署映像格式,它可选地用于从虚拟磁盘启动到内存中。这种格式由多个二进制块组成,其中某些块对于内存盘启动过程至关重要。

在我们的场景中,我们尝试从WIM文件启动到Windows恢复环境。boot.sdi将包含一个WIM块,其中包含指向附加的可信winre.wim的偏移量。此外,boot.sdi必须包含一个空的NTFS卷。这个空卷使得内存中的WIM能够作为NTFS卷呈现,确保与其他Windows组件的兼容性。

现在,让我们简要查看一下演示此过程的伪代码。

// 伪代码示例:加载SDI和WIM
size_sdi = GetFileSize("boot.sdi");
size_wim = GetFileSize("winre.wim");
buffer = AllocateMemory(size_sdi + size_wim);
CopyFileToBuffer("boot.sdi", buffer);
CopyFileToBuffer("winre.wim", buffer + size_sdi);
wim_hash = CalculateHash(buffer + size_sdi, size_wim);
if (wim_hash != trusted_hash) {
    LockOSVolume();
}
wim_address = buffer + ReadOffsetFromSDI(buffer);

值得注意的是,在用于验证的WIM和稍后执行的WIM之间没有验证链接,允许偏移量被任意设置。

考虑到这一点,让我们深入探讨我们的第一个漏洞。我们知道,当winre.wim紧接在SDI之后加载时,它必须通过哈希验证。然而,boot.sdi本身完全没有经过任何验证。由于我们可以操纵WIM偏移量指向任意位置,我们可以将不受信任的WIM附加到SDI,并调整偏移量指向它。

对可信WIM的验证将会成功,但不受信任的WIM将被执行。这允许我们加载和执行我们选择的任何WIM,同时保持操作系统卷仍处于解锁状态。

现在,让我们看看第一个漏洞的演示。这是一台锁定的机器,我们没有它的密码。我们按住Shift键选择重启以启动到WinRE。在WinRE内部,我们将运行我们预先准备好的漏洞利用程序。在启动过程中,主操作系统卷被BitLocker自动解锁。

我们到达WinRE操作界面。我们选择“疑难解答”,然后选择“高级选项”,再选择“命令提示符”。现在主操作系统卷被重新锁定,需要密钥。我们没有密钥,所以我们跳过这个驱动器。

现在我们尝试访问C盘,但无法访问,提示被BitLocker锁定。如果我们检查BitLocker状态,会看到它显示为锁定。现在,我们将路径更改为D盘,即已挂载的恢复卷(不受保护的卷)。我们执行预先准备好的漏洞利用程序。

我们将自定义WIM附加到boot.sdi,调整偏移量指向它。此时,我们只需将机器重启回WinRE。

现在,我们没有进入WinRE恢复用户界面操作,而是加载了自定义启动项,我们将其设置为启动CMD。这是CMD。我们可以将路径更改为C盘。

如果我们现在检查BitLocker状态,可以看到它显示为“已解锁”,并且其上的保护仍然开启。如果我们列出C盘下的所有文件,就可以查看所有机密信息。

完成对boot.sdi的审查后,我们将注意力转向raagent.xml以寻找漏洞。

raagent.xml文件包含当前的恢复状态和WinRE的其他配置设置。WinRE启动后,会立即使用和解析此XML文件。当WinRE状态配置为执行计划操作时,它将运行指定的恢复操作,例如启动修复或其他任务。所有这些都发生在到达之前看到的用户界面操作之前。

今天,我们将讨论两个可以通过修改raagent.xml中的状态来任意执行的计划恢复操作。首先是离线扫描,然后是WinRE应用程序。

从离线扫描操作开始。此操作允许从WinRE内部对主卷运行防病毒扫描。它主要用于对付不在WinRE内部运行的恶意软件。

我们发现我们可以控制扫描程序,但有一些限制。首先,离线扫描只能通过执行主操作系统卷内的应用程序来执行。其次,此应用程序必须由Microsoft或WHQL进行数字签名。第三,签名必须嵌入在二进制文件本身中。

我们搜索了所有满足这些要求的默认应用程序,发现了大约30个应用程序。CMD不在其中。由于兼容性原因,我们无法执行所有应用程序。

我们逐一审查它们,直到找到名为TTTracer的应用程序。这个应用程序是一个时间旅行调试器实用程序,允许跟踪任意可执行文件。如果我们能跟踪任何我们想要的东西,那就跟踪CMD吧。

现在,让我们回顾一下第二个漏洞的完整利用步骤。在启动机器之前,我们在raagent.xml中设置恢复状态以计划离线扫描操作。然后WinRE解析此XML。根据我们设置的状态,WinRE恢复执行计划的操作,即离线扫描。它将执行TTTracer,后者将跟踪您设置的任何二进制文件。我们指定了CMD。所以在我们的案例中,它将启动CMD。在这个特定时刻,当仍处于自动解锁状态时,我们拥有一个具有对完全未加密的主操作系统卷的访问权限的shell。

让我们看看第二个漏洞的快速演示。同样,这是一台锁定的机器,带有密码保护器,我们没有密码。我们再次按住Shift键重启以启动到WinRE执行我们的漏洞利用。

现在主操作系统卷被自动解锁。我们进入WinRE恢复操作界面,选择“疑难解答”,然后“高级选项”和“命令提示符”。

现在,主操作系统再次被锁定。我们没有密钥,所以跳过这个驱动器。如果我们尝试访问C盘,会提示该驱动器被BitLocker锁定。如果我们检查BitLocker状态,可以看到它显示为锁定。现在,我们将路径更改为D盘,即恢复卷(不受保护的卷)。我们将运行预先准备好的漏洞利用程序。我们设置TTTracer在离线扫描操作中被计划执行,并设置它来跟踪和运行CMD。漏洞利用完成后,我们将机器重启回WinRE。

但这次,我们没有看到之前看到的用户界面操作,而是看到了我们计划的应用程序TTTracer。这是TTTracer。它要求我们接受最终用户许可协议。我们接受它。之后,我们立即看到CMD正在启动。现在,我们可以更改驱动器。如果我们检查BitLocker状态,这里显示为“已解锁”,并且保护仍然开启。再次,如果我们列出C盘下的所有文件,就可以查看机密信息。

攻击WinRE应用程序

上一节我们介绍了离线扫描漏洞,本节我们来看看WinRE应用程序的漏洞。

我们可以配置的另一个计划操作是WinRE应用程序,它允许我们在WinRE内运行应用程序。如果这些应用程序是可信的,它们会在主操作系统卷仍处于自动解锁状态时执行。否则,它们会在主操作系统卷被重新锁定后运行。

我们寻找了哈希验证过程,发现可信应用程序使用其可执行文件名和文件哈希在WinRE注册表中注册。此注册表位于WIM文件内,物理攻击者无法修改它。对WIM的任何更改都会改变其哈希值,导致在启动哈希验证期间主操作系统卷被重新锁定。

当WinRE计划运行可信应用程序时,它首先计算目标应用程序的哈希值,然后在注册表中搜索匹配项。如果找到匹配项,应用程序被标记为可信。如果没有匹配项,应用程序被标记为不可信,主操作系统卷被重新锁定,之后该应用程序被执行。

总的来说,这听起来像是二进制可信应用程序验证是可靠的。它正常工作,对吧?我们想知道一个已注册的应用程序是否会暴露攻击面。所以我们开始寻找已注册的应用程序。

我们发现了一个名为SetupPlatform的程序对此功能的合法使用。此应用程序注册为可信应用程序,并在Windows升级期间使用。一旦升级完成,可信应用程序条目仍保留在注册表中,并且不会被删除。所以我们可以执行SetupPlatform。但我们还能用它做什么呢?

我们发现该注册表设置了F1热键来启动CMD。我们尝试了,但由于主操作系统卷上缺少配置而无法执行。由于此配置文件位于BitLocker保护的主操作系统卷上,我们无法创建或编辑它。这个配置要求导致SetupPlatform在文件不存在时提前终止。

现在,热键注册和进程退出之间的时间窗口非常短。手动使用此热键触发CMD几乎是不可能的。

我们仍然想找到另一种启动CMD的方法。所以我们回过头来分析SetupPlatform。就在这时,我们发现了一些非常有趣的事情。在注册了CMD热键之后,此应用程序立即在恢复卷(即不受保护的卷)上搜索setup.ini文件。通过正确配置此文件,SetupPlatform将触发一个消息框。这会阻止应用程序继续执行,本质上阻止了应用程序提前终止。

这将打开一个无限的时间窗口来生成CMD并在其中输入任何我们想要的内容。

让我们查看完整的流程。我们修改raagent.xml来设置计划执行WinRE应用程序,具体来说,我们设置执行SetupPlatform。WinRE验证此应用程序是否可信,验证成功,主操作系统卷保持解锁。接下来,SetupPlatform被执行。它注册了CMD的热键,即Shift+F1。然后它查找并加载setup.ini文件,这将触发一个消息框。这样,进程被阻塞,直到我们按下“确定”才会继续。现在,我们可以简单地按下Shift+F10来触发CMD。我们获得一个正在运行的shell,同时主操作系统卷仍然处于解锁状态。

让我们看看第三个漏洞的演示。同样,这是一台锁定的机器,我们没有它的密码。我们按住Shift键重启以启动到WinRE。

我们到达WinRE,选择“疑难解答”,然后“高级选项”,再选择“命令提示符”。现在,主操作系统再次被锁定。我们没有密钥,所以跳过这个驱动器。

我们再次尝试访问C盘,它被锁定。我们将检查BitLocker状态。再次,两者都显示为锁定。现在,我们将运行位于恢复卷(不受保护的卷)上的漏洞利用程序。我们将SetupPlatform设置为可信应用程序,并设置setup.ini文件。

漏洞利用完成后,我们重启机器。现在,我们没有看到之前看到的操作界面,而是期望出现来自SetupPlatform的消息框。这是消息框。现在,我们可以简单地按下Shift+F10,生成CMD。

我们可以将路径更改为C盘。如果我们检查BitLocker状态,可以看到保护仍然开启,并且卷已解锁。如果我们列出C盘下的文件,就可以再次查看所有机密信息。

攻击BCD解析

上一节我们介绍了WinRE应用程序的漏洞,本节我们来看看攻击WinRE中的BCD解析。

对于那些不熟悉BCD及其含义的人,BCD代表启动配置数据。它是定义Windows如何启动的文件。它存储启动条目、控制启动参数、恢复设置以及许多其他与启动相关的配置。

在WinRE的上下文中,BCD的使用相当有限。WinRE主要使用BCD来确定目标操作系统卷在磁盘上的位置,以便WinRE知道将恢复操作定向到哪个卷。当WinRE启动时,它读取BCD存储,从BCD中检索目标操作系统卷,然后将恢复操作定向到BCD指定的这个卷。

因此,当我们调查WinRE的BCD使用时,脑海中出现的第一个问题是:我们可能从中获得什么?事实证明,WinRE完全信任目标操作系统卷,假设它超出了攻击者的触及范围。从设计角度来看,这个假设实际上是可靠的,因为启用了BitLocker后,目标操作系统卷是加密的,攻击者无法访问它。因此,可以放心地查询其配置,假设它超出了攻击者的触及范围。

话虽如此,由于目标操作系统位置是在我们可以修改的BCD中定义的,我们开始质疑这个信任假设。BCD操作是否允许我们破坏它?如果我们能欺骗WinRE,让它认为一个攻击者控制的卷是可信的BitLocker加密卷,从而混淆WinRE,会怎么样?

因此,我们的重点转向识别一个允许冒充目标操作系统位置的原始方法。目标是操纵目标操作系统卷,使其指向攻击者控制的卷(例如恢复卷),而不是指向我们无法修改的可信BitLocker加密卷。但我们能修改恢复卷。我们获得的这个原始方法将打破信任假设。

我们已经知道目标操作系统位置是在BCD存储中控制的,我们可以直接修改它。那么,如果我们直接在BCD存储中更改位置会发生什么?理论上这是可能的,但没有价值。让我解释一下。

目标操作系统位置不仅被WinRE使用,还被启动管理器使用,启动管理器用它来知道应该为WinRE自动解锁哪个卷。对BCD存储的任何更改都会影响启动和操作系统两个方面。在这种特定情况下,将目标位置修改为指向恢复卷会阻止启动管理器自动解锁包含机密的BitLocker加密操作系统卷。而这些正是我们想要提取的机密。所以这打破了信任假设。但即使在WinRE内获得完全代码执行,BitLocker机密仍然无法访问且

Black Hat 简报会 演讲者指南 📋

在本教程中,我们将详细介绍Black Hat简报会演讲者需要了解的所有关键信息,包括虚拟平台使用、现场流程、演讲准备和活动细节。请仔细阅读并遵循指南,以确保活动顺利进行。


1. 虚拟平台与移动应用 📱

首先,我们将介绍本次会议使用的虚拟平台——移动应用程序。

您需要在应用商店搜索“Black Hat Events”并下载该应用。应用现已开放,您可以在其中查看会议内容。请使用您注册时提供的邮箱进行登录。

以下是使用移动应用的关键步骤:

  • 注册与登录:使用会议注册邮箱登录应用。
  • 更新个人资料:登录后,请立即进入个人资料页面,移除您的个人家庭住址信息,以防他人通过连接请求看到。
  • 管理可见性与会议:请勿将个人可见性设置为“关闭”,否则您的演讲将不会在应用中显示。您可以在“会议”选项卡中编辑您的空闲时间,并查看他人发送给您的会议请求。
  • 发送连接请求:如需联系他人,可浏览其个人资料并点击“发送连接请求”。

您也可以通过扫描屏幕上的二维码或访问指定链接来使用网页版应用。


2. 活动场地与日程 🗺️

上一节我们介绍了线上平台,本节中我们来看看线下活动的具体安排。

本次活动在曼德勒海湾酒店举行。会议简报室分布在三个楼层:

  • Level 0(北会议中心):包含简报室和总结交流室。
  • Level 1:设有主题演讲厅和商务展厅,无简报室。
  • Level 2 和 Level 3:设有多个主要的简报室。

活动日程概览如下:

  • 8月6日(周三):共6个时段,每时段9场简报;包含2场主题演讲和2场主舞台会议。
  • 8月7日(周四):共5个时段,每时段9场简报;包含5场主题演讲和2场主舞台会议。

您可以通过提供的链接查看详细日程。


3. 报到与证件领取 🎫

了解场地后,抵达现场的第一件事是领取参会证件。

请前往注册台,出示您注册确认邮件中的二维码以及带照片的身份证件。我们设有主注册台和位于酒店大堂的卫星注册台(开放时间较晚)。

如果您修改了注册信息以包含DC(媒体)证件,也可以在Black Hat活动现场指定柜台领取。


4. 演讲准备与现场流程 🎤

现在我们来了解作为演讲者最重要的环节——演讲准备和现场流程。

演讲者中心是您的核心报到点。您必须在演讲开始前45分钟抵达位于Level 2的Surf BC演讲者中心。我们的联络员会在此与您对接,并在演讲前约20分钟陪同您前往演讲室。

演讲彩排室位于Surf A,您可以通过提供的预订链接提前预约30分钟的时间段进行彩排。

关于视听设备,请注意:

  • 您将使用领夹式麦克风。
  • 现场提供提词器(信心监视器),方便您查看幻灯片和备注。
  • 请将演示视频嵌入PPT或存放在U盘中,切勿依赖现场Wi-Fi进行在线演示或播放网络视频
  • 建议您将演示文稿备份在U盘中,并打印演讲备注,以防笔记本电脑出现意外。

演讲结束后,请迅速离开房间以便下一场准备。您可以在总结交流室(Level 0的South Pacific D或Level 2的指定区域)继续与参会者深入讨论。


5. 重要规则与材料提交 📄

为了保证会议的专业性和一致性,请遵守以下核心规则。

公司标识:您的公司Logo仅允许出现在标题页之后的第一张幻灯片最后一张幻灯片上。请注意,标题页本身不计入。

幻灯片提交:请在演讲后尽快将最终版幻灯片以PDF格式发送给指定的工作人员。提交时请遵循邮件中指定的命名规范,例如:[日期]_[时间]_[您的姓名]_演讲标题.pdf。这有助于我们高效地将材料上传至会议平台,供参会者查阅。

字体与可读性:请确保幻灯片字体足够大,以便会场后排的观众也能清晰阅读。


6. 社交活动与后勤信息 🍽️

除了紧张的会议,我们也为您安排了一些社交活动。

周二晚上是活动密集的时段:

  1. Day Zero:大型交流活动。
  2. 演讲者招待会:在Level 3举行,提供小食和饮品。
  3. VIP派对:在Border Grill举行(仅限受邀者,不可携带同伴)。

周三则有商务展厅的展位巡游和欢迎招待会。

餐饮信息

  • 早餐位于主题演讲厅(Mandalay Bay Arena)外。
  • 午餐位于Level 1的Bayside D,靠近商务展厅。
  • 各简报楼层在会议间歇提供茶歇。

请务必全程佩戴您的参会证件。


7. 联络方式与紧急情况 📞

保持沟通畅通至关重要。

请务必将活动工作人员(Christina和Jen Hughes)的手机号码存入您的手机。如果您在演讲当天可能迟到,请务必提前通知我们。

如果您的手机号非美国号码,请告知我们最佳的联系方式(如WhatsApp),以便在紧急情况下能及时联系到您。


总结

本节课中,我们一起学习了Black Hat简报会演讲者需要掌握的完整流程:

  1. 如何使用会议移动应用。
  2. 熟悉曼德勒海湾酒店的场地布局与日程。
  3. 报到、领取证件的步骤。
  4. 演讲前45分钟必须抵达演讲者中心的核心流程。
  5. 关于幻灯片格式、公司标识、材料提交的重要规则。
  6. 会议期间的社交活动与后勤安排。
  7. 保存工作人员联系方式以备不时之需。

请提前做好准备,我们期待您的精彩演讲!

理解与防范网络钓鱼攻击 🎣

概述

在本节课中,我们将要学习网络钓鱼攻击的基本原理、常见手法以及如何有效地识别和防范这类攻击。网络钓鱼是黑客最常用的社会工程学手段之一,理解它对于保护个人和组织的数字安全至关重要。


什么是网络钓鱼? 🎣

网络钓鱼是一种通过伪装成可信实体(如银行、社交媒体或同事)来欺骗用户,诱使其点击恶意链接、下载有害附件或泄露敏感信息(如密码、信用卡号)的攻击方式。

上一节我们介绍了网络钓鱼的基本定义,本节中我们来看看攻击者通常如何实施这种攻击。


网络钓鱼的常见手法

攻击者会使用多种技术来让他们的骗局看起来更可信。以下是几种最常见的网络钓鱼手法:

  • 欺骗性邮件:攻击者发送伪装成来自合法公司或个人的电子邮件,邮件中通常包含一个指向虚假网站的链接。
  • 网站克隆:攻击者创建一个与真实网站(如网上银行登录页面)外观完全相同的虚假网站,以窃取用户输入的凭证。
  • 鱼叉式钓鱼:这是一种针对特定个人或组织的、高度定制化的网络钓鱼攻击,其成功率往往更高。
  • 短信钓鱼:通过手机短信发送恶意链接,通常简称为“Smishing”。

如何识别网络钓鱼企图? 🔍

识别网络钓鱼需要仔细观察细节。上一节我们了解了攻击手法,本节中我们来看看作为用户应该如何保持警惕。

保护自己的第一步是学会识别可疑迹象。请注意以下几点:

  1. 检查发件人地址:仔细查看发件人的电子邮件地址或电话号码,看是否有拼写错误或使用不常见的域名(例如,service@paypa1.com 而不是 service@paypal.com)。
  2. 警惕紧急或威胁性语言:如“您的账户将被关闭”、“立即验证您的身份”等,这是为了制造恐慌,让你来不及思考。
  3. 悬停查看链接:将鼠标指针悬停在邮件或信息中的链接上(不要点击),查看浏览器状态栏显示的实际URL地址是否与声称的网站一致。
    • 示例:链接文本显示为 www.google.com,但悬停后实际地址可能是 www.g00gle-login.bad-site.com
  4. 检查网站安全性:在输入任何信息前,确保网站使用HTTPS(地址栏有锁形图标),但请注意,这只是加密传输,并不代表网站本身是合法的。
  5. 留意语法和格式错误:官方通信通常经过严格校对,而钓鱼信息可能包含明显的拼写或语法错误。

核心防护措施:双因素认证(2FA) 🔑

在讨论了识别方法后,我们需要一个更强大的安全后盾。即使密码不幸泄露,也能增加一道关键防线。

双因素认证是为您的账户增加第二层保护的安全方法。它要求您在输入密码(第一因素)后,再提供一种只有您才拥有的东西(第二因素),例如:

  • 手机上生成的一次性验证码
  • 来自认证应用的推送通知
  • 物理安全密钥

核心概念公式
账户安全 = 您知道的信息(密码) + 您拥有的物品(手机/密钥)

启用2FA能极大降低账户被入侵的风险,因为攻击者仅获取密码是无法登录的。


总结

本节课中我们一起学习了网络钓鱼攻击的本质、其常见实施手法以及实用的识别技巧。关键要点在于:始终保持警惕,仔细核查信息的来源和细节,不要轻易点击不明链接或下载附件,并为所有重要账户启用双因素认证(2FA)。养成良好的安全习惯,是保护自己免受网络威胁的最有效方式。

Black Hat USA 2025 亮点回顾 [课程编号:okJJ14HKFZQ]

概述

在本节课中,我们将一起回顾 Black Hat USA 2025 大会上的核心亮点。我们将学习其中提到的关键概念,并通过简单的公式和代码示例来帮助理解,确保即使是初学者也能跟上节奏。


核心概念解析

上一节我们介绍了本课程的主题,本节中我们来看看其中涉及的一些核心技术点。理解这些基础是掌握后续内容的关键。

一个重要的概念是“初始化序列”,它在许多系统启动时扮演关键角色。我们可以用一个简单的伪代码公式来描述这个过程:

代码示例:初始化流程

系统启动 -> 加载配置 -> 执行初始化序列 -> 进入就绪状态

另一个核心思想是“节奏控制”,它强调处理过程应有适当的延迟或速度管理,以避免错误。这可以用以下逻辑表示:

逻辑公式:节奏控制

IF 处理速度 > 系统阈值 THEN 启用延迟 ELSE 继续执行

主要步骤与要点

理解了基本概念后,以下是实现或分析类似系统时需要关注的主要步骤列表。

操作步骤列表:

  1. 确认起始信号。
  2. 执行核心初始化循环。
  3. 在关键节点插入速度检查点。
  4. 验证最终输出状态。

总结

本节课中我们一起学习了 Black Hat USA 2025 的一个技术片段。我们解析了“初始化序列”和“节奏控制”这两个核心概念,并通过公式与代码进行了阐述。最后,我们列出了实现类似功能的关键步骤。希望这些内容能帮助你建立初步的理解。

三十年的网络安全演进与洞见 🔐

在本节课中,我们将跟随网络安全先驱米科·许珀宁的视角,回顾过去三十年间网络威胁的演变历程。我们将从早期的计算机病毒,一直探讨到当今由人工智能驱动的复杂攻击,并思考安全从业者应如何构建更具韧性的团队和防御体系。

概述:一个充满不确定性的时代

上一节我们介绍了课程背景,本节中我们来看看当前网络安全领域面临的宏观环境。我们正处在一个充满不确定性的时代。多种变革力量同时涌现,带来了前所未有的挑战。

以下是当前面临的主要挑战:

  • 人工智能的颠覆性影响:人工智能的潜力巨大,但其最终将如何颠覆现有格局尚不完全明确。
  • 大国竞争加剧:国家间的竞争日趋激烈,国家尊严等非完全理性的因素在决策中变得至关重要。
  • 新法规的出台:例如欧盟正在实施的《网络弹性法案》,首次将软件责任明确化,其具体影响仍在探索中。
  • 贸易不确定性:地缘政治事件(如关税调整)与突发事件(如自然灾害)可能同时发生,打乱全球供应链。
  • 社会因素与人才流动:社会环境的变迁促使人才重新评估工作与生活地点,引发全球人才竞争。
  • 技术的政治化:技术已深度融入社会各领域,采购、合作等商业决策不可避免地带有政治色彩。人工智能无法理解企业的核心使命和复杂的政治权衡,这些仍是需要人类做出的决策。

面对这种混沌环境,个人和组织需要像培养一个适应力强的孩子一样,注重灵活性、多语言能力、全球视野和跨文化适应力。对于企业和团队而言,这意味着需要构建强大的社区和团队韧性。

构建有韧性的团队与文化

上一节我们探讨了外部环境的挑战,本节中我们来看看如何从内部构建抵御这些挑战的基石。研究表明,联系紧密的社区能从灾难中更快恢复。这一原则同样适用于公司团队。

以下是构建韧性团队的核心要点:

  • 团队建设优于“购买”:除了极少数巨头,大多数组织无法直接“购买”一整支顶尖团队。更现实的路径是从B团队开始,通过培养和建设,将其提升为A团队。一个好的团队比一群顶尖的个人贡献者更重要。
  • 使命感的巨大价值:清晰的使命感可以弥补相当一部分的物质回报。人们为金钱工作的动力是有限的,而为有意义的事业工作的动力则强大得多。公式可以表示为:员工动力 = 物质回报 + 使命感
  • 文化决定战略成败:企业文化会吞噬战略。如果企业文化不支持,再完美的战略也无法落地执行。在引入新系统(如SAP)时,往往是你的公司文化去适应系统,而非相反。因此,制定战略时必须考虑其与公司文化的兼容性。

在混沌环境中,追求绝对的效率优化可能导致组织变得脆弱。相反,保持一定的灵活性、预留备选方案(如备用技术栈),为员工提供机动空间,才能更好地应对意外冲击。

威胁演变史:从恶作剧到国家武器

上一节我们讨论了团队建设,本节中我们来看看网络安全威胁本身在过去三十年发生了怎样的根本性变化。米科·许珀宁的职业生涯完整地见证了这场演变。

早期的计算机病毒(如1986年的“Brain”病毒)更像是青少年的恶作剧,通过软盘传播,显示一些无害的消息或动画。攻击者并无经济利益或政治目的。米科曾根据病毒中的地址信息,在25年后找到了“Brain”病毒的编写者。

转折点出现在2003年。在此之前,攻击多以爱好和恶作剧为主。2003年之后,情况发生了两大根本性转变:

  1. 金钱成为动机:出现了以牟利为目的的恶意软件,如帮助发送垃圾邮件的僵尸网络、盗取银行信息的木马。
  2. 国家力量入场:政府开始将网络能力用于间谍活动等目的。攻击方式通常是通过鱼叉式钓鱼邮件,诱骗目标打开带有漏洞的Office文档(如 .pdf.docx.xlsx),从而控制其电脑。

2010年的“震网”病毒是一个里程碑,它由美国和以色列开发,专门用于破坏伊朗的核设施,证明了软件可以作为物理破坏的武器。

勒索软件的兴起与“网络犯罪独角兽”

上一节我们看到了国家行为体的介入,本节中我们来看看当今最猖獗的威胁形式——勒索软件。如今,典型的攻击(如勒索软件)通常不再自动复制传播。攻击者为了赚钱,需要低调控制受害范围,避免成为头条新闻。

然而,历史上仍有大规模爆发的案例。2000年的“爱虫”病毒是史上最大的电子邮件蠕虫,感染了超过2亿台电脑。它通过标题为“I love You”的邮件传播,附件是一个Visual Basic脚本文件(LOVE-LETTER-FOR-YOU.TXT.vbs)。

2017年是另一个分水岭,出现了两起破坏行业“信誉”的巨大事件:

  • WannaCry:由朝鲜政府编写,旨在筹集资金。它利用从美国NSA窃取的“永恒之蓝”漏洞利用程序,像蠕虫一样自动传播。
  • NotPetya:由俄罗斯政府编写,实质上是针对乌克兰的网络武器,但波及全球,导致如马士基等跨国公司损失惨重,需重装数万台设备。

勒索软件得以盛行的关键推手是比特币等加密货币。加密货币是可编程的、基于数学的货币,难以通过法律进行监管,这使其成为网络犯罪的理想支付工具。2013年的“Cryptolocker”是首个要求用比特币支付赎金的勒索软件。

如今,勒索软件团伙已发展成庞大的犯罪企业。它们拥有自己的品牌、标识和网站,通过“初始访问经纪人”获取企业网络入口,然后像散弹枪一样扫描全网寻找漏洞。其利润之高,足以被称为“网络犯罪独角兽”。这些团伙甚至开始利用AI进行自动化谈判。

防御的进步与未来的挑战

上一节我们剖析了攻击方的演进,本节中我们来看看防御方取得的进展及未来的战场。尽管每天都有数据泄露和勒索软件事件,但从长远看,安全性比以往任何时候都好。

过去十年取得了显著进步:

  • 淘汰了不安全的浏览器插件(如Java、Flash),消除了“点击即感染”的主要途径。
  • 操作系统安全性大幅提升。例如,发布12年的Xbox One至今未被成功越狱,这证明了严格锁定的系统是有效的。
  • 移动设备安全:现代智能手机(iOS/Android)是高度限制性的计算机,大幅提高了攻击门槛。像“飞马”间谍软件这样的高级攻击成本极高(约10万美元/目标),仅限于针对特定人物,这本身是一种安全成功。

攻击者在技术壁垒前受阻后,转而更多地利用社会工程学攻击用户,如网络钓鱼和诈骗。我们不应简单指责“用户是最薄弱的环节”,而应将安全责任更多地放在安全专业人员和技术设计上,减少用户犯错的可能。

人工智能是未来的关键变量。目前,防御方在利用AI方面领先于攻击方。AI已帮助研究人员发现了数十个零日漏洞。然而,攻击方对AI的利用才刚刚开始,更复杂的AI攻击必将出现。

网络安全工作常是“隐形”的——成功意味着什么都没发生。这就像“俄罗斯方块”:消除的成功行会消失,而失败则会堆积起来。正如一句话所说:“当你把事情做对时,人们不会确信你做了任何事。”

总结与个人转向

本节课中我们一起学习了网络安全三十年的风云变幻。我们从混沌的外部环境谈起,探讨了构建韧性团队的重要性。随后,我们回顾了网络威胁从青少年恶作剧,演变为有组织犯罪和国家级网络武器的历程,并深入分析了勒索软件成为“网络犯罪独角兽”的根源。最后,我们看到了防御技术的进步,以及AI带来的新挑战与机遇。

米科·许珀宁在演讲最后宣布,他将离开工作了34年的网络安全行业,加入一家专注于无人机防御的国防承包商。他住在离俄罗斯边境仅两小时的地方,当前的战争形态正迅速向无人机战争演变。他认为,与他一生所对抗的、试图规避检测的可编程威胁(恶意软件)相比,无人机防御在本质上具有相似性——检测与反检测的动态对抗。对他个人而言,在当前时刻,从事“反无人机”工作比“反病毒”具有更直接的意义。

他的职业生涯转变,也标志着网络战与物理世界的传统战域正在以前所未有的速度融合。这为我们所有安全从业者留下了关于责任、使命与技术演进的深刻思考。

网络空间的新前线——站在悬崖边缘 🧑‍💻

在本节课中,我们将学习网络安全专家妮可·珀尔罗斯在 Black Hat USA 2025 主题演讲中的核心观点。她回顾了过去十年网络威胁的演变,分析了当前地缘政治下的新型混合攻击,并探讨了人工智能时代我们面临的严峻挑战与应对之道。

演讲开场与背景

首先,让我们欢迎 Black Hat 的创始人杰夫·莫斯上台。

杰夫分享了他对行业沟通的观察。他指出,有时需要外部人士(如记者)来帮助我们理解并传达网络安全工作的复杂性和社会影响。他特别提到了妮可·珀尔罗斯,她曾担任《纽约时报》网络安全记者十三年,以其著作《这就是他们告诉我世界末日的方式》和播客节目,为外界理解网络军火市场、中国网络威胁等复杂议题提供了独特而严谨的视角。

接下来,妮可·珀尔罗斯登台发表了演讲。

意外的网络安全生涯

妮可首先分享了她如何“意外”地进入网络安全领域。她最初在《福布斯》杂志工作,接到《纽约时报》的面试邀请时,对方告知职位是网络安全记者,她内心十分抗拒,认为自己对此一无所知。

然而,《纽约时报》看中了她曾撰写的一篇关于次贷危机的深度调查报道。在那篇报道中,她通过追踪一份抵押贷款在全球金融体系中的流转,清晰地解释了危机的成因。编辑部认为她擅长向普通人解释极其复杂的话题,因此决定聘用她。

于是,她“在震网病毒事件后入职,在太阳风事件后离职”,在《纽约时报》度过了定义性的十年。

“首次”频发的十年

在《纽约时报》的十年,妮可称之为“首次”频发的十年。

以下是这十年间标志性的“首次”事件:

  • 企业首次公开承认遭国家黑客攻击(如谷歌公开指控中国黑客)。
  • 首次出现利用受信任软件更新通道发起的攻击。
  • 首次出现通过 HVAC 系统、智能鱼缸甚至中餐馆 PDF 菜单发动的攻击。
  • 网络武器的用途首次从间谍活动扩展到对物理世界的破坏。
  • 攻击目标从核设施扩展到全球最大石油公司、乌克兰电网乃至美国大选。

尽管这些攻击事件常常成为头条新闻,但社会往往将其视为边缘案例或黑天鹅事件,在短暂的关注周期后便恢复常态,甚至继续扩大自身的受攻击面。

威胁的演进与共性

妮可指出,当时疲于奔命地应对一个又一个危机,可能忽略了贯穿其中的主线。这条主线就是:攻击正在变得更糟、不断升级,并以我们总是低估的方式扩散。

每一次高调攻击,都为后来的攻击者提供了微小的创新思路。攻击模式在不断演进:

  1. 震网病毒与沙蒙攻击:震网病毒是独立的里程碑,但它所属的“奥运会”行动中的部分能力,后来以更粗糙的形式出现在针对沙特阿美的“沙蒙”攻击中,不仅破坏了数万台电脑,还用燃烧的美国国旗图片取而代之。
  2. 索尼影业攻击:黑客不仅摧毁了索尼的服务器,还增加了“黑客与泄露”活动。他们成功迫使高管辞职、影片撤档。在各方为 attribution(归因)争论不休时,我们可能忽略了其本质是对美国宪法第一修正案(言论自由)的攻击。
  3. 民主党全国委员会黑客事件:攻击者不仅窃取并泄露了希拉里·克林顿的邮件,还对其进行放大和武器化,甚至利用了约翰·波德斯塔的意大利调味饭食谱。这次事件展示了归因如何被扭曲甚至武器化,以分散人们对攻击真实目的的注意力。
  4. 勒索软件的演变:勒索软件从攻击个人电脑,发展到攻击企业;从单纯加密数据,发展到不支付就泄露数据;再到攻击供应链(如软件供应商 Kaseya,硬件供应商广达电脑),最后瞄准了我们关键基础设施的供应链(如殖民管道公司、联合健康集团)。

这些攻击带来的三阶、四阶乃至五阶效应,已成为新常态。而我们似乎总是低估其造成的人员伤亡。

被忽视的人员伤亡

妮可认为,她在《纽约时报》工作的一个最大特权,就是能近距离看到网络攻击带来的人员伤亡。

她讲述了佛蒙特大学医疗中心遭勒索软件攻击后,护士们无法为化疗患者提供治疗、无法告知患者肿瘤是否增大的困境。一位护士将当时的创伤比作波士顿马拉松爆炸案后烧伤病房的惨状。

她还提到德国一位 78 岁的老妇人,因附近医院受勒索软件攻击无法接诊,在转院途中因主动脉瘤延误治疗而去世。当她自己的父亲因主动脉夹层幸存时,她立刻想起了这位老妇人。

人员伤亡似乎总是越来越严重,而这一切都在不断扩散和下沉。

一切都在扩散与下沉

无论是技术、战术还是威胁,网络空间的一切都具有“扩散性”。

例如,“火焰”病毒中利用的微软证书信任链漏洞,后来以更粗糙、针对性更弱的形式,出现在俄罗斯对 M.E.Doc 会计软件的“NotPetya”攻击中,并最终出现在“太阳风”事件里。

这些都不是黑天鹅事件,而是警告。攻击得逞的事实,只会助长对手和网络犯罪分子的气焰。我们曾不屑一顾的边缘案例,正是未来趋势的早期指标:从针对性间谍活动转向广泛破坏,从孤立事件转向系统性中断。

国家层面的战术、技术和程序(TTPs),如间谍软件和协调影响力行动,正在变成恐吓工具。

新型混合威胁:间谍软件与胁迫

间谍软件曾经是顶级国家的专属,现在却流入了那些没有网络人才但资金充裕的政府手中。

妮可与公民实验室等组织合作,发现间谍软件被安装在并非恐怖分子或罪犯,而是民权活动人士的手机上,例如阿联酋的艾哈迈德·曼苏尔,他唯一的“罪行”是在推特上要求更多投票权。他因间谍软件入狱,大部分时间被单独监禁。

间谍软件还出现在墨西哥记者及其子女的手机上,攻击者通过发送“你的孩子有危险”等钓鱼短信进行恐吓,目的是阻止他们从事勇敢的报道工作。

我们继续将这些视为边缘案例,但这些恐吓手段正在以新的、令人不安的方式扩散。

新型内部风险:学术胁迫

妮可提到斯坦福大学的一项调查,发现该校人工智能实验室的中国博士生受到秘密胁迫,被威胁如果不如实向中国汇报前沿技术研究进展,其在中国的家人将受到伤害。这是一种新型的、被胁迫的内部风险。

我们的大学建立在开放、协作的基础上,这是我们的核心竞争力,也是关键的国家资产,但也使我们独特地易受此类攻击。

我们的对手找到了利用我们民主制度、自由市场、公民自由和公共 discourse(话语)本质的方法。

叙事攻击:新型经济胁迫

虚假信息活动已成为恐吓工具,目标不仅是政治候选人或选举,还包括政府领导人和企业。

妮可讲述了一个故事:2022年,力拓集团前 CEO 告诉她,他们在塞尔维亚的一个锂矿项目(用于电动汽车电池)在举行电视剪彩仪式后,立即遭到俄罗斯机器人和水军的攻击,散播关于该项目的阴谋论。尽管通讯团队建议不予回应,但事态并未平息,最终导致塞尔维亚总理因选举压力叫停了这项价值 24 亿美元的项目。

这位 CEO 说,他准备好了应对 5000 万美元的勒索软件攻击,却没准备好应对 24 亿美元的虚假信息攻击。他认为,这是普京在展示“我可以在任何时候夺走你们珍视的任何东西”的能力。

如今,这种叙事攻击已出现在国内。特殊利益团体成功地让政客、企业及其员工保持沉默,例如 RSA 大会上演讲者因雇主害怕触及敏感话题而被临时撤换。

沉默的代价与人才危机

妮可看到,许多在网络安全领域尽职尽责的公共服务人员,正因履行职责而失去工作、学术任命,甚至面临人身威胁。而大多数人对这些事件保持沉默和漠然。

她认为这不可接受。我们评判一个机构,不是看它如何招人,而是看它如何对待离开的人。

美国正面临严重的网络安全人才短缺(估计有 50 万个空缺职位)。当我们看到最高级别的公共服务人员不仅被草率解雇,还被有目的地搞得无法再就业时,这向未来的网络战士传递了什么信号?当其余人都保持沉默时,又意味着什么?

她认为,这本身就是一种国家安全威胁。

合作的力量:乌克兰的启示

尽管挑战严峻,但我们已取得了长足进步。自 12 年前有人计划向基思·亚历山大将军扔鸡蛋以来,我们建立了令人难以置信的公私合作伙伴关系。

俄罗斯入侵乌克兰时,这种伙伴关系对于抵御最初最猛烈的攻击至关重要。尽管外界误以为乌克兰没有发生网络战,但实际上:

  • 我们看到 Viasat 遭黑客攻击,随后星链系统维持了乌克兰的军事通信。
  • 针对乌克兰政府和银行的史无前例的 DDoS 攻击浪潮,被 Cloudflare、谷歌和亚马逊等公司化解。
  • 在乌克兰发电站发现的恶意软件,在引爆前就被美国网络安全和基础设施安全局、乌克兰网络防御机构及 ESET 联手清除。
  • 最重要的是,公私实体合作发现了“管道之梦”这一关键基础设施黑客工具,并在其部署前就将其捕获。

这种程度的合作与信任,是我们以前无法想象的。

当前最大威胁:伏特台风

妮可近期重点关注中国对我们关键基础设施的威胁,即所谓的“伏特台风”行动。

她讲述了马萨诸塞州利特尔顿电力与水务公司总经理尼克的故事。一天,他接到 CISA 和 FBI 的电话,被告知可能遭到入侵。起初他以为是骗局,核实后才发现是真的。对方告诉他,他的系统被中国 PLA 组织“伏特台风”入侵了。最终,在政府协助下,他们成功将“伏特台风”从系统中清除。

这距离我们过去的处境已经非常遥远。我们需要这种程度的公私协作与信任。

攻击不再仅仅来自上海或圣彼得堡的服务器,而是来自新泽西的服务器或印第安纳波利斯的家庭路由器。中国 APT 组织通过默认设置、弱密码、配置错误等常见方式入侵美国家庭路由器,将其变成僵尸网络,并用于针对关键基础设施的“离地攻击”。

这些混合攻击显然是为了在未来必要时进行破坏而进行的预置。无论是为了在台海局势中延迟军事动员、制造混乱恐慌,还是削弱我们支持远方岛屿的意愿,他们都在保留选项。

唯一出路是维护公私实体之间脆弱的信任。如果美国人连一天没有 TikTok 都无法忍受,那么当我们一天、一周没有水,或者水被污染时,我们支持台湾的意愿又会如何?答案显而易见。

人工智能:站在新的悬崖边

现在,我们正站在可能是人生中最大的悬崖边:人工智能时代。

我们知道对手已经在我们的系统、基础设施、电力、通信和叙事中。现在,这些威胁正在被自动化训练,并大规模部署。问题已不是我们能否阻止它们,而是我们是否有勇气尝试。

早期迹象表明,在 AI 助力攻防的竞赛中,进攻方可能占据优势。微软 Copilot、GitHub Copilot 被攻破,Claude 赢得黑客竞赛,Expoit 在黑客排行榜上名列前茅。尽管 AI 有望生成更安全的代码、实现自动补丁管理,但上周 Veracode 的一份报告显示,LLM 在生成安全代码方面表现很差。

我们正在将关键业务构建在不可预测、可能被大规模操纵和投毒的模型之上。高管们宣称员工已做好 AI 准备,但事实上,我们还有一个窗口期。麦肯锡调查显示,近 75% 的公司采用了某种形式的 AI,但其中只有四分之一超越了试点阶段。

我们仍能掌控方向,但窗口正在迅速关闭。一旦 AI 嵌入我们的基础设施、决策和防御系统,失败的代价将成倍增加。与太阳风等供应链攻击不同,AI 造成的破坏可能是不可逆的。

出路:勇气与创新

“安全设计”从未如此紧迫。我们每个人都需要在此刻找到自己的声音,将这些事件视为预警,而非边缘案例。我们必须清晰阐述使用护栏、安全设计、保护模型(从 infancy 开始)、左移安全、保护原始数据以及加强红队测试的必要性。

妮可受到两件事的鼓舞:

  1. 技术创新:她通过自己的“网络登月基金”和作为 Ballistic Ventures 的风险合伙人,看到了令人充满希望的创新,如实时深度伪造检测、诱捕勒索软件攻击者的 AI 幻觉技术、24/7 自动审查第三方风险的智能体,以及帮助中小企业实现安全民主化的 AI 工具。
  2. 行业的勇气:这个行业自我选择了勇气。她列举了丹·卡明斯基(DNS 安全)、谷歌(公开指控中国黑客)、马库斯·哈钦斯(遏制“想哭”病毒)、克里斯·克雷布斯(捍卫选举安全)、阿里巴巴员工(披露 Log4j 漏洞)、凯文·曼迪亚(披露曼迪昂特公司自身漏洞以帮助溯源太阳风事件)以及所有在乌克兰挺身而出的组织和个人。

她引用了乔·马歇尔在获奖时的话:“我们不再从事网络安全业务,我们从事的是拯救文明的事业。”

最后的启示:无处可逃

妮可用一个亲身经历的故事作为结尾。今年夏天,她在多洛米蒂山脉进行铁索攀岩时脚趾骨折,又遭遇雷暴。在剧痛中她呼叫救援,却得知南蒂罗尔高山救援系统遭到了勒索软件攻击而瘫痪。

她坐在山崖上,前所未有地切身感受到:已经没有“离线”状态了。你可以做任何准备,但总有一天你需要帮助,而医院、救援系统、911 接线员——所有这些都已数字化。

因此,她留给听众的唯一信息是:唯一的出路是穿越,而穿越的唯一方式是凭借勇气。


本节课中,我们一起学习了妮可·珀尔罗斯对过去十年网络威胁演变的梳理,认识了从国家间谍活动到混合叙事攻击、从勒索软件到关键基础设施渗透的新型威胁。我们看到了威胁如何扩散、人员伤亡如何被忽视,以及公私合作在应对危机中的关键作用。最后,我们站在人工智能带来的新悬崖边,认识到“安全设计”的极端紧迫性,并铭记:面对无处可逃的数字化未来,唯有依靠技术与人的勇气,才能穿越困境,守护文明。

深入漏洞:探寻 Windows SecureBoot 的远程攻击面 🚀

在本课程中,我们将学习关于 Windows SecureBoot 安全特性的漏洞研究。我们将探讨如何发现这些漏洞、它们的影响范围,以及普通用户应如何保持系统安全。

我是来自 Cyber Kun 的 Andrew Youngang。Cyber Kun 是一家专注于软件和系统安全的新一代网络安全公司。多年来,我一直对 Windows 操作系统充满热情,并在四年前开始了我的 Windows 安全研究员之旅。在此之前,我是一名全能型的 CTF 挑战者。这是我第一次进行演讲,很荣幸能站在这个舞台上。

首先,我会介绍一些背景信息,例如什么是 SecureBoot,以及我的研究与以往研究有何不同。我将介绍基于模糊测试减少重复报告的方法,并讲解理解引导加载程序中漏洞所需的基础知识。

然后,我们将深入探讨我发现的多个攻击面以及针对这些攻击面的关键研究。

之后,我会介绍如何在环境中设置模糊测试框架。

最后,我们将探讨引导加载程序之外的攻击面,并进行总结与要点回顾。

研究背景与动机

在深入技术细节之前,让我分享一下这项研究是如何开始的。

作为一名安全研究员,我们总是被未知领域所吸引。对于 SecureBoot 而言,它是三个因素的完美结合:未知的领域、基础的重要性以及现实因素。这种结合使其成为一个极具吸引力的目标。相比之下,引导过程本身没有更高的安全要求。

因此,根据我的理解,SecureBoot 使用数字签名和加密哈希来建立从硬件到操作系统的信任链。你可以看到它在移动设备锁定实现中的应用,例如 iOS 和 Android 内核的各种实现,这些实现将设备锁定为仅运行硬件信任的代码,这通常是硬件制造商或操作系统供应商提供的引导加载程序和操作系统。

在 PC 平台上,操作系统供应商通常不是硬件供应商。借助 UEFI 标准,可以将 SecureBoot 功能引入 PC 平台。

虽然移动电话更贴近我们的日常生活并持有更多隐私数据,因此你可以看到每部手机都默认启用了 SecureBoot。它非常重要,以至于如果你试图破坏手机的 SecureBoot,它会警告你手机不可信。在 Windows 操作系统中,近年来也有一些功能要求强制执行 SecureBoot。

但坦率地说,PC 平台还有很长的路要走,因为有太多的硬件制造商,很难让每个硬件制造商都投入精力。

回到我们的主题,“深入漏洞”。那么,是什么造成了这些漏洞?

首先你需要知道的是,我所有的发现目前仍然可以通过网络在 PC 平台上默认被利用。这主要是因为 PC A 2011 第三版是 UEFI 标准中的默认设置,并被无数主板制造商和虚拟化平台使用。

它的有效期到 2026 年。它的前身已经通过 Windows 更新默认部署在 Windows 机器上,但由于兼容性问题,PC A 2011 并未被添加到黑名单中,正如微软安全响应中心的 Bill 在去年的 Black Hat 演讲中所解释的那样。

此外,UEFI 黑名单的限制也较少。因此,所有这些条件使得这些 Windows SecureBoot 漏洞能够被利用,这是时间上的漏洞。

先前研究与现状

让我们回顾一下之前关于 Windows SecureBoot 的研究。你可以看到,它们主要关注需要本地或物理访问系统的攻击服务。在过去的 10 年里,只有 8 个关于 Windows SecureBoot 的 CVE。与其他 Windows 组件相比,这个数字很小,对吧?

在这仅有的 8 个 CVE 列表中,有两个著名的漏洞拥有自己的名字。最著名的 CVE 是被 Black Lotus 恶意软件使用的两个。

这里有一份由微软安全响应中心发布的关于我的发现的公开致谢列表。你可以看到,与之前的研究相比,我的发现数量非常大,并且它们可以通过网络被利用。因此,在过去 10 年里,我发现了近 60% 的 Windows 操作系统 SecureBoot 安全特性绕过漏洞。

有时我看着我的研究,会想,这真的重要吗?它是否带来了任何改变?然后我看到了这样的反馈,这让我想起了我为何要继续前进。

漏洞为何能通过网络利用?

在这里,我想请大家注意一个名为 PXE 的协议,即预启动执行环境。PXE 是一种标准化的客户端-服务器模型,支持网络引导。与我之前提到的由其他研究人员发现的 9 个漏洞不同,我在研究中发现的漏洞更容易利用,其复杂性不高,并且不依赖于特定的硬件供应商。

漏洞性质与影响

既然有这么多安全特性绕过漏洞,你一定会有疑问。这些漏洞是关于什么的?微软安全响应中心向我解释说,在 SecureBoot 之前,微软不承认引导加载程序中的漏洞。引导加载程序问题可以获得 CVE。因此,SecureBoot 是 Windows 的一项安全功能。所以,Windows SecureBoot 中的漏洞属于安全特性绕过。因此,它可以是远程的,可以无需用户交互,可以是临时的,可以是远程代码执行或信息泄露,但不能是拒绝服务。他们不认为这是一个安全问题。

关于我的发现的影响,它可以用来攻击大多数启用了 UEFI SecureBoot 的 PC,而不管平台上运行的是什么操作系统。但在现实世界中,主要是 Linux 和 Windows。通常,这两个系统需要经常重启,并且有许多环境利用磁盘环境,这些环境默认使用 PXE 作为选项。这些环境默认就处于真实风险之中。因此,攻击可以通过 B.Y.O.B. 实现,即“自带引导加载程序”。

研究成果总结

以下是我的研究成果总结。在研究期间,我向微软提交了 55 份报告,详细说明了在微软代码中发现的各种漏洞。

从图表中可以看到,按发现方法分类,共有 35 个案例是通过代码审计发现的,20 个案例是通过模糊测试发现的。按攻击面分类,有 25 个案例与 BCD 注册表处理相关,16 个案例与文件系统相关,6 个案例与网络协议相关。还有 5 个案例发生在 Windows 内核中。

减少重复提交的策略

在我的研究中,我面临的第一个挑战是如何减少提交的重复性。我的方法是从开发者的角度来考虑这个问题。首先,我会发现漏洞。然后,我会尝试编写一个模糊器,通过模糊测试来发现漏洞。最后,我会对漏洞进行热补丁修复。

如果热补丁成功,应该不会再出现与同一根本原因相关的案例。我会重复这些步骤,直到模糊器无法再生成崩溃为止。

引导加载程序内存管理基础知识

在深入探讨攻击面之前,有一个关键知识点需要记住,以便我们未来在引导加载程序上开展工作。那就是引导加载程序中的堆管理。

与 Windows 用户模式相比,引导加载程序中没有页面堆。这意味着在发生越界访问时,它不会立即崩溃。相反,它会在下次使用损坏的数据时,或者在堆管理代码进行垃圾回收时崩溃。

我非常惊讶地发现,堆损坏报告函数本身存在自递归问题,但这并不重要,因为栈溢出理论上不会使堆越界更容易被利用。

此外,你需要知道块大小至少为 32 字节,并且按 32 字节对齐。

引导加载程序中的攻击面

现在,让我们进入引导加载程序中的攻击面部分。

网络协议攻击面

我们首先介绍引导加载程序中的网络协议。在我的研究中,使用了多种网络协议,包括 IPv4、IPv6、TFTP、HTTP 和 WDS 多播。我发现协议栈是引导加载程序中最安全的部分。在引导加载程序协议栈中,我只发现了 6 个漏洞。

这包括引导加载程序中处理 IPv6 响应包时的两个栈溢出、处理 TFTP 时的一个递归调用、处理长路径自加载时的一个递归调用,以及引导加载程序中处理 HTTP 响应时的一个整数下溢。此外,在 IPv6 协议栈中还有一个中等严重性的拒绝服务漏洞。从这个拒绝服务漏洞可以看出,微软引导加载程序的 IPv6 代码尚未准备好投入生产。

这张图向你展示了 IPv4 PXE 引导阶段。这张图展示了 IPv6。

我花了几个小时将这张图实现为 Python 代码。它是引导加载程序研究中一个非常好的参考起点。

搭建研究环境

在开始研究实际案例之前,我们需要为研究搭建一个易于复现的环境。Hyper-V 绝对是漏洞挖掘的好帮手,因为它是唯一一个无需入侵虚拟机就能生成小型转储文件的工具。

它还支持在固件上进行 IPv6 PXE 引导。根据文档,很容易找到指南,教你如何使用 PowerShell 为 PXE 引导选择特定的 IPv6。

你可以看到,小型转储生成代码在 VMWP 进程中。如果你想实现完整转储或使其在 KVM 中工作,需要做同样的工作。我还没有做,因为 Hyper-V 的小型转储对于研究来说已经足够了。你可以获得关于漏洞的非常详细的堆栈跟踪,以及可能的根本原因分析。小型转储在许多情况下都很有帮助,但当缓冲区溢出只影响堆块之后的几个字节时,它通常不起作用。

你也可以准备一个 VMware ESXi 环境,因为 VMware 是现实世界中的虚拟化领导者。

实际漏洞案例:栈溢出

现在,我们将看到引导加载程序中的真实漏洞,从一个简单的 PXE 引导加载程序栈溢出开始。

这两个漏洞的根本原因是函数未能检测到客户端/服务器标识符长度过长,而目标数组只有 16 字节。然后它会覆盖父函数栈上的变量。这是一个非常简单的案例,非常老派,然而它存在了很长时间。所以我认为我们可以从中学习到的是,当你查看一个攻击面时,需要确保没有遗漏任何组件。顺便说一下,在 PXE 引导加载程序之前,没有漏洞只存在于其中。因此,选择一个尚未引起所有人注意的目标很重要。你可能会在其中发现简单的漏洞。这可以为你赢得信心。我认为这是进行研究时最重要的事情。

成功利用这两个漏洞将使攻击者能够控制 IP 和一些其他寄存器。攻击者随后可以发起 ROP 攻击。我们将在后面的部分讨论为什么这种利用如此容易。

BCD 注册表处理攻击面

我们刚刚讨论了网络协议。接下来,我们将讨论 BCD 元素处理漏洞。

之前已经有两次关于 BCD 注册表溢出的演讲。所以我们简要介绍一下。BCD 是一个注册表存储库,可以通过 Regedit 分配和添加。

在我的研究中,模糊器只发现了一个与注册表文件结构相关的漏洞,就是这个函数中的越界写。同样,这非常老派。可能你们大多数人都知道,来自 Project Zero 的 Ju 近年来在 Windows 内核中发现了大量的注册表漏洞,但引导加载程序中的注册表要简单得多。它不支持完整版 Windows 注册表中的许多功能。它只是一个简单的配置存储库。然而,一个简单的模糊器在 2023 年仍然能找到东西。

在引导加载程序的注册表解析代码中,这很神奇。我不会手动查看注册表解析代码。那对我的水平来说太复杂了。

有两个工具叫 BCDedit,可以生成各种对象模板。当你计划在 BCD 注册表中寻找漏洞时,它非常有用。

BCDedit 的用法没有完全记录。有一些实际用法你只能通过逆向工程 BCD 代码来发现和理解。在我的研究中,我发现这个网站上的 BCD 元素页面非常有帮助。如果你真的想深入研究引导加载程序中的 BCD 元素处理代码,你不会想错过这份资料。

在引导加载程序中,有一个关键结构称为引导环境设备,它反映了 BCD 注册表元素的内部二进制数据。通过逆向工程,我们看到二进制格式数据在解包时会被检查。

但似乎横幅的内容没有被完全检查。

引导环境设备类别有一个关键类型。BL_DEVICE_TYPE 是你研究 BCD 元素处理代码的灯塔。请牢记这个类型,并带着它继续前进。

关键漏洞函数分析

在处理来自 BCD 注册表的数据时,有一个神奇的函数。为什么说它神奇?从它的名字可以看出,它应该被设计用来消除攻击者控制数据中的非法设备对象。

然而,这个函数本身太有价值了。它只有大约 100 行代码。我在其中发现了 6 个漏洞。

这包括两个可以覆盖返回地址的栈溢出、一个任意内存写和三个堆越界写。所以,简单的模糊器在这个函数中产生了第一次崩溃,我逆向了这个函数并发现了另外两个漏洞,并在研究引导加载程序的早期就报告给了微软。实际上,在我开始研究 BCD 解析的初期,我并没有意识到它是可以通过 Regedit 添加到半文件中的标准写入二进制数据。所以在我面前是一个未记录的结果。它是一团糟。基于此,你可以修改的数据非常有限。大约一个月后,当我在引导加载程序中找不到更多漏洞时,我意识到数据可以通过 Regedit 修改。我回过头来查看这个函数内部是否还有其他漏洞,并在其中发现了另外三个堆越界写。

但微软安全响应中心告诉我,这三份报告是一份内部报告的重复,那份内部报告获得了 CVE-2024-26175。事实上,这个 CVE 在 2024 年 4 月被确认并修复。他们澄清说他们已经实施了设计层面的更改来解决所有问题。

所以我深入询问。工程团队在哪里实施了这种设计层面的更改?我得到了两个函数名,它们有 88% 的调用相似度。

所以我的想法是:也许工程团队在我报告那三个堆越界案例之前更改了函数名。当他们收到那三个堆越界报告时,他们找不到我报告的函数名了。所以他们向我解释说,它们已经被一个设计层面的更改修复了。但这只是我的猜测,因为我在 2023 年报告了这个案例,而 CVE 是在 2024 年。我不知道当我被告知是重复时是什么情况。

从我之前的介绍中,你可以看到这些漏洞很简单。你只需要添加边界检查来防御它们。它们太简单了,工程团队不会错过。这里又有了另一个想法:如果他们从一开始就不知道这三个报告的根本原因呢?

所以我尝试在打了补丁的引导加载程序上运行越界写漏洞验证代码。它确实触发了我报告的漏洞。它触发了堆损坏,正如你在屏幕上看到的那样。

在向微软安全响应中心报告此事后,我收到了关于案例重复的合理解释。我要特别感谢微软安全响应中心的明星员工在整个过程中的工作。我认为我们能从中学到的最重要的一点是,如果你在同一组件中有大量漏洞,当补丁发布时要非常小心。不要偷懒,只需在补丁 1 上测试你的验证代码。我想,如果我在补丁发布时进行复查,也许我能在列表中获得更多 CVE。

递归调用漏洞

两个 BCDedit 工具只是我大多数提交的提示和模板。当你深入研究并尝试利用更复杂的漏洞时,BCDedit 将超出其能力范围。这是这种情况的另一个例子。它的根本原因是在模拟元素时发生了递归调用。

关于递归调用,有一些重要的事情你需要知道。与用户模式的递归调用通常导致用户模式的拒绝服务不同,在 UEFI 环境中,它是高度可利用的漏洞。在尝试利用引导加载程序中的栈溢出之前,你应该了解 EDK2 UEFI 栈内存布局。

在标准的 EDK2 内存模型中,UEFI 栈之前的红色区域内存大小是 Hyper-V 中的两倍,尽管它与 UEFI 标准中的栈大小相同。在 Hyper-V 中,栈内存区域之前似乎有一个不是红色的间隙。在 UEFI 定义中,不能保证栈内存之前的内存不是红色的。因此,这将把递归调用变成栈越界写,而这种越界写将有能力覆盖 UEFI 环境中的中断栈或一些关键变量。

导致一个高度可利用的漏洞。从这张图片中,你可以看到当引导加载程序中发生递归调用时,它最终会覆盖 UEFI 环境中的一些关键变量,导致另一次访问违规。

如果你尝试在标准内存布局中手动利用这些漏洞来暴露这些漏洞,我会感谢你的耐心。你需要包含 415 个设备对象在 BCD 注册表文件中。即使在半虚拟化内存模型中,你也需要包含 226 个设备对象。

在这种情况下,我想强调编写一个能让你生活更轻松的程序的重要性,因为 BCD 注册表本身就是一个注册表。你可以在 Windows 上通过注册表 API 加载和修改它。你可以简单地编写一个像这样的程序来测试递归调用的崩溃边界。

安全策略相关漏洞

此外,这里还需要考虑另一个协议问题。

你只能通过利用特定的 BCD 元素来指定使用 HTTP 协议的引导加载程序。

大多数漏洞都围绕着数据应该至少有一定长度的假设,这是不正确的。在这种情况下,你需要根据假设检查攻击者控制的数据。

好了,关于 BCD 元素处理我们已经谈得够多了。让我们继续讨论安全策略。

这是微软关于 UEFI 平台初始化 2 规范的一个非常有趣的公开文档,非常重要。

正如你从我之前的幻灯片中看到的,最后一句话是不正确的。攻击可以通过 B.Y.O.B. 实现,即“自带引导加载程序”攻击。

因此,与策略相关的代码仍然存在于最新的 Windows 引导加载程序中。这看起来就像后门,只有拥有有效微软签名策略的人才能利用。我某种程度上能理解为什么这是设计使然。当你有能力正确发送所有内容时,为什么不直接签署一个引导加载程序呢?

另一个是我在研究期间提交的唯一一个安全特性密钥绕过漏洞。我的意思是,这不是内存损坏。它是逻辑性的,易于利用。它存在是因为引导加载程序从引导设备获取引导管理器 PE 文件进行验证。当执行代码时,PE 文件已经加载到内存中。然而,当引导由 PXE 启动时,它们会再次获取。远程服务器不可信。

因为它可以为验证提供一个有效的镜像,而为实际运行提供一个无效的镜像。类似的逻辑案例确实存在于其他产品中,比如手机,但它需要更受限制的环境才能利用。所以每个人都会犯错。

在你真正想研究类似组件之前,查看其他研究非常重要。

文件系统攻击面

去年,微软安全响应中心的 Bill 向我们提出了这个问题。他说文件系统是那些喜欢红色模糊测试的人的天堂,并问为什么默认暴露这么多文件系统。但今天,我们不打算讨论不必要的文件系统。我们只讨论现代 Windows 中引导加载器正常工作所必需的文件系统。

即 WIM 和 NTFS,并提供一些针对文件系统的模糊测试技巧。

这是另一个神奇的示例,函数名中带有“fix”。奇怪的是,我们在一个名字中带有“sanitizing”的函数中发现了 6 个 RCE。这次,我在这两个函数中识别出了 5 个 RCE。它们的名字中都有“fix”这个关键词。同样,它们非常老派,不难发现。我们真的花了时间查看正确的函数。

这些发现都始于引导加载程序中文件系统的一个简单模糊器。在审查结果列表时,事实证明,模糊器更擅长发现和生成拒绝服务案例,而不是内存损坏案例。分析文件系统中的拒绝服务非常痛苦,因为它有太多这样的案例,而且引导加载器中的拒绝服务案例属于中等严重性。将时间花在分析拒绝服务上是一种浪费。

文件系统模糊测试设置

所以在这里,我将向你介绍如何在 Windows 引导加载器中设置文件系统模糊测试。我使用 AFL++ 的 NYYX 模式开始我的模糊测试设置,因为使用 NYYX 模式,我不需要关心当前集合。是的,你需要一个现代英特尔处理器来运行模糊器。

这是我设置模糊测试调用的方法,分配一些部分来保存模糊测试所需的必要代码和数据,并修补引导加载器中的必要函数以进行快速插桩。

关于文件系统模糊测试,在你真正开始之前,有一个关键点你应该知道。文件系统本身是一个代码覆盖率放大器,因为模糊测试使用代码覆盖率基本块来计算代码覆盖率,并且为了到达代码中的相同逻辑,所有路径都可以引导你到达罗马,你会在真正对

攻击 Windows Server 故障转移集群 - 集群化的故障点 [FSRmPwfMYs0] 🎯

在本节课中,我们将学习 Windows Server 故障转移集群的工作原理、其安全风险,以及攻击者如何利用集群配置中的弱点。我们将从基础概念开始,逐步深入到实际的攻击路径和防御策略。


概述 📖

故障转移集群旨在为关键应用(如文件服务器和数据库)提供高可用性。然而,这种设计也引入了独特的安全风险。我们将探讨集群的架构、身份验证机制,以及如何从控制单个集群节点升级到控制整个集群甚至整个域。


集群简介与历史背景 🕰️

为了理解故障转移集群,我们需要回溯到1997年。当时,微软在“可扩展性日”活动中发布了 Windows NT 4.0 Enterprise Edition,并引入了 Microsoft Cluster Server(MSCS)。这是微软首次涉足高可用性领域。

微软对 Windows Server 故障转移集群的当前定义是:一组独立的计算机协同工作,以提高应用程序和服务的可用性。三十年来,这项服务的核心目标没有改变。

最常见的集群化应用和服务是文件服务器和数据库。这两者都代表了单点故障。如果它们离线,就会失去对这些资源的访问。

集群通过让多台服务器支持单一资源来解决这个问题。如果一台服务器失效,另一台服务器会接管该资源。


故事时间:一次攻击中的异常发现 🔍

上一节我们介绍了集群的基本概念,本节中我们来看看一个真实的攻击案例,它揭示了集群行为的复杂性。

在一次内部测试中,攻击者控制了一台机器账户,并试图利用“msDS-AllowedToActOnBehalfOfOtherIdentity”属性(即基于资源的约束委派,RBCD)来攻击另一台主机。他们按照标准流程设置了 RBCD,并尝试使用 Impacket 等工具进行攻击,但都失败了,出现了主机名解析错误。

然而,当他们转而使用计划任务(Scheduled Tasks)时,攻击成功了。但奇怪的是,他们发现有效负载执行在了另一台完全不同的主机上,而他们最初的目标用户会话也存在于这台新主机上。

这引发了一系列问题:

  • 为什么计划任务能成功,而 Impacket 脚本会失败?
  • 我们能否预测或控制有效负载将在哪台主机上执行?
  • 会话数据是怎么回事?是账户到处登录,还是其他原因?
  • 集群环境下的 Kerberos 身份验证是如何工作的?


深入研究:搭建实验环境 🧪

为了找到答案,我们搭建了一个实验环境。我们创建了一个三节点集群,并部署了一个文件服务器角色。

以下是创建集群和角色的关键步骤:

  1. 在“故障转移集群管理器”中创建新集群。
  2. 添加所有节点计算机。
  3. 为集群管理创建一个访问点,并指定集群名称和 IP 地址。
  4. 创建角色(例如文件服务器),为其创建客户端访问点,并分配存储。

完成这些后,我们就有了一个正常运行的集群。每个节点都安装了一个“网络容错虚拟适配器”,用于节点间通信。集群使用 UDP 3343 端口进行心跳检测,使用 RPC(端口 135 及动态端口)进行管理通信。

通过分析网络流量,我们发现了第一个问题的答案:管理工具(如计划任务 MMC 管理单元)能够正确解析集群的虚拟主机名,而一些 Impacket 脚本在尝试写入文件时,会因为无法在虚拟命名空间上找到有效路径而失败。使用不依赖文件输出的命令可以解决这个问题。


集群的逻辑组件与 Kerberos 谜题 🧩

上一节我们搭建了实验环境,本节我们来深入理解集群的逻辑组件,并解开 Kerberos 身份验证的谜题。

集群包含几个关键逻辑组件:

  • 节点:构成集群的物理或虚拟服务器。
  • 虚拟计算机对象:代表集群服务(如文件服务器)的 Active Directory 计算机账户。
  • 集群名称对象:代表集群本身的 Active Directory 计算机账户。

在任何时候,一个 VCO 或 CNO 资源只能由一个节点“拥有”。客户端连接到 VCO 的命名空间来访问服务(如文件共享),而管理员则连接到 CNO 的命名空间进行管理。

这解释了第二个和第三个问题:有效负载在哪台主机上执行取决于当时哪个节点是资源的所有者。BloodHound 报告的会话数据是准确的,因为它通过虚拟主机名查询,实际响应的是底层所有者节点。

但最大的谜团是 Kerberos。在标准 Kerberos 流程中,服务票证使用目标服务账户的密码进行加密。攻击者无法解密。但在我们的攻击案例中,一个主机(节点A)生成的票证,却被另一个完全不同的主机(节点B)成功解密并接受了。

这意味着所有集群节点似乎都能访问 VCO 和 CNO 的密码。经过研究,我们发现密码存储在集群数据库中(实际上是每个节点上的注册表项),并且使用基于证书的加密进行保护。

通过逆向工程集群服务二进制文件,我们找到了解密这些凭据的方法。关键代码逻辑如下:

# 简化版的解密流程示意
private_key = load_private_key_from_registry()
encrypted_secret = extract_from_resource_blob(data_blob)
derived_key = derive_key(encrypted_secret, private_key)
decrypted_password = decrypt_ciphertext(ciphertext_blob, derived_key)

解密后的数据块不仅包含 VCO/CNO 的当前密码,还包含历史密码,以确保密码轮换时不会中断现有连接。

至此,我们得到了最终答案:每个集群节点在启动时,都会用存储在本地集群数据库中的密码,为 VCO 和 CNO 执行一次登录。这样,任何节点在故障转移时都能立即接管服务并处理身份验证。


攻击演示:从节点到集群再到域 🚀

既然我们理解了机制,那么作为攻击者,在控制一个集群节点后能做些什么呢?

首先,我们可以提取 VCO/CNO 的密码哈希。利用 VCO 的哈希,我们可以执行 S4U2Self 扩展,代表任意用户(甚至是受保护用户组的成员)向我们控制的服务请求票证。由于我们就是服务本身,这种请求无法被拒绝。

以下是攻击步骤:

  1. 使用 VCO 的 NTLM 哈希,通过 S4U2Self 为域管理员请求一张访问文件服务器(VCO)的服务票证。
  2. 使用这张票证,通过 RPC 连接到集群管理接口(CNO 命名空间),模拟集群管理员。
  3. 枚举集群中的所有节点和角色。
  4. 找出当前拥有文件服务器角色的活动节点。
  5. 在该节点上通过计划任务执行有效负载。
  6. 使用集群管理命令将文件服务器角色移动到下一个节点。
  7. 无需刷新或修改票证,直接再次执行计划任务命令,有效负载将在新的所有者节点上执行。
  8. 重复此过程,即可在所有集群节点上执行代码。

结论是:如果你控制了一个集群节点(拥有本地管理员权限),你就控制了整个集群及其所有托管的服务。

但这还能变得更糟吗?能否从集群控制整个域?这取决于 CNO 账户在 Active Directory 中被授予的权限。根据微软过时的文档和常见的错误配置,CNO 经常被授予其所在组织单元的过多权限,例如“完全控制”、“创建/删除所有子对象”等。

这些过度的权限可能带来灾难性后果。我们看到了多个真实环境中的攻击图:

  • CNO 对某个 OU 拥有通用权限,该权限向下继承,最终导致 DCsync 权限。
  • CNO 是某个安全组的成员,该组对域对象拥有完全控制权。
  • CNO 对一台属于“Exchange Trusted Subsystem”的计算机拥有权限。
  • 即使权限看似无害(仅能创建计算机对象),结合 2024 年披露的 Shadow CredentialsBA Successor 攻击,也能导致域沦陷。

普遍性、影响与防御建议 🛡️

集群非常普遍。根据数据,82% 的企业环境中至少存在一个集群,平均每个环境有 141 个独立集群,最多的甚至接近 2700 个。这是一个巨大的攻击面。

受影响的不仅仅是域,还包括集群化的关键服务本身:

  • MS SQL Server:最常见的集群数据库。
  • AD FS:使用“始终可用”组。
  • Exchange:数据库可用性组。
  • SCCM:其核心站点数据库。
  • AD 证书服务:微软也提供了集群配置指南。

如何防御?

  1. 权限修正:审核并修正 CNO 账户的权限。在 OU 上,它仅需要“创建计算机对象”权限。移除所有不必要的“完全控制”、“通用所有”等权限。
  2. 检测异常认证:VCO/CNO 账户只应从集群节点的 IP 地址进行认证。监控来自非节点 IP 的该账户认证,这是一个高置信度的警报。
  3. 监控注册表访问:集群凭据存储在注册表的特定位置。只有集群服务及其子进程需要读取它。使用 Sysmon 等工具监控其他进程对此注册表项的访问尝试。
  4. 不要遗忘虚拟账户:这些 VCO/CNO 账户是长期存在的 Active Directory 对象,即使底层硬件多次更换。它们应与物理服务器账户一样,受到严格的权限管理和生命周期监控。


总结 📝

本节课中我们一起学习了:

  • Windows 故障转移集群的架构和核心组件:节点、VCO 和 CNO。
  • 集群如何通过在所有节点上存储和同步服务账户密码来实现高可用性和故障转移。
  • 攻击者如何利用控制单个节点的权限,通过提取密码、滥用 S4U2Self 和集群管理 API,最终控制整个集群。
  • 由于常见的过度权限配置,控制集群身份(尤其是 CNO)可能成为通往域管理员权限的跳板。
  • 集群化服务(如 SQL、AD FS)本身也是高价值目标,其沦陷会造成重大业务影响。
  • 通过实施最小权限原则、监控异常认证和敏感注册表访问,可以有效地防御和检测此类攻击。

关键要点:

  • 控制一个节点,就等于控制了整个集群。
  • 集群的错误配置可以导致域沦陷。
  • 对于长期存在的虚拟服务账户,要像管理物理服务器账户一样严格。

(附注:相关攻击工具、PoC解密代码和更详细的技术博客可通过演讲中提供的资源链接获取。)

滥用 Entra OAuth 获取内部 Microsoft 应用程序访问权限 🎯

在本课程中,我们将学习一种针对 Microsoft Entra ID(原 Azure AD)身份平台的新型配置错误。这种错误允许外部用户通过滥用多租户应用程序的 OAuth 授权流程,访问本应仅限于内部使用的 Microsoft 应用程序。我们将从基础概念讲起,逐步剖析攻击原理、步骤和实际案例。


概述

本次分享源于一次偶然的发现:通过访问特定的 Microsoft 内部域名并登录个人账户,意外获得了访问内部工程门户的权限。这引出了一个核心安全问题:为何个人账户能通过授权访问内部应用?答案在于对 Entra ID 多租户应用程序OAuth 授权流程的误解与错误配置。

上一节我们概述了本次发现的背景,接下来我们将深入 Entra ID 身份平台的基础知识。


Entra ID 身份平台基础

为了理解后续的漏洞,我们需要回顾一些关于 Microsoft Entra ID(身份平台)的基础知识。我们通常都知道身份验证授权的区别:

  • 身份验证:确认用户是其声称的身份。在 Entra 中,这通过 OpenID Connect 协议完成,结果是一个 ID 令牌。
  • 授权:验证用户是否有权限执行特定操作。在 Entra 中,这通过 OAuth 2.0 协议完成,结果是一个访问令牌。

对于开发者而言,在 ASP.NET 应用中,通常使用 [Authorize] 属性来同时要求身份验证和授权。这个过程主要在授权服务器(即 Microsoft 身份平台,如 login.microsoftonline.com)完成。

其核心流程是:资源所有者(用户)通过一个客户端应用访问自己的数据。客户端向授权服务器请求一个承载令牌,并用它来访问资源。任何需要用户使用 Microsoft 账户登录的应用,都必须在 Entra 中注册。


应用注册与服务主体

在 Entra 中有两个关键概念:

  1. 应用注册:可视为一个模板,定义了应用在租户内可以拥有的权限类型以及应用中存在的角色。
  2. 企业应用/服务主体:是应用注册在特定租户中的具体实例,描述了应用在该租户内的实际访问级别以及用户在该应用中的具体角色。

简单来说,应用注册是蓝图,服务主体是根据蓝图建好的房子


OAuth 授权码流程

虽然存在多种令牌授予流程,但本次漏洞适用于所有类型。我们以最常见的单页应用使用的授权码流程为例:

  1. 应用引导用户登录。
  2. 如果服务主体尚不存在,用户需要同意该应用。
  3. 用户/应用获得一个授权码。
  4. 应用使用授权码换取访问令牌。
  5. 应用使用访问令牌调用 Web API 并获取数据。

同意分为用户同意(仅限用户范围的权限)和管理员同意(需要整个目录范围的权限)。同意的过程,就是在租户内实例化应用注册,创建服务主体。

你可以通过访问特定 URL 并输入应用 ID 来强制触发同意提示:
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?client_id={app_id}&response_type=code&scope=...

也可以编程实现,例如通过直接调用后端 API 循环对大量应用进行同意(但不推荐)。


访问令牌与声明

获得同意后,你会得到一个访问令牌。令牌由头部、载荷和签名组成,由 Microsoft 签名,不可篡改。令牌的载荷中包含重要的声明

  • aud:受众,即令牌的目标应用 ID。
  • iss:颁发者,即签发令牌的租户,至关重要
  • tid:用户所属的租户 ID。
  • scp:应用在环境中的访问范围(权限)。
  • 以及其他用于标识用户的声明。

访问令牌示例结构(伪代码):

{
  "aud": "应用客户端ID",
  "iss": "https://login.microsoftonline.com/{tenantId}/v2.0",
  "tid": "用户租户ID",
  "scp": "user.read",
  "sub": "用户唯一标识",
  "roles": ["管理员"] // 如果分配了角色
}

多租户应用与端点

Microsoft 身份平台可以通过多个端点访问,这与应用注册为单租户还是多租户有关:

  • 多租户应用:允许其他租户的用户同意并使用。应使用 common 端点(或 organizations)。
  • 单租户应用:仅限自己租户内的用户使用。应使用 tenant 端点(租户 ID 或域名)。

关键点在于:一个应用注册对象只存在于一个租户(其主租户)。但如果它是多租户应用,那么其服务主体可以存在于多个同意它的租户中。

这意味着,如果应用注册在租户 A,租户 B 的用户在向其主租户(租户 B)认证并同意该应用后,会在租户 B 内创建一个服务主体,并获得一个对租户 B 内该应用有效的令牌。

上一节我们介绍了多租户应用的核心机制,接下来我们将回顾一个历史相关漏洞,以更好地理解当前问题的演变。


历史背景:BingBang 漏洞

在 2023 年的 BlackHat 大会上,Wiz 团队披露了一个名为 BingBang 的漏洞。该漏洞也存在于多租户应用中。

他们发现,在授权码流程的认证阶段,如果攻击者在认证 URL 中将攻击者租户替换为资源租户(例如 Microsoft 的租户),身份平台会错误地颁发一个由资源租户签发的令牌。这使得攻击者能够以资源租户的身份访问应用。当时,约 25% 的应用受此影响。

Microsoft 随后进行了缓解:

  1. 停止向未在资源租户内注册的客户端颁发访问令牌。
  2. 建议实施推荐的授权检查以减少多租户应用的暴露面。
  3. 建议要求用户分配并实施条件访问策略。

然而,我们将会看到,这些建议并不能完全缓解我们今天要讨论的新问题。

了解了历史漏洞及其修复措施后,让我们回到最初的问题:为什么我能登录 Microsoft 内部工程中心?


漏洞原理:同意与妥协

回顾发现过程:我访问了 eng.ms 等内部域名,被重定向到 common 端点进行登录。我用个人账户登录并同意了应用请求。

结果:我在我的个人租户内完成了认证,并获得了一个对我的租户内该应用实例有效的访问令牌。然后,我使用这个令牌成功访问了 engineering hub 应用。

根本原因engineering hub 这个 Web 应用在验证我的访问令牌时,没有检查 iss(颁发者)或 tid(租户 ID)声明。它只验证了令牌有效、用户已认证且被授权(在我的租户内被分配了角色)。所有用户分配、条件访问策略都在我的个人租户内生效,而内部应用对此毫无察觉。

责任划分:前端应用开发者可能正确地实现了身份验证和授权库。问题很可能出在 Entra 管理员或应用注册配置者身上,他们可能认为“会有多个租户的用户需要访问此应用”,于是将其注册为多租户应用,但实际上它本应是严格的单租户内部应用。

既然在一个内部服务中发现了此问题,那么很可能存在其他类似漏洞。


攻击面枚举与发现

我开始枚举 Microsoft 的各种子域名(*.microsoft.com*.azure.com 等),最终获得了超过 10 万个域名。

以下是枚举和分析的结果摘要:

  • 超过 7 万个域名解析到 IP 地址。
  • 超过 4 万个域名响应 HTTPS 请求。
  • 其中,超过 1400 个使用了 Entra ID 进行授权。
  • 大部分使用客户端重定向,少部分使用 HTTP 重定向。
  • 发现了 327 个 Swagger 接口(留给他人研究)。

有趣的是,大部分应用重定向到 tenant 端点(应为单租户),但其中一部分实际上是多租户应用。这表明开发者可能并未意识到他们的应用被配置成了多租户。

具体来说,在重定向到 common 端点的 400 个应用中,我检查了其客户端 ID(应用 ID)的多租户属性。发现有 172 个是多租户应用。但值得注意的是,其中大多数在请求中使用的却是 tenant 端点,这进一步表明了配置与认知的不一致。


攻击步骤详解

由于我们没有 Microsoft 租户的账户,但目标应用是多租户的,我们如何登录?方法很简单:使用代理工具(如 Burp Suite)进行中间人攻击,在飞行中(on-the-fly)将认证请求中的 Microsoft 租户 ID 替换为 common

这将整个授权流程重定向到了我自己的租户,允许我同意该应用、登录并获得访问令牌。但许多应用仍然会返回错误。以下是遇到的错误及绕过方法:

1. 错误:需要用户分配

  • 绕过:用户分配现在发生在我自己的租户。我可以浏览到在我租户内创建的企业应用对象,将我的用户分配一个角色(例如“管理员”)。这些角色由应用注册定义,但实例化在我租户的服务主体中。之后,我的令牌中将包含 roles 声明。

2. 错误:请求访问的资源已被删除或不再可用 / 组织缺少所需服务的服务主体

  • 原因:应用定义需要访问其他资源(其他应用对象),其中一些可能是单租户应用,导致同意流程失败。
  • 绕过:直接在我自己的租户内创建所需的服务主体。可以使用 PowerShell 或 Microsoft Graph API 完成。创建后,仍需进行用户分配,并尽可能对各个实例化的应用进行同意。之后,大多数应用便可访问。

总结攻击步骤

  1. 识别多租户应用。
  2. 列出其所需的资源(其他应用)。
  3. 实例化所需的服务主体(在自己的租户)。
  4. 分配角色给自己的用户。
  5. 使用代理工具,在认证请求中将租户 ID 重写为 common
  6. 同意应用。
  7. 攻陷应用。

在我识别的多租户应用中,有 22 个(12.5%) 受此漏洞影响并暴露了内部数据。这还不包括那些我获得了前端访问权限但未能访问后端 API 的应用。


实际案例展示

以下是一些通过此漏洞访问到的内部 Microsoft 应用示例:

1. 紧急广播系统

  • 可向全球每个 Microsoft 365 管理员中心广播消息。我没有发布任何消息。

2. ACE 命令中心

  • 顶级客户支持门户(财富 500 强公司)。可以查看、关闭、编辑所有支持工单。

3. 负责任 AI 运营平台

  • 可管理各种大型语言模型,可能是 Copilot 的“父模型”。

4. 风险登记册(应微软要求已打码)

  • 包含 Microsoft 组织当前面临的所有风险列表。可按安全风险、高严重性、未缓解等条件筛选。这相当于获得了所有已识别但未缓解的零日漏洞概览。

5. 安全智能平台

  • 包含整个 Microsoft 组织的所有数据集(VPN 日志、云 shell 日志、用户、设备历史等),高度机密。平台内嵌了 AI 助手“Sippy”,通过与之对话,可以枚举 Microsoft 云环境中的任何用户和服务主体(存在大量测试账户)。还意外下载到一个包含用户授权码的 40MB 日志文件(但授权码只能兑换一次)。

6. 媒体创建服务

  • 需要同意约 20 个关联应用。用于构建“版本客户端”,可能是 Windows。日志文件中包含 ESD 私钥,这是用于批量许可的密钥,可能用于生成大量 Windows 密钥。还提供了源代码查找工具,并允许上传新工具,极有可能导致远程代码执行。

攻击演示

  1. 已在个人租户创建所需服务主体并分配角色。
  2. 在 Burp Suite 设置规则,将请求中的 Microsoft 租户 ID 替换为 common
  3. 访问内部应用(如“赋能中心”)。
  4. 被重定向到个人租户的身份提供商进行登录。
  5. 成功以管理员身份进入应用,可以查询所有后端数据。

此外,还发现了硬件库存 API 等,可以查询数据中心每个螺丝的序列号。


SAML 身份验证的注意事项

SAML 的工作方式与 OAuth 不同,但使用相同的认证端点。问题在于 SAML 请求中也包含租户 ID,且请求是 Base64 编码和压缩的。攻击时需要实时解码、解压、修改租户 ID、再压缩编码。由于时间有限,未发现易受攻击的 SAML 服务,但此方向值得进一步研究。


时间线、奖励与影响

  • 2024年11月:提交了 4 个案例。
  • 2025年1月:再次提交了 18 个案例。此时,Microsoft Azure 安全威胁狩猎团队也在并行查找环境中的漏洞应用。我可能率先报告了其中 17 个。
  • 修复:Microsoft 成立了专项团队,几乎所有案例在两个月内修复。

漏洞赏金:由于 Microsoft 赏金计划范围仅限面向客户的应用,内部应用不在范围内,因此我未获得奖金。但获得了排行榜积分。

更广泛的影响:在我们自己的客户群中,发现 2% 的客户也存在易受攻击的应用。我们已协助修复。此漏洞在外部依然存在

一个有趣的发现:其中一个应用叫“Microsoft 奖励中心”,我给自己分配了管理员角色,找到了“返利”功能,可以输入任意金额、货币和 PayPal 标识,然后点击“支付”。这证明了“黑客微软仍然是一个无限金钱漏洞”——当然,这是出于研究目的的概念验证,并未实际操作。

现状:Microsoft 表示已修复所有审查过的应用,并实施了更广泛的监控。当我制作幻灯片时再次测试,立即收到了他们的监控邮件。


检测与缓解建议

如何检测自己是否受影响?
我编写了一个简单的 PowerShell 脚本来列出您环境中所有定义了重定向 URI 的多租户应用。

Get-MgApplication -Filter "signInAudience eq 'AzureADMultipleOrgs'" -All | Where-Object {$_.Web.RedirectUris.Count -gt 0} | Select-Object DisplayName, AppId, SignInAudience

您需要检查这些应用是否真正需要多租户特性。对于大多数已识别的案例,多租户配置是偶然的、非必需的。如果确实需要,则必须确保应用逻辑检查访问令牌的 tidiss 声明。

最终建议(要点)

  1. 谨慎使用多租户:仅在绝对必要时才将应用注册为多租户。
  2. 强制验证颁发者:对于多租户应用,必须在应用逻辑中显式检查所接收令牌的 iss(颁发者)或 tid(租户 ID)声明。
  3. 主动狩猎:所有漏洞赏金猎人和渗透测试员,请务必检查此类配置错误,它仍然相当普遍。

总结

在本节课中,我们一起学习了一种新型的 Entra ID 配置错误。通过滥用多租户应用的 OAuth 流程,并利用内部应用不验证令牌颁发者的缺陷,外部攻击者可以获取对敏感内部应用的访问权限。我们从身份验证和授权的基础知识讲起,回顾了历史漏洞,深入剖析了新漏洞的原理、攻击步骤和真实案例,并提供了检测与防御建议。安全始于正确的配置和对安全边界的清醒认知。

协程帧导向编程:通过滥用现代 C++ 破坏控制流完整性 🧠

在本节课中,我们将学习一种新的攻击方法,它利用现代 C++ 中的协程特性来绕过控制流完整性保护。我们将从控制流完整性防御的基础知识开始,深入了解 C++ 协程的内部工作原理,并探讨如何利用这些机制来执行攻击。


概述:控制流完整性的演变 🛡️

50年前,我们首次认识到破坏程序内存可能导致控制其执行的指令。这是今天我们所知的缓冲区溢出的最早提及。

自那时起,安全社区,无论是防御者还是攻击者,都取得了长足进步。一方面,防御者创造了更好的方法来加固内存,例如地址空间布局随机化和不可执行栈。另一方面,攻击者总是能找到绕过这些防御的新方法,例如信息泄露和代码复用。

2005年,学术界引入了控制流完整性。这与经典防御方法不同。它不是在尝试使利用变得更困难,而是从根本上解决问题,即控制程序指令指针的能力。控制流完整性使用静态和动态方法分析程序,构建控制流图,然后对程序进行插桩,强制程序只允许图中描述的合法函数跳转,从而阻止攻击者发起的跳转。

这是一个对防御方非常重大的升级,因为它本质上阻止了我们长期使用的一种技术:返回导向编程以及其他代码复用技术。当然,攻击者也随之升级。我们不是第一个提出绕过控制流完整性方法的人,但今天,我们将指出一种在 C++ 协程中实现的新方法。


现有控制流完整性防御方案 🔍

上一节我们介绍了控制流完整性的基本概念,本节中我们来看看几种现有的、广泛部署的控制流完整性方案。

以下是几种主要的控制流完整性方案:

  • Intel CET:这是目前最流行的方案,是硬件辅助的粗粒度方案。它包含两个部分:

    1. 影子栈:每次调用函数时,返回地址会被推送到一个独立的、用户空间无法访问的影子栈页面上。函数返回时,会比较栈上的返回地址和影子栈中的值。如果不匹配,则触发错误。
    2. 间接分支跟踪:用于保护程序中的间接指针和间接函数。它通过 ENDBRANCH 指令强制执行,确保每个间接跳转都只能跳转到这些指令处,从而只能从函数开头调用。
  • Control Flow Guard:这是 Windows 采用的方案,是软件实现的。它在编译时工作,将程序中的每个间接调用转换为对特定函数的直接调用。该函数通过检查一个位图来判断此次调用是否被允许。函数开头的 __guard_check_icall_fptr 调用就是其标志。

  • LLVM-CFI:这是一种更细粒度的方案。它会计算每个间接指针的动态类型。例如,如果一个间接函数被赋值为 close 函数,它会根据函数的返回类型和参数定义一个原型,并强制所有调用都跳转到具有相同原型的函数。


C++ 协程内部机制揭秘 ⚙️

上一节我们了解了现有的控制流完整性防御,本节中我们来看看攻击者可能利用的新编程范式:C++ 协程。

协程是一种可以暂停和恢复执行的函数。这意味着协程内部有“暂停点”。当再次调用协程时,不会从头开始执行,而是从上次暂停的地方继续。

在 C++ 中实现协程需要几个关键组件:

  • 任务对象:这是最顶层的对象,包含了协程的所有内容。
  • 协程句柄:这是一个指向协程的指针,允许你恢复或销毁协程。
  • Promise 对象:这是一个用于协程和调用者之间传递数据的对象。例如,返回值就存储在这里。

一个函数要成为协程,需要使用特定的操作符:co_yield(暂停并返回值)、co_return(返回并结束协程)或 co_await(等待某个操作完成)。

当协程被编译时,编译器会在后台生成三个关键函数:

  1. 创建函数:负责分配和初始化协程帧。
  2. 恢复函数:负责实际恢复协程的执行。
  3. 销毁函数:负责销毁协程帧。

C++ 协程是“无栈”的,这意味着协程只能在自身内部暂停,不能在它调用的其他函数内部暂停。这导致编译器可以将协程的所有状态(局部变量、参数等)高效地存储在一个堆分配的对象中,即协程帧

一个协程帧的结构如下:

  • 恢复指针:指向恢复函数。
  • 销毁指针:指向销毁函数。
  • Promise 对象:存储返回值等。
  • 参数:调用协程时传入的参数。
  • 局部变量:协程内定义的变量(现在存储在堆上)。
  • 协程索引:一个整数,指示当前位于哪个暂停点。

co_await 是最强大、最常用的操作符,它允许进行异步操作和协作式多任务。它通过评估一个“可等待对象”来工作,该对象包含一个“等待器”,后者会按顺序执行三个函数:await_readyawait_suspendawait_resumeawait_suspend 是执行实际异步操作(如创建新线程)的地方,对攻击者来说非常有趣。


攻击模型与核心原语 ⚔️

上一节我们深入了解了协程的内部结构,本节中我们来看看攻击者如何利用这些结构。

我们的攻击模型与控制流完整性假设的模型相似:

  1. 需要知道程序中某些函数的地址(通常通过信息泄露)。
  2. 需要存在内存破坏漏洞,允许覆盖某些内存。
  3. 目标程序中使用了协程。
  4. 目标程序启用了控制流完整性保护。

一个基本的观察是:协程句柄和协程帧是可写内存。基于此,我们设计了两种核心攻击原语:

以下是两种核心攻击原语:

  • 帧操纵:覆盖一个已存在的协程帧的内容。
  • 帧注入:在内存中注入伪造的协程帧,并让程序将其当作真实的帧来使用。

数据导向攻击 📊

首先,我们看看在不修改指针(恢复/销毁指针)的情况下能做什么,即数据导向攻击。

由于参数在协程创建时就被复制到协程帧中,攻击者可以通过覆盖协程帧和协程索引,跳转到任意暂停点,并使用被覆盖的参数数据执行代码。

对于局部变量,情况稍复杂。如果变量只在某个暂停点初始化并在后续暂停点使用,那么覆盖帧可以修改其值。但如果编译器优化后发现变量在某个暂停点未被使用,它可能延迟初始化,从而使得攻击失效。

更强大的攻击涉及堆分配的对象。例如,如果一个 std::vector 指针存储在协程帧中,并且在最后一个暂停点会被释放,那么覆盖这个指针可以导致对任意地址的 free() 调用,这是一个非常有用的原语。

内存覆盖可能发生在多种场景:

  • 任意内存写。
  • 基于栈的溢出,覆盖栈上的协程句柄。
  • 协程内部的栈溢出(注意,协程变量在堆上,但可能通过缓冲区溢出影响其他帧)。
  • 经典的堆溢出,覆盖堆上的协程帧。
  • 组合利用,例如释放一个指针导致下次堆分配覆盖另一个协程帧。

控制流劫持与无限调用链 🔗

上一节我们探讨了数据攻击,本节我们来看看如何利用指针进行更强大的控制流劫持。

恢复指针和销毁指针对攻击者极具吸引力。然而,在控制流完整性保护下,我们不能简单地覆盖返回地址或虚函数表指针。许多细粒度的控制流完整性方案并未对协程进行插桩,导致协程的恢复和销毁指针不受保护。这暴露了防御机制需要随着编程范式演进而更新。

最终,我们主要面对的是粗粒度控制流完整性方案,如 Intel CET 和 CFG。它们仍然限制我们只能从函数开头调用。虽然我们可以覆盖恢复指针,但通常只能调用一两个函数,且参数受限。

为此,我们设计了一种方法来实现任意次数、任意参数的函数调用。核心是识别控制流指针。CFP 不仅包括恢复和销毁指针,还包括任何指向协程帧的句柄。例如:

  1. 协程句柄本身。
  2. 调度器中管理的大量句柄。
  3. 协程帧内部的指针,如“续延”指针(用于协程调用链中返回)和“销毁器”指针(用于在协程调用结束时隐式销毁被调协程)。

基于这些 CFP,我们设计了无限协程链攻击。攻击步骤如下:

以下是无限协程链攻击的核心步骤:

  1. 在内存中注入多个恶意协程帧。
  2. 从第二个暂停点(一个 co_await 调用之后)恢复恶意链,此时即将调用 destroy
  3. 将下一个帧的销毁指针覆盖为恢复指针,这样调用 destroy 时实际是调用 resume
  4. 链式执行,直到最后一个“蹦床帧”,在此帧中执行任意函数调用(如 system)。
  5. 利用第二个 CFP(如续延指针)再次调用 resume,跳转到另一个蹦床帧执行另一个任意函数。
  6. 此过程可无限重复。

为了设置任意参数,我们利用了 C++ 成员函数的特点:它们使用 this 指针(存储在 RDI 寄存器)作为基址来访问成员变量。我们构造一个“碰撞”,在协程帧中特定偏移处放置我们想要的值,当某个成员函数被调用时,就会将这些值加载到寄存器中。随后,再利用另一个 CFP 进行间接调用,此时寄存器已准备好所需参数。


实例分析与防御建议 🛠️

上一节我们介绍了强大的攻击链,本节我们通过一个实例来具体分析,并探讨可能的防御措施。

我们研究了 SerenityOS 操作系统,它在其浏览器中使用了协程。我们发现了潜在的 CFP。作为概念验证,我们使用了 2021 年 Chrome 浏览器中的一个真实漏洞。该漏洞是一个整数溢出,可导致内存覆盖和信息泄露。我们利用它覆盖了一个间接调用指针,并链接了多个 CFP,最终成功执行了多个带有任意参数的函数调用,绕过了 Intel CET 保护。

协程特性在所有主流编译器中都可用,攻击面广泛。防御措施包括:

以下是几种可能的防御思路:

  • 将指针替换为标识符:不直接在协程帧中存储函数指针,而是存储一个只读表中函数地址的标识符。即使标识符被修改,攻击者也无法直接调用任意函数。
  • 堆分配优化:这是一个编译器优化,可将协程帧从堆移动到栈上。作为副作用,它不再在帧中使用恢复和销毁指针。然而,该优化触发条件苛刻,需要内联、同一翻译单元、知晓完整生命周期等,且并非所有编译器都完全支持或默认启用。
  • 调整协程帧布局:例如,将 promise 对象移到帧末尾,或分配更大的帧,使得通过堆溢出覆盖关键指针变得困难。

总结 📝

本节课中,我们一起学习了如何利用现代 C++ 的协程机制来挑战控制流完整性防御。我们从控制流完整性的背景出发,深入剖析了协程帧的内部结构,并在此基础上构建了数据攻击和强大的控制流劫持攻击链。通过识别和链接控制流指针,攻击者可以绕过粗粒度控制流完整性,实现任意函数的无限次调用。最后,我们探讨了针对此类攻击的潜在防御方向,包括修改协程帧布局和利用编译器优化。这项研究表明,安全防御需要紧跟编程语言和范式的发展,才能持续有效。

通过 HTTP/2 服务器推送和签名 HTTP 交换进行的跨源 Web 攻击 [IeHGk34HG3k] 🔐

在本节课中,我们将要学习一项关于 Web 安全的新研究。我们将探讨现代 HTTP 协议(HTTP/2 和 HTTP/3)中“同源”定义的演变,以及这种变化如何引入新的安全威胁。具体来说,我们将介绍两种新型攻击向量:跨推送攻击和跨 SXG 攻击。课程内容将涵盖攻击原理、实际利用方式、现实世界中的可行性以及相应的缓解措施。

同源策略及其演变

上一节我们介绍了课程概述,本节中我们来看看 Web 安全的基石——同源策略。同源策略旨在保护用户数据免受跨源攻击。

我们通常知道,同源策略中的“源”是基于 URL 的。这意味着只有当两个资源的协议(scheme)、主机(host)和端口(port) 完全相同时,它们才被视为同源。

然而,我们发现这并不是“源”的唯一定义。在深入研究 HTTP 协议规范时,我们发现 HTTP/2 和 HTTP/3 协议引入了一个新的、更宽松的“源”定义,它是基于 证书(Certificate) 的。

具体来说,在 HTTP/2 和 HTTP/3 中,任何列在证书的主题备用名称(Subject Alternative Name, SAN) 列表中的主机都被视为同源。例如,Google.com 的证书可能同时包含 android.comyoutube.com 等域名。在 HTTP/2/3 的视角下,所有这些域名都属于同一个“源”。

这种多域名共享证书的做法非常普遍。已有研究表明,96% 的证书在其 SAN 列表中包含多个域名,其中 3.2% 的证书包含了属于不同组织的域名。这意味着基于证书的“源”可能包含多个不同的实体,它比基于 URL 的“源”定义更为宽松。

新的威胁:跨推送与跨 SXG 攻击

基于上一节介绍的更宽松的“源”定义,一个很自然的问题是:这会为 Web 带来哪些新的安全威胁?这正是我们研究的核心:跨推送攻击和跨 SXG 攻击。

顾名思义,这两种跨源 Web 攻击基于两个旨在提升 Web 性能的服务器交付机制:HTTP/2 服务器推送签名 HTTP 交换

对于本次课程,你需要记住这两个机制的两个关键特性:

  1. 在它们的规范中,两者都遵循基于证书的“源”定义
  2. 服务器推送和 SXG 可以指示(或证明) 共享证书中列出的其他“源”。

结合这两个特性,攻击者可以向列在证书 SAN 列表中的其他“源”推送或提供资源访问权限,即使这些“源”属于其他组织。

基于这些发现,我们提出了两种新的攻击向量:跨推送攻击和跨 SXG 攻击。

以下是攻击流程的概述:

  1. 首先,假设攻击者获取了一个同时包含受害者网站和攻击者网站域名的共享证书。共享证书是我们所有攻击的基础
  2. 攻击开始时,攻击者诱使受害者点击一个恶意链接。
  3. 当受害者访问攻击者网站时,攻击者会利用服务器推送或 SXG 来传递一个恶意脚本,并将其“源”设置为受害者网站。
  4. 由于之前介绍的基于证书的宽松“源”定义,浏览器会将这个恶意的跨源资源视为同源资源,并在加载受害者网站时执行它。

值得注意的是,我们的攻击引入了新的安全影响。在以往的研究中,获得证书的攻击者通常只能发起中间人攻击。相比之下,我们的攻击使得离线攻击者能够利用共享证书发起实际的 Web 攻击,从而导致跨站脚本、Cookie 操纵等利用。

攻击利用细节

上一节我们概述了攻击原理,本节中我们来看看具体的利用方式。由于服务器推送和 SXG 本质上都类似于一个 HTTP 响应,包含 HTTP 头部和 HTTP 正文,因此我们可以从这两方面入手。

以下是几种主要的利用方式:

利用 HTTP 正文发起跨站脚本攻击
我们可以通过将恶意脚本插入 HTTP 正文来发起跨站脚本攻击。令人惊讶的是,由于我们控制了整个 HTTP 响应,这种跨站脚本攻击是通用的。这意味着无论目标网站本身是否存在漏洞、是否离线甚至是否已不存在,我们的攻击都有效。同时,内容安全策略等安全措施也无法阻止此类攻击,因为攻击者不会在恶意响应中设置 CSP 头部。

利用 HTTP 头部发起攻击
我们也可以利用 HTTP 头部发起攻击。

  • 操纵 Cookie:使用 Set-Cookie 头部可以在目标网站上将受害者的 Cookie 设置为任意值(例如攻击者自己的 Cookie),从而导致会话固定攻击。
  • 绕过 HSTS:使用 Strict-Transport-Security 头部,将 max-age 设置为 0,可以有效地移除网站的 HSTS 保护。

组合利用头部和正文发起恶意文件下载
我们可以组合利用 HTTP 头部和正文来发起恶意文件下载。通过使用 Content-Disposition 头部控制 HTTP 正文被视为附件,然后将恶意二进制内容放入正文中,可以诱使用户下载并执行恶意文件。

攻击的现实可行性

到目前为止,我们的攻击看起来威力很大。但有人可能会问:这些攻击在现实世界中是否可行?在下一部分,我们将讨论使攻击变得实用的技术。

我们将回答以下三个关键问题:

  1. 如何获取作为攻击前提的共享证书?
  2. 如何延长攻击持续时间?
  3. 如何绕过潜在的对策(例如受害者撤销共享证书)?

获取共享证书
获取共享证书是执行攻击的主要前提。虽然 HTTP、DNS 和电子邮件中的某些偶然漏洞可能帮助攻击者获取非法证书,但我们的重点是证书生态系统中的固有漏洞。

我们发现,目前没有机制能确保证书所有者与域名所有者始终保持一致。因此,我们提出了两种创造攻击条件的方法:域名转售和域名劫持。

  • 域名转售:攻击者可以购买大量域名,为它们签发一个多域名证书,然后将部分包含的域名转售给受害者,同时保留共享证书。这样,攻击者就轻易创造了攻击条件。
  • 域名劫持:当域名指向废弃的虚拟主机 IP、已注册但未使用的 CNAME 记录或刚刚过期的域名时,就可能发生域名劫持。由于这些目标是公开可用的,攻击者可以注册这些被废弃的服务,将其 DNS 记录指向攻击者控制的基础设施,并通过 HTTP 挑战等方式签发证书,从而获得包含被劫持域名的共享证书。

延长攻击持续时间
影响攻击可行性的另一个关键因素是攻击持续时间。传统的域名劫持攻击在受害者移除错误的 DNS 记录后会失效。相比之下,我们的攻击在 DNS 记录被移除后仍然有效,直到证书过期(通常为 398 天)。

然而,我们的研究发现,一个名为域名验证重用的用户友好机制,有可能将攻击持续时间延长至 796 天。该机制允许先前已通过域名所有权验证的证书申请者,在特定时间窗口内申请新证书时跳过重新验证。这个时间窗口最长可达 398 天。因此,攻击者可以在证书到期前的最后一天重新申请新证书,从而将攻击持续时间从 398 天最大延长至 796 天。这意味着即使 DNS 记录被移除,我们的攻击在两年多的时间里仍然有效。

绕过证书撤销对策
有人可能会想到,证书在我们的攻击中至关重要,因此一个潜在的对策是通过证书透明度日志检测并撤销未经授权的证书。那么攻击者是否有方法绕过这个对策呢?答案是肯定的。

我们引入了一种使未经授权证书不可撤销的策略。根据 Let‘s Encrypt 的文档,要撤销一个证书,必须满足以下两个条件之一:

  1. 签发者必须通过证书中包含的所有域名的所有权验证。
  2. 或者,拥有证书的私钥。

考虑一下,如果攻击者签发了一个同时包含攻击者域名和受害者域名的共享证书,会发生什么?不幸的是,受害者不满足任何撤销条件。这种共享的证书对受害者来说是不可撤销的。我们也在实际平台上进行了实验,报告了一个与我们域名共享的非法证书,但未收到回复。

现实世界影响评估

为了评估我们攻击在现实世界中的影响,我们进行了一次大规模测量。在客户端,我们测量了哪些浏览器接受服务器推送和 SXG;在服务器端,我们测量了哪些网站可能允许攻击者获取共享证书。如果两个条件都满足,就可能使攻击者发起我们的攻击。

客户端测量结果
我们的客户端测试目标包括 StatCounter 上的主流浏览器、主流移动设备上的不同浏览器以及苹果应用商店中的流行应用程序。考虑到日常生活中使用的浏览器种类繁多,我们无法手动收集所有数据。因此,我们开发了一个名为 PS Checker 的自动测量系统。

该系统机制很简单:我们使用一个受控的高流量网站将流量引导至一个功能测量服务器的 iframe。该服务器然后使用服务器推送和 SXG 进行跨源脚本推送。最后,通过检查脚本是否被执行,我们可以判断浏览器是否支持服务器推送和 SXG。

运行 PS Checker 一个月后,测量结果显示漏洞浏览器广泛存在。11 款最常用浏览器的最新版本以及 5 款默认移动浏览器中,至少有一款容易受到我们其中一种攻击。同时,我们惊讶地发现,一些流行应用程序使用了基于移动操作系统 WebView 组件的内置浏览器,这些浏览器继承了与 WebView 相同的漏洞。这显著地将攻击面从浏览器扩展到了第三方应用程序。

服务器端测量结果
为了衡量对服务器端网站的影响,我们首先测量了“转售域名”(这是我们之前讨论的攻击者获取共享证书的潜在方法之一)。我们利用 WHOIS 历史数据来识别那些曾被转售给不同所有者的域名。

对于另一种方法“悬空域名”,我们利用了一个发表在安全顶会上的最先进工具 Hosting Checker 来检测此类易受攻击的域名。

我们还考虑了“第三方共享域名”。虽然这些域名本身不允许攻击者直接获取共享证书,但它们揭示了一种安全依赖关系。也就是说,如果这些域名中的任何一个被攻破,那么与它们共享证书的高排名域名也可能变得易受我们的攻击。

我们的测量方法如下:首先,我们从 Top 1000 网站中抓取其证书 SAN 列表中列出的所有域名,以识别它们的关联域名。然后,我们从 HTTP 响应、错误日志和被动 DNS 数据中提取这些关联域名的子域名。最后,我们检查这些关联域名是否与 Top 1000 网站共享证书。

评估结果显示,大量网站受到影响。一些案例甚至影响了知名网站。例如,排名 3895 的 ftstatic.com 曾从一家澳大利亚食品公司转售给一家美国广告公司,可能被原域名所有者利用。微软的一个与 Windows 更新相关的子域名 subtleway.of.windowsupdate.com 曾是悬空域名,可以被任何攻击者注册。此外,许多高排名域名与低排名域名共享证书,这些低排名域名甚至来自不同的组织,有可能对 Top 1000 网站发起我们的攻击。这种情况在 baidu.com 上得到了证实。

真实世界案例:微软域名漏洞

当然,我们知道空谈无益。因此,在下一部分,我将展示我们在微软发现的一个真实世界案例。

根据测量,我们发现微软一个与 Windows 更新相关的域名的 CNAME 记录指向了一个未注册的域名。攻击者只需购买并注册这个 qtlcdn.net.com,然后配置 DNS A 记录指向攻击者服务的 IP 地址。结果,域名所有权得到验证,攻击者可以签发共享证书并发起我们的攻击。这是我们之前获得的与微软域名共享的证书。当然,该漏洞已被报告,证书已被我们撤销,微软也已修复了此问题。

我们记录了在过去对微软域名发起跨站脚本攻击的视频。在通过域名劫持获得共享证书后,我们设置了一个 HTTP/2 攻击服务器。然后,我们模拟受害者点击恶意链接。我们受控的攻击服务器向微软网站推送了一个 alert(document.domain) 脚本并触发了重定向。与之前的跨站脚本演示类似,我们成功在微软域名上执行了 alert 脚本。

缓解措施与总结

最后,让我们讨论如何缓解我们的攻击。我们为不同方提出了以下对策:

对于浏览器厂商
他们应在浏览器中执行一致的权限检查以缓解跨推送攻击,并强制使用单域名证书以防止跨 SXG 攻击。

对于证书颁发机构
我们建议他们提供一种机制,允许域名所有者将其域名从已签发的共享证书中移除。

对于用户
我们建议他们检查域名注册中的证书状态,以检测未经授权的共享证书。

正如你所见,我们的攻击涉及多方:浏览器、证书颁发机构、域名系统。因此,解决此安全问题需要所有利益相关者的共同努力。我们也已负责任地向受影响的厂商披露了我们的发现。7 家厂商确认了漏洞,其中 5 家(包括华为、百度、微软等)已修复此问题。我们还在 IETF 网络安全工作组发起了一场讨论,探讨 PKI 中的弱点。如果你对这些问题感兴趣,欢迎加入我们的讨论。

总结
在本节课中,我们一起学习了以下内容:
我们观察到 HTTP/2 和 HTTP/3 中基于证书的“源”定义比浏览器基于 URL 的“源”定义更为宽松。基于这一发现,我们提出了两种新的跨源 Web 攻击:跨推送攻击和跨 SXG 攻击。这些攻击使得离线攻击者能够利用共享证书发起实际的 Web 攻击。

我们还演示了如何利用 PKI 中的弱点来促成我们的攻击。我们展示了如何利用域名所有者与证书所有者之间的错位来创造攻击条件(例如通过域名转售)。我们介绍了域名验证重用如何延长证书寿命,从而延长攻击持续时间。同时,我们揭示了一个事实:尽管你控制着域名,你可能无法轻易撤销一个包含你域名的证书,这使得攻击者能够绕过撤销未经授权证书等对策。

我的演示到此结束。感谢聆听。

一个失败的补丁如何让 VMware ESXi 虚拟机逃逸漏洞敞口两年 🕵️♂️

在本节课中,我们将学习一个关于 VMware ESXI 虚拟机逃逸漏洞的深度技术分析。我们将了解一个在 2021 年被报告但未能被正确修复的漏洞,如何直到 2024 年才被真正修补,以及研究人员如何利用它实现完整的虚拟机逃逸和沙箱突破。

概述与背景

大家好,我是 Yu Haojiang。今天,我和我的同事 Zmin 将介绍“黑暗角落:一个失败的补丁如何让 VMware ESXi 虚拟机逃逸漏洞敞口两年”。这项研究是我、Xinlei 和 Zmin 的合作成果。

我们是安全研究员,来自奇安信集团安全实验室,曾多次成功实现虚拟机逃逸,并在 2023 年获得了 Pwn2Own 奖项。

以下是我们的课程路线图:

  • 首先,我们将简要介绍 ESXi 及其架构。
  • 其次,我们将深入探讨 ESXi 虚拟机逃逸的两个主要组成部分:从虚拟机中逃逸,以及逃逸 ESXi 沙箱。
  • 最后,我们将以一个演示视频作为总结。

现在,让我们从介绍部分开始。

在深入技术细节之前,先分享一下我们进行这项研究的背景。今年早些时候,VMware 披露了几个已被在野利用的漏洞。这突显了 ESXi 漏洞在真实世界场景中的潜在影响和危险性。

由于我们在 2023 年天府杯上成功演示了 VMware ESXi 虚拟机逃逸,我们认为来这里分享这个故事背后的一些有趣细节会很有价值。

ESXi 架构简介 🏗️

现在,让我们看看 ESXi 的架构。作为一个虚拟化平台,它与 VMware Workstation 非常相似。然而,其底层主机操作系统被替换为 VMkernel,这是一个专门的虚拟机监控程序内核。

此外,它还有一个沙箱系统,为每个进程提供细粒度的权限控制。

虚拟机逃逸的攻击面分析

接下来,让我们转向虚拟机逃逸部分。首先,我们来审视 ESXi 虚拟机监控程序的攻击面。我整理了一个表格,这是去年演讲中表格的更新版本,添加了一些新信息。

它全面记录了近年来所有公开披露的关键漏洞及其影响的模块。

我们可以看到,当前 VMware 虚拟机监控程序的攻击面主要由虚拟设备和客户机 RPC 构成。2024 年之前的大多数漏洞都与 USB 相关。这些包括虚拟 USB 控制器和蓝牙设备。虚拟蓝牙设备通过 UHCI 控制器连接。然而,我注意到 VMware 后来移除了蓝牙设备,因此这个攻击面可能已不存在。

今年,我们看到了其他模块中出现的漏洞,例如 CSI、VMX、net3 和 VMCI。本质上,我们寻找的是可以从虚拟机内部触发,但不会受到客户机操作系统本身干扰的模块。

一个古老漏洞的故事

现在,让我们来谈谈一个故事。我们的故事始于一个古老的漏洞。2023 年,当我们决定参加天府杯时,我们开始研究 VMware。我们检查了当时最新修补的漏洞,即 2021 年天府杯期间报告的漏洞。这个漏洞是由来自昆仑实验室的 Way 发现的。我们可以看到,这是 xHCI USB 控制器中的一个释放后使用漏洞。

在继续分享我们的分析工作之前,让我简要介绍一些 xHCI 对象。蓝色部分来自 xHCI 规范,紫色部分是 VMware 特有的。

首先,Slot 对象代表一个 USB 设备。每个设备有 31 个端点,用于配置出站数据传输和入站数据传输。每个端点可以有字符串上下文,对应 TR 环,用于存储数据包。

现在,紫色部分是 VMware 特有的对象。Pipe 管理端点的数据传输,URB 代表正在处理的数据包。所有 URB 都由 Pipe 管理。

这个释放后使用漏洞的关键变化位于两个 HCI 命令环处理函数中。这些变化重新编排了 Slot 上下文重写和执行 xHCI 清除字符串上下文的顺序。

我们可以从下面源代码中的红色方框看到这一点。这意味着在旧版本中,我们可以在执行 xHCI 清除字符串上下文之前修改 Slot 上下文。

那么,我们能利用它做什么呢?让我们看看 xHCI_ClearStringContext 函数。它执行 xHCI_DeleteStringContext,并依次调用 xHCI_FetchPipexHCI_CleanPipe

xHCI_CleanPipe 中,我们可以看到它首先检查临时端点变量中是否存在 Pipe。如果存在,它将执行 CancelPipe,这会释放该 Pipe 管理的所有 URB。

但这也意味着,如果 xHCI_FetchPipe 失败,CancelPipe 将完全不会被执行。

那么,在 xHCI_FetchPipe 中我们能做什么呢?我们可以看到,它从存储的上下文中读取内容,然后执行检查。如果检查失败,它直接返回 0。那么,这个临时端点变量中将不会有任何 Pipe。

所以流程是这样的:正常情况下,当我们删除字符串上下文时,它会执行 CancelPipe 释放 URB,最后释放字符串上下文。但是,如果我们能修改存储的上下文,它将跳过 Pipe 处理,直接执行后续代码。

现在,我们可以在字符串上下文被释放后,让 Pipe 不被释放。接下来我们能做什么?

我们发现 URB 有一个指向字符串上下文的指针。当一个 URB 完成时,它会从字符串上下文中减去 URB 数据包的大小。

由于在删除字符串上下文时我们可以跳过 Pipe 处理,URB 和 Pipe 得以保留,但字符串上下文已经被释放。因此,如果我们能手动清除 Pipe,它将释放 URB,导致它在已释放的字符串上下文中执行减法操作。这就是释放后使用漏洞。

补丁的失败与漏洞重现

在理解了这个旧漏洞后,我决定查看 VMware 当时的最新版本。我发现 VMware 在 xHCI_FetchPipe 函数中添加了新代码。本质上,它引入了一种获取 Pipe 的新方式。所以现在有两种基于 Slot 状态的方法。

这使我能够修改这个特定的 Slot 成员,以达到与原漏洞相同的效果,即在修改后无法找到 Pipe,从而完全不处理 Pipe。流程是这样的。但由于时间限制,这里不深入细节。

是的,所以我们发现了一个新漏洞,对吧?这看起来相当令人兴奋。

但是等等,故事没那么简单。实际上,这个亚洲漏洞隐藏着更多秘密。实际上,我们不需要新代码就能让 HCI_FetchPipe 函数失败。

我们发现这个补丁从未成功。让我们再看一下 xHCI_ClearStringContext 函数。它实际上有一个 EPID 参数来指定端点。

根据我们之前对 xHCI 对象的介绍,我们知道每个端点都有其对应的字符串上下文数组。这意味着 xHCI_ClearStringContext 只删除特定端点的字符串上下文。

但是整个 Slot 的内容已经被我们修改了。所以我们可以修改 Slot 内容,然后清除一个端点的字符串上下文。接着,我们可以执行一个禁用 Slot 的命令来清除所有端点的字符串上下文,从而触发释放后使用漏洞。

所以它从未被成功修补。

漏洞利用的挑战与突破

现在,让我们进入漏洞利用部分。让我们更仔细地看看这个释放后使用漏洞。这个漏洞实际上给我们的利用工作带来了巨大挑战。

这是一个约束条件非常严格的释放后使用漏洞。首先,它只影响已释放内存块偏移 +0x205C 处的值,而使用操作是从该地址的 4 字节值中减去一个值。

这带来了几个困难:

  1. +0x205C 不是一个 64 字节对齐的地址偏移。这意味着如果我们想用这个释放后使用漏洞来修改堆块中的指针,我们只能修改该指针的高 4 字节。但修改指针的高 4 字节对于利用来说完全没有意义,因为即使只加 1,也会使指针跨越 4GB 的内存空间。
  2. +0x205C 也是一个非常大的偏移值,这意味着我们在堆布局整理时需要做得更好。

所以我们需要一些方法来解决这个问题。这对于一个闭源目标来说也相当具有挑战性。

幸运的是,我找到了一个完美的原语。这个完美的原语就是哈希表。我相信你们都知道哈希表是什么。VMware 的哈希表是这样工作的:每个元素有一个值和一个键,它们存储在一个堆块中。当存储超过容量时,哈希表的大小会翻倍。

更妙的是,xHCI 字符串上下文哈希表正好拥有我们需要的结构。每个元素是一个 8 字节的指向字符串上下文的指针,加上一个 4 字节的 ID,总共正好是 12 字节。

这太完美了。我们的释放后使用漏洞现在可以修改第二个元素,其中指针起始于偏移 +0xC 处。现在,我们可以修改这个字符串上下文指针的低 4 字节。有了这个原语,我们受约束的释放后使用漏洞突然拥有了巨大的潜力。我们可以让这个指针指向一个我们可以控制的伪造字符串上下文。

可用的其他利用原语

让我们看看我们手头还有哪些其他原语。

第一个是 URB 对象。这是我们去年分享过的对象,我们用它开发了一套全新的利用原语。它非常强大。我们可以任意控制它的大小、分配或释放它。它有一个由 lens 成员管理长度的数据数组,并且它还有许多指针,使其在各个方面都非常有用。

在这里,我还想分享一些我们去年没有发现的事情。我们发现 VMware Linux 版本中的 VMware USB 仲裁程序没有剥离符号。因此,我们可以获得许多与 USB 相关的符号,例如 URB 的符号。这对我们正在进行的研究非常有帮助。

第二组原语是 MOB SurfaceGMR。它们都属于 VMSVGA 模块,即图形模块。有关详细信息,您可以查看 VDI 在 2018 年发布的博客文章。通过这些对象,我们可以轻松地执行堆喷射和堆风水。

此时,我们实际上已经有了足够的可用原语。是时候将它们组合起来,完成我们的利用了。

完整的利用链构建

为了更好地与大家分享,我简化了相关内容。实际的堆布局和操作比这更复杂。

首先,我们需要执行信息泄露以获取堆地址。

  1. 我们首先分配一个字符串上下文,然后触发漏洞。它会被释放,随后我们可以在其 +0x205C 偏移处减去一个值。
  2. 接下来,我们分配一个大小为 0x2050 的 GMR 堆块,它将占据前部空间。此时,我们的能力变为修改后续堆块偏移 +0xC 处的值。
  3. 然后,我们可以在 GMR 后面分配一个 URB,而 URB 的 actual_lens 字段恰好位于 +0xC 位置,非常完美。
  4. 现在,当我们触发释放后使用漏洞中的“使用”操作时,我们可以将 URB 的 actual_lens 向下减去一个很大的值,从而允许我们对 URB 之后的内容进行越界读取。
  5. 如果我们在该设置后面的内存区域中预先布置了包含堆地址的内容,我们就可以成功泄露这些地址。

在获取堆地址后,我们就可以开始在这次利用中伪造各种对象。由于我们使用字符串上下文哈希表作为原语,我们需要伪造字符串上下文。

  1. 我们可以在后续内存中放置一个字符串上下文,然后触发漏洞。同样,我们只释放字符串上下文,然后使用哈希表占据适当的位置。
  2. 当我们触发释放后使用漏洞的“使用”操作时,原始指针将被减去一个值,最终指向我们伪造的字符串上下文。
  3. 虽然我们无法直接用这个伪造的字符串上下文做太多事情,但我们可以使用 xHCI_ClearStringContext 函数来释放它。此时,它仍然是 URB 堆块的一部分。因此,我们可以实现堆块重叠的能力。
  4. 由于 ESXi 使用 GC 来管理堆,这种堆块重叠能力非常强大。

最后,我们可以进入控制流劫持步骤。现在我们有了堆地址和堆块重叠能力。下一步是找到一个可以调用函数指针的地方。

我们发现,从字符串上下文中减去 URB 大小的函数实际上是 URB 中存在的 VUSB 设备对象内的一个函数指针。因此,我们可以伪造 URB 的 VUSB 设备对象来实现任意地址调用。

此时,我们实际上已经完成了虚拟机逃逸。然而,为了执行后续的沙箱逃逸,我们需要执行任意 shellcode 的能力。执行 shellcode 的方法是找到用于栈迁移的 gadget,然后使用 ROP 创建可执行内存,复制 shellcode 并执行它。

总结与反思

至此,我们回顾了关于 ESXi 虚拟机逃逸的故事。现在,让我们回顾一下这一切背后的安全问题。

我们发现 CVE-2021-2205 从未被正确修补。我们在 2023 年报告了这个问题,它获得了一个新的 CVE 编号:CVE-2024-22252。然而,没有人指出这两个漏洞实际上是同一个。

我们还看到了 VMware 今年早些时候关于这些漏洞在野被利用的公告。这证明了 ESXi 逃逸的真实价值。

但另一方面,一个 2021 年的漏洞直到 2024 年才被真正修复。这种现象值得反思。

我认为有几个原因:

  1. 首先,也是最重要的,漏洞赏金计划的奖励金额远低于这些漏洞的实际价值。这导致更少的人愿意向 VMware 报告关键漏洞。
  2. 更多的安全研究人员选择在像天府杯和 Pwn2Own 这样的安全竞赛中使用这些漏洞。但这些一年一度的竞赛不可避免地延长了漏洞的生命周期。或者,更多的漏洞利用可能被用于在野攻击,而不是被披露给安全竞赛。
  3. 其次,VMware 是闭源软件,入门门槛较高,导致研究 VMware 的研究人员非常少。
  4. 这引出了我们的第三点:社区缺乏与 VMware 相关的技术分享。这也是我们这两年在本会议上分享 VMware 逃逸技术的动机。

课程 2:VMware ESXi 沙箱逃逸技术 🔓

上一节我们介绍了如何从 VMware ESXi 虚拟机中逃逸。本节中,我们来看看如何逃逸 ESXi 的沙箱。在实现虚拟机逃逸后,我们可以在主机系统上运行代码,但 VMX 进程仍然在沙箱内。这意味着我们无法执行许多操作,例如开启 SSH、关闭防火墙以获取主机的完全控制权。我们必须逃逸沙箱。

ESXi 沙箱工作原理

首先,让我解释一下沙箱是如何工作的。一个 ESXi 系统只有一个用户,即 root 用户。它使用安全域来限制进程对文件、网络的访问。

在 shell 中,我们可以使用以下命令查看沙箱规则。ESXi 有超过 100 个沙箱域,每个进程驻留在其中一个域中。当虚拟机启动时,ESXi 为 VMX 进程创建一个新的沙箱域。我们重点关注它。

查看规则,我们可以看到对此系统调用的限制。有些规则很容易理解,比如 ioctlopen 等,但有些像 vmcall,我们需要知道它们的含义。

为了知道可以使用哪些系统调用,我们必须查看 VMkernel。带有符号的 VMkernel 可以从系统中的这个文件提取。我们可以使用 find 命令定位此文件。

检查内核代码后,我们了解到:vmcall 有三个系统调用表。使用的表取决于系统调用号。如果号码小于 400,它使用初始表,例如 openreadwrite,与 Linux 相同。我们可以添加超过 700 个新的系统调用,就像图中所示。这似乎是一个更大的攻击面。

但并非所有系统调用都在沙箱中允许。沙箱对系统调用的限制主要在这个函数中。它执行两项检查:

  1. 检查强制级别,类似于 Linux 安全增强模式域有强制、许可、禁用等级别。如果级别为 0(禁用),该函数直接返回成功。
  2. 如果级别为强制,则检查访问掩码。每个域都有一个访问掩码,一个显示其能做什么的数字。vmcall 定义了许多访问类别类型,如 generic。每个访问掩码中的位代表一个类别,每个系统调用属于一个访问类别。例如,如果一个域同时具有 genericvmmax 权限,其掩码将是 3。而这个函数是一个系统调用函数,它属于 generic 类别。

所以,如果我们能列出每个系统调用的访问类别,我们就知道可以使用哪些系统调用。

切换到其他沙箱域的方法

接下来,我将讨论如何切换到另一个沙箱域。有两种方法。

第一种方法是通过在此系统调用的参数中添加安全域。这个参数可以是一个整数(域索引)或字符串(域名)。如果你想在沙箱域中测试你的程序,有一个简单的方法,只需将此添加到命令行。

我们能通过这种方式逃逸沙箱吗?然而,只有特权域和转换域才能使用此方法。列表如图所示。

另一种切换到沙箱域的方法是当二进制文件具有 VMware 安全属性时。以下是 getxattr 函数。域的标签用于查找域对象,然后进行转换。

同样的问题:是否可以通过设置二进制文件的扩展属性来逃逸沙箱?答案是否定的。

  1. 首先,此系统调用在沙箱中被阻止。我们需要 VMK_SAYS 权限。
  2. 其次,安全域有一个加载目标列表。例如,VMX 域只能切换到 TPM 域,如图所示。一个链表用于存储允许转换的所有域。

发现沙箱逃逸的突破口

现在,我们可以完全理解沙箱规则了。该命令显示了四个部分的规则:文件、系统调用和转换。每个部分都可能成为攻击系统的途径。

在检查规则时,我看到了有趣的东西。VMX 进程对 CBT 设备具有读写访问权限。什么是 CBT?更改块跟踪用于跟踪虚拟机磁盘的哪些部分已更改。

让我们看看这个 CBT 驱动程序。CBT 驱动程序是一个文件设备服务驱动程序,通过此函数添加到内核。主要功能是 CBT_IOCTL。我们可以通过两种方式调用它:

  1. 打开默认的控制设备,然后使用 ioctl
  2. 使用 CBT_MakeDev 创建一个新设备。例如,创建 power1 设备,打开并使用 ioctl

这两种方式进入不同的代码路径。我们关注第二种方式。CBT_MakeDev 首先调用此函数,创建一个 CBT 设备对象,存储用户输入的填充句柄,并使用此函数获取文件大小。最后,基于文件大小创建一个位图对象。位图用于跟踪更改的块。

CBT 驱动程序中的漏洞

此函数 UpdateBitmap 中存在一个漏洞,它基于用户提供的偏移和大小导致越界写入,但没有进行充分检查。所以,如果我们能进入此函数,我们就可以在位图末尾之后写入,获得越界写入原语。

但在此之前没有问题。代码调用此函数,它会检查偏移和大小不能大于文件大小。但是,这里有一个技巧:位图大小是在文件首次检查时设置的。但如果我们后来使文件变大,位图大小不会改变。所以,让我们向文件写入更多内容使其变大。现在,我们的偏移和大小可能小于新的文件大小,但位图仍然很小,因此我们可以写入其边界之外。现在我们有了一个越界写入原语。

现在,我们可以在堆对象上触发越界写入。我们可以覆盖哪个对象呢?首先,我想到在内核中寻找

解密 Signal:理解端到端加密的真实隐私保障 🔐

在本节课中,我们将深入探讨 Signal 应用的安全审查过程。我们将学习 Signal 的工作原理、它所承诺的隐私保障,以及在审查过程中发现的一些漏洞。课程将分为三个主要部分:安全审查方法介绍、Signal 的设计与加密原理解析,以及具体的实现细节与漏洞分析。

第一部分:安全审查方法论 🧐

上一节我们介绍了课程的整体结构,本节中我们来看看进行安全审查时采用的方法论。

我的安全审查通常从四个层面思考一个应用:

  1. 设计:系统应该做什么,规格说明书是如何定义的。
  2. 意图:工程师如何理解设计,以及他们打算如何实现。
  3. 实现:工程师实际编写的、用于表达其意图的代码。
  4. 执行:代码在运行时的行为及其边界情况。

在每个层面都可能存在不同的安全漏洞,并且发现这些漏洞需要不同的技能和技术。

此外,我将漏洞大致分为四类:

  • 语言特定漏洞:例如,审查 C/C++ 代码时可能发现内存损坏问题。
  • 应用程序特定漏洞:例如 SQL 注入。
  • 逻辑漏洞:业务逻辑或流程中的缺陷。
  • 产品特定漏洞:与特定功能实现相关的漏洞。

在本次 Signal 的审查中,我们将涉及上述多个类别。

第二部分:Signal 架构与加密原理 🏗️

上一节我们介绍了审查的框架,本节中我们来看看 Signal 的整体架构和核心加密机制是如何工作的。

我们可以用一个类似物理邮件的类比来理解 Signal。发送方(Alice)写好信,装入信封,投递到邮箱。邮递公司(Signal 服务器)拾取信封,将其路由到收件人(Bob)的邮箱。收件人收取并阅读信件。

在未加密的情况下,信封是透明的,服务器可以阅读内容。Signal 的目标就是让这些信封变得不透明(加密)。

密钥协商与加密

为了实现用户间的加密通信,双方需要协商一个共享密钥。这通常通过迪菲-赫尔曼密钥交换协议实现。

迪菲-赫尔曼密钥交换的简化类比

  1. Alice 和 Bob 公开约定一种公共颜料(公共参数)。
  2. 双方各自选择一种秘密颜色(私钥)。
  3. 双方将自己的秘密颜色与公共颜料混合,得到混合颜色(公钥),并通过公开网络交换。
  4. 双方收到对方的混合颜色后,再混入自己的秘密颜色。最终,双方得到相同的最终颜色(共享密钥)。从混合颜色反推出原始秘密颜色在计算上是不可行的。

Signal 使用椭圆曲线迪菲-赫尔曼算法。用于建立会话的临时密钥称为“预密钥”。这些密钥由一把称为“身份密钥”的长期密钥签名,身份密钥在账户生命周期内基本不变,且几乎从不离开设备。

一旦 Alice 和 Bob 通过迪菲-赫尔曼交换获得了共享密钥,他们就可以开始加密消息了。

前向保密与后向保密

然而,这里存在一个攻击面:如果服务器保存了所有加密消息的副本,而攻击者后来窃取了用户设备上的密钥,他就能解密所有过去的对话。这破坏了“后向保密性”。

解决方案是为每条消息使用唯一的密钥。Signal 通过“链密钥”和“消息密钥”来实现:

  1. 从迪菲-赫尔曼共享密钥派生出一个“链密钥”。
  2. 将链密钥输入密钥派生函数,输出一个“消息密钥”和一个新的“链密钥”。
  3. 使用消息密钥加密本条消息,加密后立即丢弃该消息密钥。
  4. 新的链密钥用于派生下一条消息的密钥。

这个过程可以形象地看作一个“棘轮”:每发送一条消息,棘轮就向前转动一格,无法倒退。这解决了后向保密性问题。

但还有“前向保密性”问题:如果攻击者当前窃取了设备上的棘轮状态,他就能解密所有未来的消息。Signal 通过“双棘轮协议”解决:在对话方向改变时(例如从 Alice 发送变为 Bob 回复),双方会协商一个新的迪菲-赫尔曼共享密钥,从而创建全新的棘轮,旧棘轮被废弃。这样,即使当前密钥泄露,未来的通信也能得到保护。

元数据保护:密封发送者

除了消息内容,通信的元数据(如谁在和谁通信)也可能泄露隐私。Signal 的“密封发送者”功能旨在隐藏发送者身份。

其原理是:发送者将包含接收者信息和加密消息的整个数据包,再用一层仅接收者能解密的密钥加密。这样,Signal 服务器只能看到一个需要投递给 Bob 的加密包裹,而不知道包裹来自 Alice。

第三部分:实现细节与发现的漏洞 🐛

上一节我们探讨了 Signal 的设计原理,本节中我们将深入代码实现,并查看在审查中发现的具体问题。

漏洞一:明文信封处理不当

Signal 协议允许一种特殊的“明文”信封类型,仅用于一种情况:当接收方无法解密消息时,向发送方发送“重试请求”。该明文信封应只包含一个“解密错误”消息。

然而,审查发现客户端对此验证不严:

  • iOS 客户端:完全未验证明文信封的内容,导致恶意服务器可以向任何对话注入任意类型的消息(如文本消息、编辑消息)。
    • 修复:添加检查,确保明文信封有且仅有“解密错误”内容。
  • Android 客户端:验证了明文信封必须包含“解密错误”消息,但遗漏了对“数据消息”的检查。因此,恶意服务器可以发送一个同时包含“解密错误”和“数据消息”的明文信封,Android 客户端会处理其中的数据消息。
    • 修复:添加检查,确保明文信封不包含数据消息。
  • 桌面客户端:验证逻辑与 Android 类似,但由于代码执行顺序(先处理“解密错误”,处理完后函数返回),实际上阻止了后续恶意内容的执行,因此是安全的。

漏洞影响:恶意服务器可利用此漏洞,在用户不知情的情况下,向任何 Signal 对话中注入消息。

漏洞二:同步消息缺少身份验证

Signal 支持多设备链接。为了同步状态(如已发送消息、已读回执),设备间会通过一种特殊的“同步消息”进行通信,这些消息使用相同的端到端加密协议。

关键的安全要求是:设备必须验证同步消息确实来自用户自己的其他设备,而不是其他任何人。

审查发现:

  • Android 客户端:在处理同步消息时,缺少对发送者身份的验证。这意味着攻击者 Mallory 可以向 Bob 的 Android 设备发送加密的同步消息,Bob 的设备会信以为真并执行相应操作(例如,更改 Bob 的已读回执设置,甚至在他的对话中注入消息)。
  • iOS 和桌面客户端:正确验证了同步消息的发送者身份。

漏洞影响:攻击者可以向 Android 用户发送恶意同步消息,零点击(无需用户交互)修改其应用状态或注入消息。该漏洞在发现当天即被修复,并且由于 Signal 强制客户端在3个月后必须更新,目前应已无受影响的客户端。

总结 📝

本节课中,我们一起学习了 Signal 端到端加密消息应用的安全审查之旅。

我们首先了解了从设计、意图、实现到执行的多层安全审查方法。接着,深入探讨了 Signal 的核心架构,包括如何使用迪菲-赫尔曼协议建立安全会话,以及通过双棘轮机制实现前向和后向保密性。我们还了解了 Signal 通过“密封发送者”功能来保护元数据隐私的努力。

最后,我们剖析了在代码实现中发现的两个关键漏洞:明文信封滥用导致的服务器端消息注入,以及同步消息缺少身份验证导致的客户端状态篡改。这些漏洞属于逻辑和产品特定类别,这也符合成熟高质量应用中漏洞类型的演变趋势。

总体而言,Signal 的设计展现了强大的隐私保护理念,其开源特性也促进了安全审查和快速修复。本次审查揭示了即使在一个设计精良的系统中,实现细节上的疏忽也可能引入风险,强调了安全编码和严格验证的重要性。

Linux内核中安全关键内核对象的确定性定位去随机化 🎯

在本课程中,我们将学习如何利用微架构侧信道攻击,结合内核防御机制的特性,来精确定位Linux内核中的关键对象,并构建稳定的内核提权利用链。我们将从TLB侧信道的基础开始,逐步深入到如何利用这些信息实现可靠的内核攻击。

概述

内核利用通常始于在非特权上下文中获得初始代码执行能力。攻击者的目标是通过利用内核漏洞进行权限提升。传统方法依赖于猜测或概率性的内存布局,容易导致系统崩溃和利用失败。本课程介绍一种方法,通过结合TLB侧信道内核防御机制的副作用,能够可靠地定位目标内核对象,并将其转化为强大的任意读写原语,从而实现稳定、隐蔽的提权。

TLB侧信道基础

上一节我们介绍了内核利用的挑战。本节中,我们来看看攻击的基础——翻译后备缓冲器侧信道。

TLB是CPU中用于缓存虚拟地址到物理地址转换的硬件单元,用于加速内存访问。其工作流程可以简化为:

  1. 虚拟地址通过一个函数(如异或)生成一个索引,指向TLB中的特定组。
  2. 在该组的所有路中,比较标签以查找匹配的转换条目。
  3. 若命中,则快速返回物理地址;若未命中,则需进行耗时的页表遍历。

这种命中与未命中的时间差构成了侧信道的基础。测量代码的核心逻辑如下:

start = rdtsc();          // 读取时间戳计数器
prefetch(kernel_address); // 预取指令(不会因访问内核地址而崩溃)
end = rdtsc();            // 再次读取时间戳计数器
time = end - start;       // 计算访问耗时

通过测量大量地址的访问时间,可以区分出:

  • 未映射的页:访问时间最长。
  • 已映射但未缓存的页:访问时间中等。
  • 已映射且缓存在TLB中的页:访问时间最短。

然而,测量行为本身会将目标地址加载到TLB中,污染状态。为了解决这个问题,我们使用驱逐-重载攻击

  1. 测量目标地址(如果是首次,可能未缓存,速度慢)。
  2. 精心构造一组地址,利用已知的索引函数,填满目标地址所在的TLB组,将其驱逐出去。
  3. 回到初始状态,可以再次进行测量。

利用这个基础能力,我们可以泄露内核内存区域(如直接物理映射、vmalloc区域)的基址,但此时粒度是2MB的大页。

将泄漏粒度从2MB细化到4KB

上一节我们获得了2MB对齐的内核区域信息。本节中我们来看看如何将泄漏精度提升到4KB页级别。

我们需要更精细的粒度来定位具体的内核对象。关键点在于利用内核的内存布局和防御机制:

  • vmalloc区域:本身就以4KB页进行映射,如果目标对象分配于此,则已满足条件。
  • 直接物理映射区域:通常使用2MB大页映射。我们需要将其“拆分”为4KB页。

以下是利用防御机制副作用实现拆分的方法:

  1. CONFIG_VMAP_STACK:该防御机制将内核栈分配在vmalloc区域而非直接物理映射区域,自然使用4KB页。
  2. SLAB_VIRTUAL:该防御机制虚拟化整个内核堆,使其位于4KB映射上。
  3. 严格的页权限执行:这是最有趣的一个。内核模块的代码页不应同时可写。当模块加载到直接物理映射区域时,内核需要将包含该模块的2MB大页拆分为4KB小页,以设置不同的权限。我们作为非特权用户,可以触发内核加载模块,从而间接地拆分大页。

接下来,我们需要让内核访问我们感兴趣的目标页,将其加载到TLB中,以便我们测量。我们通过系统调用来实现:

以下是触发内核访问特定对象页面的系统调用示例:

  • 内核栈:调用任意系统调用。
  • msg_msg 对象:使用 msgrcv 系统调用。
  • 管道缓冲区:对管道文件描述符进行读写操作。
  • 页表:使用 mprotect 系统调用。

然而,一个系统调用会访问大量内核页,产生大量“噪声”。我们需要从中识别出目标页。

从大量噪声中识别目标页

上一节提到系统调用会访问许多页。本节中我们来看看如何通过集合运算从噪声中提取出目标页的信号。

我们以 msg_msg 对象为例。假设我们想泄露存储 msg_msg 0 的页(P_target)。

  1. 调用 msgrcv(0),它访问了页面集合 S1 = {P_ipc_ns, P_queue0, P_target}
  2. 调用 msgrcv(1),假设 msg_msg 1msg_msg 0 在同一页,它访问了 S2 = {P_ipc_ns, P_queue1, P_target}
  3. 调用 msgrcv(32),假设 msg_msg 32 在另一个不同的页 P_other 上,它访问了 S3 = {P_ipc_ns, P_queue32, P_other}

通过集合运算,我们可以提取出 P_target
P_target = (S1 ∩ S2) \ S3
即,前两次调用都访问了的页面,且第三次调用没有访问的页面,很可能就是我们的目标页。

在实际攻击中,一个系统调用可能访问数百个页面,但通过精心选择多个调用并进行集合交集与差集运算,可以可靠地筛选出目标4KB页的地址。

堆风水:控制目标页的内容

上一节我们能够定位到目标对象所在的4KB页。本节中我们来看看如何进一步控制该页的内容,使其充满攻击者可控的对象。

我们不知道目标页上各个对象的具体排列顺序。但我们可以通过堆风水技术,操纵内核的SLAB分配器,让目标页只包含我们想要的对象类型(例如,全是 msg_msg 对象)。

这利用了SLAB分配器在分配相同大小对象时的行为模式。通过持续地分配和释放特定对象,我们可以提高目标页被同类型对象填满的概率。结合另一个侧信道(如缓存侧信道)来探测该页的“对象密度”,我们可以确认堆风水是否成功。

一旦目标页被我们可控的对象占据,我们就知道了该页上每个对象相对于页面基址的固定偏移。这为后续的利用提供了稳定的基础。

构建任意物理内存读写原语

上一节我们解决了“写到哪里”的问题。本节中我们来看看如何利用一个初始的有限写能力,构建强大的“任意写”原语。

假设我们通过一个漏洞(例如不安全的链表unlink操作)获得了一个受限的写原语:它能将两个值AB分别写入地址BA(即 *B = A; *A = B)。这被称为一个“交换写”原语。

我们的目标是将此转换为对物理内存的任意读写。我们选择管道缓冲区对象作为跳板。管道缓冲区结构体包含一个指向实际数据页的 page 指针。

以下是利用步骤:

  1. 信息泄露:使用前述方法,定位到一组连续的管道缓冲区元数据所在的SLAB页(P_pipe_meta),并确保该页内容已知(例如,包含 pipe_buffer 0, 1, 2...)。
  2. 利用初始原语:使用unlink原语,修改pipe_buffer 0page指针,使其不再指向真实的数据页,而是指向它自身的元数据页P_pipe_meta。这样,pipe_buffer 0page成员现在指向了包含所有管道缓冲区元数据的页面。
  3. 构建任意读/写
    • :向pipe_buffer 0写入数据。由于它的page指针指向P_pipe_meta,我们写入的数据会覆盖到P_pipe_meta页上的其他管道缓冲区元数据,例如pipe_buffer 1page指针。我们可以将其覆盖为我们想要读写的目标物理页地址
    • 读/写:现在,对pipe_buffer 1进行读写操作,实际上就是对目标物理页进行读写。
  4. 迭代:重复步骤3,通过pipe_buffer 0修改pipe_buffer 1page指针,可以移动读写指针到任意物理页。

通过这种方式,我们将一个受限的“交换写”原语,升级为了一个对物理内存的任意读写原语

缓解措施

本课程展示的攻击结合了硬件侧信道和软件漏洞。有效的缓解需要软硬件协同:

  • 软件缓解内核页表隔离(KPTI)。它完全分离用户空间和内核空间的页表。当进程运行在用户模式时,其页表中没有内核映射,从而从根本上阻止了用户程序通过预取指令探测内核地址。虽然会带来性能开销,但能有效防御此类攻击。
  • 硬件缓解:如Intel的线性地址空间分离(LASS)。它在地址翻译的早期阶段(在TLB查找之前),就根据虚拟地址的最高位(通常用于区分用户/内核空间)进行隔离检查,阻止非法的跨空间访问,从而消除TLB侧信道。

总结

在本课程中,我们一起学习了:

  1. 如何利用TLB计时侧信道区分内核地址的映射与缓存状态。
  2. 如何利用内核防御机制的副作用(如模块加载)将2MB大页拆分为4KB小页,提升泄漏精度。
  3. 如何通过系统调用触发内核访问目标对象,并运用集合运算从大量噪声页面中精确定位目标4KB页。
  4. 如何使用堆风水技术控制目标页的内容,为利用做准备。
  5. 如何将一个受限的写原语(如不安全的unlink),通过管道缓冲区对象,升级为强大的任意物理内存读写原语
  6. 了解了KPTI硬件隔离等可能的缓解措施。

这项研究表明,安全机制可能产生意想不到的副作用,而内存分配器的实现细节也可能被攻击者利用。将侧信道攻击与传统漏洞利用相结合,可以显著减少利用过程中的不确定性和猜测,实现更稳定、更隐蔽的内核攻击。

深入Windows HTTP服务:揭示隐藏的预认证漏洞 [CD-1s2uBqmQ] 🔍

在本节课中,我们将学习Windows HTTP服务框架的基本原理,并深入探讨其中存在的几种逻辑型拒绝服务漏洞和远程代码执行漏洞的发现过程与利用技巧。课程内容由浅入深,旨在帮助初学者理解这些复杂的安全问题。

背景介绍 🎯

我们专注于研究Windows HTTP服务,主要原因是几乎所有这类服务都可以在无需认证的情况下被访问。它们不需要用户交互和额外配置。最重要的是,许多默认服务都构建在HTTP API之上。这意味着如果存在任何漏洞,都可能导致严重问题。

让我简要介绍一下HTTP服务。基于HTTP API的服务使用诸如HttpCreateServerSession函数和HttpAddUrl函数来注册各种HTTP服务信息。在这些HTTP服务注册后,我们可以使用HttpQueryServiceConfiguration函数来获取关于它们的各种信息。

我们可以轻松地使用netsh命令来获取关于HTTP服务的信息。这有助于我们快速确定研究目标。

HTTP服务框架 🏗️

上一节我们介绍了研究背景,本节中我们来看看HTTP服务的整体框架。

基于HTTP API的Web应用程序通过HTTP API提供的接口与内核组件http.sys进行交互。这些接口使用具有特定IO控制代码的设备IO控制功能代码。最终,http.sys处理诸如接收和发送HTTP协议数据等任务。

以下是HTTP服务的简单框架。所有基于HTTP API的Windows HTTP服务都在此框架下工作。这是最简单、最常见的HTTP服务处理流程。

值得一提的是,几乎所有HTTP API服务都不需要预认证,只有极少数服务需要认证。客户端在收到HTTP头后,使用HTTP头中的NTLM或其他认证数据。但即使在这些情况下,接收阶段本身也不需要认证。

HTTP服务涉及两个重要的HTTP API函数。第一个是HttpReceiveHttpRequest函数,它负责接收HTTP头数据。服务调用HttpReceiveRequestEntityBody函数来接收HTTP实体数据,例如在接收POST数据的情况下。

总而言之,以下是通用的HTTP服务处理流程。

逻辑型拒绝服务漏洞 💥

现在我们已经了解了HTTP服务框架,我将分享一些由于不正确使用HTTP API而导致的逻辑型拒绝服务漏洞。

对于拒绝服务漏洞,由内存损坏引起的崩溃并不是唯一需要关注的问题。对于一个HTTP服务,如果服务器停止处理正常的客户端请求,这也是一种高影响的拒绝服务形式。

首先,我关注HTTP服务的接收阶段。不同的服务使用不同的接收方法,我将其分为三种类型:单线程接收方法和两种异步接收方法。

以下是每种方法的介绍:

单线程接收方法
它的主要特点是使用单个线程。我将以CVE-2024-43512中的AvoidableFunction为例进行介绍。HttpReceiveHttpRequest被设定为接收固定长度0x1360字节的HTTP头。当攻击者发送一个长度超过0x1360字节的HTTP头时,函数返回0xEA,这意味着接收缓冲区太小。通常,服务应该更新缓冲区大小并再次调用接收函数。但这个服务没有更新接收缓冲区大小,它保持在0x1360。结果,服务持续循环尝试接收数据,但永远无法从其他客户端接收数据。漏洞触发后,正常客户端只会收到超时错误。

异步接收方法(类型一)
在这种方法中,接收仍然由服务内的线程完成,但它不会在HttpReceiveHttpRequest函数内部等待。接下来,我将介绍CVE-2025-27471。UPnP服务是这类异步HTTP服务的典型例子。由于HttpReceiveHttpRequest函数是通过异步方式处理的,这导致了时间差问题。当攻击者同时发送多个恶意请求时,HttpReceiveHttpRequest函数不会像往常一样返回0或0x3E5,而是提前返回一个错误。这意味着接收到的字节数在初始化为0后没有被更新。如果返回的错误是0xEA,接收长度被设置为0而不是正确的值。我们可以通过设置条件断点来打印HttpReceiveHttpRequest函数的返回值来观察这个逻辑问题。当问题被触发时,即使攻击者断开连接,该函数也会永远返回错误。正如你所见,正常的UPnP客户端请求会收到正确的HTTP响应,但一旦漏洞被触发,客户端就无法再与服务器通信。

异步接收方法(类型二):使用注册回调
这是在Windows服务中处理HTTP请求最常见的方式。使用这种方法,多个线程可以同时处理来自多个客户端的请求。这是一个常见的回调处理模式。我列出了一些常见的回调函数。重要的是要知道有些回调是可选的。这些代码是根据服务的需求注册的。

在前两种使用单处理线程的接收方法中,如果接收函数停止被调用来获取新请求,就会导致拒绝服务问题。对于多线程回调方法,在一个函数处理完成后,它在线程池中创建一个新线程并再次调用接收函数。

但这里我想提到另一个需要考虑的拒绝服务技巧。由于线程池中的线程数量是固定的,如果每个线程在处理完成后没有调用StartThreadpoolIo函数来在线程池中创建一个新的接收线程,而是直接返回,那么该线程就会结束。当线程池中没有接收线程剩余时,HTTP服务将停止处理正常的客户端请求。

接下来,我将介绍FunctionResourceService中的一个漏洞。在这个服务中,IoResultHttpReceiveHttpRequest函数的返回值。当它为0时,意味着HTTP请求接收成功。服务正常处理请求,并最终调用IssueReceiveRequest函数。在这个函数中,StartThreadpoolIo函数被调用来在线程池中创建一个新线程,然后该线程调用接收函数等待新请求。然而,当IoResult不为零,意味着接收数据出错时,该函数立即返回而不创建新线程。这意味着,通过重复发送损坏的数据包导致IoResult错误,线程池中的所有线程都会退出。正如你所见,在漏洞触发前,正常请求会收到HTTP响应包,但一旦漏洞触发且所有接收线程退出,所有正常请求都会超时。

我去年报告了这个漏洞。MSRC认为,尽管它可能导致拒绝服务,但该服务被认为只在受信任网络中启用。因此,他们将其评为低严重性。

在接收阶段,我介绍了使用这些技巧的三个案例。我在Windows HTTP服务中发现了许多类似的问题。从研究这些漏洞中,我认为对于HTTP API服务,处理函数绝不应停止接收。换句话说,在任何请求之后,无论是有效的还是无效的,服务都必须将RequestId设置为0来调用HttpReceiveHttpRequest函数以等待新的客户端请求。仔细检查函数的返回值,并正确更新和验证接收函数的参数尤为重要。

响应阶段与连接管理 🔗

上一节我们探讨了接收阶段的漏洞,本节我们聚焦于响应阶段。

这里涉及两个函数。第一个是HttpSendHttpResponse函数,它发送HTTP响应包。第二个是HttpCancelHttpRequest函数,它强制断开与客户端的连接,导致客户端收到错误。客户端和服务器之间的连接实际上是在内核驱动中建立的。它通过AllocateConnectionForLookaside函数创建一个连接,并初始化一些所需的结构。类似地,当服务器主动断开连接时,它调用FreeConnectionForLookaside函数来关闭连接,释放相关结构并减少连接的引用计数。

当我的分析进行到这一点时,我想知道如果服务器不主动关闭连接会发生什么。换句话说,如果它从不调用HttpSendHttpResponse函数或HttpCancelHttpRequest函数来关闭连接会怎样。

我在一些服务中发现了这种情况。在接收和处理数据后,它们不调用HttpSendHttpResponse函数或HttpCancelHttpRequest函数,而是立即开始接收新数据。当我调试内核时,我看到http.sys没有关闭连接或减少连接的引用计数。这可能导致内核中的非分页池耗尽。

我以BranchCache服务为例。相关函数在MSDN上有文档,其中定义了不同类型POST数据的结构。

在POST数据结构中,我们可以指定服务应处理哪种数据。当我们发送特定数据时,服务使用throw辅助函数抛出异常。然后,服务在注册的回调中调用HttpReceiveHttpRequest函数来接收新数据,但它不调用HttpSendHttpResponse函数或HttpCancelHttpRequest函数来关闭连接。这导致http.sys中的连接未被释放。

以下是一个简单的演示。首先,使用netsh,我们可以看到BranchCache服务正在运行,以及它的URL和服务器的IP地址。接下来,我们从认证客户端运行PoC。你可以观察到非分页池的增长,最终导致系统蓝屏死机。

这些类型的漏洞导致非分页池耗尽,进而导致系统挂起或蓝屏死机。我认为服务在处理后必须始终响应,无论是成功还是失败,通过调用响应函数或使用注册的断开连接回调主动关闭连接。

IIS框架与相关漏洞 🌐

最后,我们来谈谈IIS。IIS是一个框架,它本身也是一个构建在HTTP API之上的服务。IIS为一些Web服务提供了一个基本框架,帮助它们处理接收和响应请求。Web服务只需要通过ISAPI扩展处理数据。值得一提的是,使用C#或ASP.NET的常见Web服务器在核心上也由Windows内置的ISAPI扩展支持。

通过ISAPI和CGI限制,我们可以找到不同服务使用的ISAPI扩展。

对于运行在IIS上的服务,当客户端发送HTTP请求时,IIS使用一个命令为相应服务启动w3wp进程。一旦服务运行,我们也可以通过netstat看到它的进程。

在这个进程中,一个非常重要的数据结构是ISAPI_CONTEXT。对于IIS上的每个服务,当w3wp进程被创建时,也会创建一个ISAPI_CONTEXT结构。随着IIS服务的访问,ISAPI_CONTEXT结构被释放。对于这个结构,每次有特定服务的请求到达时,IIS检查该结构的引用计数。IIS设置了0x1366的引用限制。如果引用计数超过0x1366,IIS返回一个503服务不可用错误。

通常,IIS可以处理数据接收,但ISAPI扩展必须决定何时发送HTTP响应。为了支持这一点,IIS提供了ServerSupportFunction,这是一个具有不同分支以满足各种需求的调度函数。为了确保ISAPI_CONTEXT的引用计数保持平衡,ServerSupportFunction中的一些分支会减少ISAPI_CONTEXT的引用计数。

因为ServerSupportFunction管理着ISAPI_CONTEXT的引用计数,并且这个函数被不同的ISAPI扩展服务使用,所以ISAPI扩展在使用时必须非常小心。错误地使用ServerSupportFunction会导致引用计数问题,例如过早释放,从而导致释放后使用或拒绝服务。

接下来,我将分享CVE-2024-38067。OCSP是一个在IIS框架下运行的服务。OCSP ISAPI是它的ISAPI扩展,它处理来自客户端的POST数据并将结果响应回客户端。最终,OCSP在SendResponseToClient函数内部调用ServerSupportFunction来发送HTTP响应。

ServerSupportFunction的分支中,服务器首先调用Flush函数。最后,在PostCompletion函数中,ISAPI_CONTEXT的引用计数被减少。然而,如果攻击者的客户端在发送POST数据后但在收到服务器响应之前提前断开连接,Flush函数会返回一个错误。结果,PostCompletion函数没有被调用,ISAPI_CONTEXT的引用计数没有减少。当引用计数达到0x1366时,OCSP服务将停止处理任何请求。在拒绝服务被触发前,正常请求会收到响应。触发后,客户端将收到503服务不可用错误。

这些类型的漏洞也会导致永久性拒绝服务。更严重的是,由引用计数问题引起的释放后使用很常见。如果ISAPI扩展不小心使用ServerSupportFunction,类似的问题可能导致远程代码执行。在开发ISAPI扩展时,在使用ISAPI支持接口时,我们必须密切关注结构的引用计数。

远程代码执行漏洞案例 ⚔️

我已经介绍了HTTP服务接收和响应阶段的逻辑型拒绝服务问题。接下来,我们将介绍HTTP服务中的远程代码执行问题。

首先,我将介绍KDC代理服务的HTTP服务。它提供了一种机制,允许客户端使用代理服务器更改密码并从KDC服务器安全地获取Kerberos服务器票据。客户端通过HTTPS与KPS服务器建立连接。然后,服务器解析客户端提供的域的IP地址。随后,KPS与KDC服务器指示的IP建立套接字连接,充当客户端和KDC服务器之间转发消息的通道。

以下是三列内容。第一列列出了服务器中使用的HTTP API。第二列显示了服务器在HTTP API注册的事件发生后涉及的回调函数。第三列显示了触发这些回调的事件。正如你所见,这是一个基于异步回调的HTTP架构。

当服务器调用HttpReceiveHttpRequest时,如果客户端发起连接请求,服务器进程会触发KPSHttpReceiveRequestIoCompletion回调函数来处理新的连接请求。如果服务器配置了客户端证书,它会等待客户端发送带有证书的请求。然后,服务器调用HttpReceiveRequestEntityBody来等待客户端的消息。如果客户端发送消息,它会激活KPSReceiveRequestEntityBodyIoCompletion函数,该函数继续处理客户端的消息。由于服务没有注册HttpWaitForDisconnect,当客户端断开HTTP连接时,服务器不会响应,导致新的问题,尽管这不是我们的主要关注点。服务器本身调用HttpCancelHttpRequest,随后在新线程中触发KPSHttpCancelRequestIoCompletion回调函数。服务器可以使用HttpSendResponse向客户端发送消息,并触发未完成的回调函数。

连接建立后,服务器调用DsGetDcName函数,该函数查询DNS服务器以获取与域对应的IP。假设客户端提供域test.yours.zz,它将查询两个SRV记录,假设服务器返回abc.test.your.zz。然后它使用LDAP协议评估此地址以获取Kerberos服务器地址,例如abcd.test.your.zz。在后续过程中获取此地址后,服务器调用Winsock接口socketconnect连接到我们模拟的Kerberos服务器。

此时,KPS服务器充当客户端。当它从伪造的Kerberos服务器收到消息时,会触发3个回调函数来处理接收到的消息。

接下来,让我们讨论案例CVE-2024-43639。在KPSSoReceiveDataIoCompletion回调过程中,它通过几个函数解码消息。由于套接字不限制接收消息的长度,消息长度可以是任意长度。当调用ASN1InCheck函数时,如右图所示,a2是当前消息长度,第10行,如果a2大于word_18的值,则将其赋值给r8d。在下一行,dword_18v9相加,和赋值给return1,然后用作分配内存的大小。如果消息长度是,例如,0xFFFFFFFF,而dword_18是5,那么加法会溢出到0,导致分配非常小的内存。随后在向这个小内存写入数据时会导致溢出。在适当的条件和布局下,这可能导致远程代码执行问题。

以下是崩溃堆栈跟踪。我们可以看到RCX指向一个不可读的地址。

讨论完KDC代理服务器后,让我们转到另一个案例:远程桌面协议服务及其网关服务。远程桌面服务是Windows中的内置组件,使用户能够通过网络远程控制Windows系统。此功能通过使用端口3389的RDP协议实现。然而,Windows远程桌面服务也使用端口3387,它实现了一个支持WebSocket的HTTP服务。它允许客户端通过HTTP完成远程桌面协议请求。

现在,让我们探索远程桌面网关服务。如图所示,客户端通过HTTPS端口443或DTLS端口3391与远程桌面网关服务连接。经过一系列协商和认证后,网关服务将客户端的远程桌面协议消息转发到相应的远程桌面服务器。

现在,让我们检查远程桌面网关服务的HTTP架构。远程桌面服务器及其网关都采用了类似的基于异步回调的HTTP架构。正如你所见,它与KPS架构相似,不同之处在于它有一个用于处理连接断开的注册回调函数,以及用于处理WebSocket和非WebSocket请求的回调函数。

现在,让我们使用此流程图完成一个正常的连接过程。首先,客户端向服务器发起一个WebSocket请求,连接ID为ConID1。这会触发服务器的HttpReceiveRequestCompletion回调函数。在处理过程中,它调用ProcessOutChannelOrWebSoRequest函数,该函数为此连接分配新的连接结构并将其存储在哈希表中。随后,它调用HttpSendHttpResponse向客户端发送消息。完成后,触发服务器回调函数HttpSendResponseCompletion,该函数分配HttpServerConnection结构并将其绑定到Connection1。在后续处理中,它调用ReceiveData,其中参数3是指向HttpServerConnection结构偏移量的指针。在ReceiveData函数内部,它使用连接IDConID1从哈希表中检索Connection1,并将参数3分配给结构中成员的缓冲区字段。在后续调用中,通过WebSocketReceiveRawData并调用HttpReceiveRequestEntityBody来注册新的回调。当服务器从客户端收到消息时,会触发此回调。在处理过程中,它调用WebSocketReceiveLoop,执行一个关键步骤:将接收到的消息复制到Connection1成员的缓冲区字段所指向的地址,该地址是HttpServerConnection结构的偏移量。其他操作随之进行。

那么这种架构可能有什么问题呢?客户端可以使用相同的连接ID连接到服务器吗?事实上,这是不允许的,因为ProcessOutChannelOrWebSoRequest会检查ID是否已存在于哈希表中。但是,我们能否在获取操作之前释放连接,然后让客户端使用连接ID1进行连接?这似乎是可能的。让我们推断一下会发生什么。

首先,客户端1使用ConID1连接到服务器,服务器创建Connection1结构。发送后,它创建HttpServerConnection1。然后进入ReceiveData。在此时刻,我们断开客户端1。由于断开连接回调已注册,服务器自动触发HandleDisconnected,该函数取消引用HttpServerConnection结构并从哈希表中移除Connection1。此时HttpServerConnection可能不会被释放,因为对它的引用仍然存在,直到HandleSendResponseCompletion完成。然后我们使用相同的连接ID连接客户端2,服务器创建Connection2并将其放入哈希表。现在,返回到ReceiveData线程,它继续运行,使用连接ID1从哈希表中检索Connection2,并将参数3分配给Connection2结构的缓冲区字段。然后它调用HttpReceiveRequestEntityBody来注册回调函数。HandleSendResponseCompletion函数完成,HttpServerConnection1的引用计数变为0,因此没有引用,参数3将成为一个悬空指针。后来,当客户端2向服务器发送消息时,它会激活HandleWebSocketReceiveRawDataCompletion回调函数。在函数内部,它使用CallID1从哈希表中检索Connection2,并向悬空指针写入数据。因此,我们可以溢出到一个悬空内存。

以下是崩溃现场的堆栈。正如所示,它在内存复制函数中崩溃,RCX指向一个不存在的地址。

总结与展望 📝

本节课中我们一起学习了Windows HTTP服务框架及其存在的多种

E-Trojans:小米电动滑板车上的勒索软件、追踪、DoS与数据泄露 🛴🔓

在本课程中,我们将学习一项关于小米电动滑板车安全性的研究。我们将了解攻击者如何利用滑板车内部的漏洞,通过无线方式发动多种攻击,包括物理破坏、勒索软件、用户追踪和数据泄露。课程内容基于对小米M365和米家电动滑板车3(ES3)等型号的深入分析。

1. 引言与背景

大家好,我是Marco,目前在瑞典KTH大学从事博士后研究。这项研究是我在法国Eurecom攻读博士学位期间,在共同演讲者Ben Antonioli教授的指导下完成的。我的研究领域是安全与隐私,主要分析蓝牙、Wi-Fi等专有和标准传输协议,以及移动安全。

接下来由Daniela Antonioli发言。感谢大家来听我们的演讲。我是Daniela Antonioli,是位于法国南部的大学和研究中心Eurecom的助理教授。我们的研究涵盖安全和隐私领域,包括蓝牙、电动滑板车、FIDO认证和网络追踪等主题。在我们的研究网站上可以找到更多信息。

在开始演讲前,我想感谢E-Trojans研究项目的三位合著者:Ricardo Castao、Ionor Luzuk和Marco Conti,他们都是意大利帕多瓦大学的研究人员。

以下是本次演讲的大纲。我将首先介绍电动滑板车,并概述E-Trojans的漏洞和攻击。然后Marco将接手,详细介绍其中两种攻击:一种是过压电池破坏攻击,另一种是欠压电池勒索软件攻击。我们的项目中还有另外三种攻击,鼓励大家阅读关于E-Trojans的研究论文以了解更多细节。接着,Marco将介绍我们用于发现这些攻击和漏洞的逆向工程技术、我们开发并部分开源的工具包(包含测试攻击的方法),以及我们在小米滑板车上进行的实验。最后,Marco将总结演讲,介绍我们向小米建议的防护措施,以及过去两年中我们与小米进行的负责任披露过程。

2. 电动滑板车简介

首先进行简要介绍,以设定背景。我们讨论的是电动滑板车。你在左边看到的实际上是一个相当复杂的嵌入式系统,它就像一个带轮子的智能手机,拥有无线电接口,可以与智能手机通信。智能手机通常运行一个配套应用程序来控制滑板车。

这两个设备使用专有协议进行通信,这些协议可以通过多种无线技术传输。大多数时候,这种技术是蓝牙低功耗,因为它成本低且普及。但需要记住的重要一点是,在BLE上运行的协议是自定义的、特定于供应商的,可能包含一些安全措施等。

然后,移动应用程序与滑板车的后端(一种云服务)通信。这个通信链路使用标准的互联网协议,如TLS和TCP/IP。

在本次演讲中,我们将重点关注这个红色方框:即滑板车本身、滑板车与移动应用之间的无线链路,以及移动应用本身。这是我们的攻击面。

对于E-Trojans,我们决定重点关注小米滑板车,因为小米是市场领导者。你可能知道M365和米家电动滑板车3,这是两款非常流行的电动滑板车,既用于个人用途,也用于像Bird这样的租赁服务。这款滑板车的配套应用叫做“米家”应用,适用于安卓和iOS,提供多种功能。你可以使用小米后端创建账户,将应用与滑板车配对,然后可以通过应用设置密码来锁定或解锁滑板车,可以从滑板车获取一些传感器读数(如电池电量、电压等),还可以发送固件更新。请记住固件更新这个功能,因为我们将要利用它:恶意固件更新。

研究电动滑板车非常重要,因为如今它们可以通过多种方式被攻击,甚至可以通过无线方式在近距离内远程攻击。攻击滑板车不仅会带来典型的安全和隐私影响(例如,破坏加密协议或泄露敏感数据),而且如果攻击者控制了滑板车,还可能引发安全问题,例如物理损坏,甚至可能导致滑板车起火。因此,保护这些滑板车免受远程和近距离攻击者的侵害至关重要。

3. 现有研究与E-Trojans的定位

当我们在2023年开始这项研究时,我们查看了现有技术,发现了Zimperium在2019年的这项工作。在那项工作中,Zimperium演示了一种攻击:他们在攻击者的笔记本电脑上运行一个自定义应用程序,该应用程序能够利用他们逆向工程得到的小米专有协议来制作无线BLE数据包。通过这个应用程序,研究人员能够演示对图中所示滑板车的远程锁定命令。

从这项初步工作出发,我们对小米滑板车进行了广泛的安全评估,并在2023年的ACM WiSec(无线安全和隐私领域的顶级会议)上发表了名为《E-Spoofer》的论文。在这项研究中,我们研究了在冒充受信任的小米“米家”应用时,所有可能危害滑板车的方法。我们演示了基于近距离的攻击:我们使用一个设备,能够恶意地与滑板车配对,然后不仅可以发送锁定命令,还可以发送任何授权命令,就像我们拥有真正的“米家”应用一样。此外,我们将攻击者模型扩展到了所谓的“远程攻击者”,这与之前Zimperium演示的不同。这次,我们在受害者的手机上安装一个恶意应用程序,这个恶意应用程序与“米家”应用共存。然后,只要检测到滑板车在范围内,它就可以发送恶意载荷。这是一种远程攻击面,因为我们可以通过应用程序远程攻击滑板车,并且可以轻松传播恶意应用程序,例如改装应用。当你拥有电动滑板车时,你可以从第三方市场安装这些改装应用来改变滑板车的最大速度。因此,攻击者很容易重新打包这些非常流行且用户不会仔细检查的改装应用,从而危害滑板车。

这就是《E-Spoofer》。随后的论文是《E-Trojans》,这也是本次演讲的重点。在这项研究中,我们从《E-Spoofer》的发现出发,评估了作为远程或近距离攻击者,通过发送这些恶意的专有命令来影响滑板车内部的可能性。因此,重点是滑板车的内部结构。这篇论文的预印本已在arXiv上发布,目前正在提交给学术会议进行评审。

4. 滑板车内部架构

让我们快速了解一下滑板车的内部结构。滑板车内部有几个共存的片上系统。一个是驱动电机系统,在图中用黄色标出。这是一个管理电机的芯片。这个芯片连接到BTS和BMS子系统。BTS是蓝牙子系统,这是无线电系统,非常重要,它是通往其他子系统的网关,通过无线信号提供访问。例如,当你发送固件更新时,你想更新DRV的固件,那么固件会通过BLE从“米家”应用发送到BTS,然后BTS使用嵌入式总线(如UART)在内部分发固件。

第三个重要的子系统是电池管理系统。这是管理电池、管理滑板车充电的系统。如果你深入了解,它通常包括两个模块:一个是电池控制器,另一个是电池监视器,在图中分别标为BCTL和BMon。

需要理解的重要一点是,电池控制器固件可以与DRV固件和BTS固件一起通过无线方式更新。而电池监视器就像一个模拟前端,可以通过电池控制器进行部分编程。它们之间通过嵌入式总线(I2C总线)连接,你可以发送信号来写入和读取寄存器,以编程电池监视器。我们稍后会看到,这可以作为一个攻击向量来危害电池管理系统。此外,还有一个电池充电器,你可以将其插入滑板车进行充电。

这只是一张内部结构的图片。如果你打开一个电动滑板车,你会看到DRV、BMS、电池单元、ST-Link调试器、黑色电缆以及BTS片上系统。BTS片上系统通常位于前灯附近,而其他芯片则位于滑板车底座上,电池也在这里。

这是一张电池管理系统的图片,是双面的:一面是电池控制器,另一面是电池监视器。所以,这是同一个子系统上的两个片上系统。

在我们的E-Trojans评估中,我们重点关注两款非常流行的滑板车。请记住,我们在2023年开始这项分析,当时最著名、最流行的滑板车是米家电动滑板车3,所以我们将其作为目标。这是2021年推出的第二代滑板车。同时,我们也决定瞄准最流行的第一代小米滑板车,即M365。通过瞄准这两款滑板车,我们也间接瞄准了介于它们之间的型号,如Pro、Pro 2、1S和Essential。这些是2018年至2020年推出的滑板车,因此也在研究范围内。

这只是我们目标芯片的列表。这些滑板车共享这些芯片,芯片可能运行不同的固件版本,但问题仍然存在。BTS运行Nordic nRF51,这是一个非常流行的无线电通信芯片。DRV运行STM32芯片。蓝牙控制器是STM微控制器,采用STM8架构。电池监视器(模拟前端)是德州仪器的芯片,可以部分编程。

5. E-Trojans漏洞与攻击概述

现在,让我们看看E-Trojans的漏洞和攻击。我们从以下威胁模型开始:我们有一个拥有电动滑板车的受害者,他通过恶意应用程序与滑板车配对。攻击者可以近距离使用BLE信号攻击滑板车(例如使用带有特殊BLE板的笔记本电脑),或者攻击者可以在受害者的智能手机上安装恶意应用程序,然后从受害者的智能手机攻击滑板车。这就是我们的威胁模型。

我们对这些滑板车进行了广泛的逆向工程,使用了静态和动态技术。Marco稍后会简要介绍这些技术。长话短说,我们发现了影响这些滑板车的四个关键漏洞。

第一个漏洞是蓝牙控制器固件未加密。因此,我们能够从“米家”应用以及蓝牙控制器的内存中提取固件,并进行逆向工程。

第二个问题是蓝牙控制器固件未签名。这非常糟糕,意味着你可以通过无线信号在电动滑板车上安装恶意固件。这正是我们所做的。所以我们的攻击技术是恶意固件更新,固件就像是一个载荷。利用这种攻击技术,我们可以发起不同的攻击。

第三个漏洞是连接内部片上系统的UART通信缺乏完整性、加密和身份验证。这也很糟糕,因为我们可以将恶意固件更新与以下事实结合起来:我们可以编程蓝牙控制器,使其表现得像DRV或BTS,因为我们可以欺骗内部系统。然后,我们可以发送多种内部消息,从BTS获取数据,阻止BTS知道出了问题,停止充电,或者做任何我们想做的事情。因此,V2和V3的结合非常强大。

第四个问题是拒绝服务,因为内部的UART通信没有针对拒绝服务进行保护。我们能够利用这个漏洞,通过固件更新对滑板车内部发起拒绝服务攻击。

以上就是将在攻击中被利用的四个漏洞。

6. E-Trojans攻击技术

这是利用这些漏洞的E-Trojans攻击技术。攻击者与无线电系统通信,无线电系统是进入滑板车内部的网关。攻击者的第一条消息利用了E-Spoofer。如果你还记得,通过E-Spoofer,我们能够利用一些技巧和发现的漏洞绕过身份验证。一旦我们绕过身份验证,我们就可以表现得像真正的“米家”应用一样。

然后,我们通过蓝牙低功耗发送蓝牙控制器固件更新消息。请记住,所有这些消息都不是标准的BLE消息,而是专有消息。因此,你必须先对协议进行逆向工程,才能发送这些消息。

一旦我们发送了这个固件更新消息,无线电系统就会接收固件(固件包含在我们发送的一组消息中),然后将其分发给蓝牙控制器模块。蓝牙控制器模块安装我们的恶意固件,然后回复一条消息,表示一切正常。接着,无线电系统回复攻击者,表示一切正常。这就是E-Trojans攻击技术:一个利用蓝牙控制器缺乏完整性保护的恶意固件(蓝牙控制器不检查签名),同时我们也利用了可以欺骗内部系统的事实,因为内部通信同样没有受到保护。

然后,我们使用这种攻击技术展示了五种新的攻击。

第一种是欠压电池勒索软件。Marco将详细讨论它。据我们所知,这是第一个针对电动滑板车的勒索软件,也是第一个使用欠压作为攻击技术的攻击。

我们展示了过压电池破坏攻击。这是第一个使用过压来攻击任何电动滑板车的攻击。

Marco将详细介绍这两种攻击。接下来,我将重点介绍最后三种攻击。如果你想了解更多细节,可以阅读论文。但基本上,通过第三种攻击,我们可以追踪用户和内部系统。我们展示了通过读取每个滑板车独有的值(如电池序列号、电机序列号)来创建滑板车指纹的可能性。这些都是非常强的指纹。我们创建指纹,然后使用BLE模块广播这个指纹。通过部署嗅探器网络,我们可以基于这个指纹追踪用户。这是首次在电动滑板车上演示这种追踪攻击。然后,我们还进行了拒绝服务攻击,利用我们的恶意固件破坏内部的UART通信。

有趣的是,我们还能够通过滑板车泄露密码,即“米家”应用的密码。这也很重要。当你拥有电动滑板车时,你可以设置密码来锁定和解锁它。但密码不仅存储在手机上,也以哈希形式存储在滑板车上。我们能够恢复这个哈希值,并以与泄露指纹相同的方式泄露它,然后我们可以暴力破解哈希值,从而恢复用户的密码或PIN码。

7. 过压电池破坏攻击详解

现在,Marco将接手,继续详细介绍攻击的技术细节。

谢谢Daniela让我来解释攻击中很酷的部分。我们将讨论两种攻击,从过压电池破坏开始。

首先,什么是过压?这是一张电池单元的图片,你的电池内部有多个这样的单元。现在我们讨论的是小米锂电池单元,其工作电压范围为4.2V(100%充电)到3.6V(滑板车停止行驶,电量为0%)。这是正常的操作范围。

电池过压发生在电压溢出时,即电池单元的电压超过4.2V,充电超过100%。如果充电器出现故障或损坏,就可能发生这种情况。这就是我们威胁模型中的假设。

过压是一种非常危险的物理状态,会带来严重后果。例如,导致永久性电池损坏、电池单元变得不平衡(即电压不同)、由于能量增加而过热,并可能导致火灾或爆炸等安全隐患。

电池监视器有一个过压阈值寄存器。如果电池单元的电压超过阈值,电池监视器会在系统状态寄存器中将过压故障位设置为1,并向电池控制器发送警报。电池控制器可以写入电池监视器的寄存器,这意味着我们可以通过电池控制器影响电池监视器,而我们可以通过恶意固件更新访问电池控制器。

例如,我们可以做几件事。我们向过压阈值寄存器写入0xFF,将阈值从4.2V设置为4.7V。这是电池监视器支持的最大值,因此我们称之为临界过压,我们超过了电池控制器可设置的最大限制。或者,例如,我们可以将系统状态寄存器中的过压故障位取消设置为0,这样从电池监视器的角度来看,就好像没有发生过压一样。

因此,过压电池破坏攻击始于恶意固件刷入。然后,电池控制器执行以下操作:我们将过压阈值设置为最大值4.7V,这允许我们执行危险的过压操作。然后,我们忽略来自电池监视器的所有过压警报。这意味着无论小米在电池控制器中设置了什么安全措施,我们都不执行并忽略它,因为我们控制了电池控制器。接着,我们取消设置电池监视器中的过压故障位。同时,我们将快速充电位设置为1。正常情况下,如果发生过压,快速充电功能可以阻止充电。如果电池控制器将其设置为1,它就会再次开始充电。现在,由于我们忽略了故障位并使其充电,我们可以超过临界过压阈值。我们也不希望负载均衡,因为负载均衡意味着我们平衡电池单元的电压。如果一个单元过压,我们会将电压分配到其他电压较低的单元,使它们相等。我们希望它们不平衡,我们希望过压。因此,我们更改电池均衡寄存器中的均衡位。最后,我们只是向蓝牙系统和最终用户报告没有发生过压。因此,攻击是隐蔽的。

8. 欠压电池勒索软件详解

现在,我们来看一个更复杂的攻击:欠压电池勒索软件。

什么是欠压?现在我们使用相同的电池单元和相同的操作范围。在这种情况下,电池欠压发生在电压下溢时,即电池单元的电压低于3.6V(标称最低值),充电低于0%。是的,这是可能的。

欠压也是一种安全风险,其后果包括永久性电池损坏、电池因损坏而无法再充电,甚至可能发生极性反转。当电池深度放电,电压非常低接近0V,并且有电流通过时,就可能发生这种现象,逆转电池的极性。这非常危险,可能导致火灾、短路和爆炸。

与之前类似,电池监视器中有一个欠压阈值。如果我们低于这个值,就会设置欠压故障位,并向电池控制器发出欠压警报。电池控制器也可以写入欠压寄存器。如果我们写入0x00,在这种情况下,我们将欠压阈值设置为可能的最低值1.58V,我们称之为临界欠压,甚至低于最大可设置值。我们也可以取消设置欠压故障位,就像之前一样。

当我们部署欠压电池勒索软件时,我们执行以下操作:我们在电池控制器中刷入我们的固件,然后将欠压阈值设置为最小值1.58V,这样我们就可以执行危险的欠压操作。我们忽略欠压警报,也不执行电池控制器为防止欠压而通常会做的任何事情。我们还取消设置欠压故障位。现在,我们设置快速放电位。放电是同一寄存器中不同的一种设置。这允许滑板车最小化能耗,因为当我们欠压时,意味着我们在消耗电力。如果我们关闭蓝牙系统和电机系统,就会减少消耗,电压可能会得到缓解。我们不希望这样,因此我们将快速放电位设置为1,以便继续放电电池,并达到临界欠压状态。出于与过压相同的原因,我们也不希望均衡。我们希望电压差异大。攻击同样是隐蔽的,因此我们不向蓝牙系统和用户报告任何欠压情况。

UBR是第一个电动滑板车勒索软件。它物理上针对电池,通过欠压物理损坏电池。这与典型的针对数据加密的勒索软件不同。我们在勒索软件中设置了一个触发条件,例如,当我们达到临界欠压时,它会向受害者揭示感染情况。我们通过更改BLE广播来实现这一点:我们向蓝牙系统发送一个小米命令,将设备的BLE广播更改为一个短链接,以下载我们的应用程序。该应用程序向用户解释他的不幸情况,并要求他支付赎金。否则,滑板车将继续消耗电力,电池将永久损坏,并且这种损坏会随着时间的推移而增加。因此,这是一个恢复或停止欠压的倒计时。我们还提供恢复服务。在我们的勒索软件中,我们非常“仁慈”。你可以刷入这个电池控制器恢复固件。这种恢复并不意味着你可以逆转物理损坏,损坏是物理性的,你无法做任何事情。你的电池健康度已经下降,但你可以通过提高电压来解决欠压问题。因为在正常的小米固件中,如果滑板车欠压,你可以为其充电。我们出于安全原因移除了这个功能,但我们为你提供了这个恢复固件,这样你至少可以在剩余的任何条件下使用滑板车。

这种攻击,UBR,也可以在不要求赎金的情况下使用。这只是对你电池的静默破坏,你只需使其欠压,最终电池就会报废。

9. 逆向工程、工具包与评估

现在,我将讨论工程细节、今天在GitHub上发布的工具包以及评估结果。

为了理解滑板车的内部架构和固件,我们进行了数月的逆向工程。我们使用了一套动态和静态

ECS-cape – 在 Amazon ECS 中劫持 IAM 权限 [UV-hS-DTeik] 🚨

在本节课中,我们将学习一个名为 ECS-cape 的漏洞。这个漏洞允许在同一个 EC2 实例上运行的一个容器,通过内部 AWS 协议,劫持另一个权限更高的容器的凭证。在某些情况下,这足以接管整个云环境。我们将深入探讨其技术背景、发现过程、工作原理、影响以及缓解措施。


技术背景 📚

在深入探讨漏洞细节之前,我们需要了解一些核心概念。上一节我们介绍了课程概述,本节中我们来看看理解 ECS-cape 所需的关键技术背景。

什么是 IAM?

IAM 代表 身份和访问管理。它是 AWS 中定义“谁可以访问什么”以及“他们可以做什么”的系统。它有两个主要组成部分:策略角色

  • 策略 是一个 JSON 文档,列出了允许和拒绝的操作。例如:
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "s3:*",
                "Resource": "*"
            }
        ]
    }
    
  • 角色 是一个附加了一个或多个策略的身份。角色可以被“担任”,这意味着你可以获得与该角色权限关联的临时凭证,并以该角色的身份行动。

什么是 Amazon ECS?

Amazon ECS 是 AWS 原生的容器编排服务。它本质上是 Kubernetes 的一个更简单的托管替代方案,在你的云环境中运行 Docker 容器,并与 IAM、日志记录和网络等 AWS 核心功能深度集成。

以下是贯穿本课程的三个核心概念:

  • 集群:一组由 Amazon ECS 管理的 EC2 实例。容器将在这些实例上运行。
  • 服务:确保指定数量的任务持续运行。它处理重启、扩缩容和部署等事务。
  • 任务:由任务定义指定的单个运行单元。它包含一个或多个容器(如你的应用、边车或日志收集器)。

在 ECS 中,每个任务被分配两个 IAM 角色:

  1. 任务角色:定义任务内容器可以在云环境中执行的操作。
  2. 任务执行角色:供 ECS 自身使用,任务本身无法访问。它授予 ECS 为任务拉取容器镜像和获取密钥的权限。

ECS 在 EC2 启动类型下的工作原理

本课程重点讨论 EC2 启动类型,因为这是漏洞实际生效的环境。

每个 EC2 实例都被分配一个唯一的 实例角色,该角色具有特定的 ECS 权限。在该实例上,运行着 Docker 守护进程(实际运行你的容器)和一个名为 ECS 代理 的组件。

ECS 代理充当 AWS 控制平面和实例本身之间的桥梁。它使用实例角色向 AWS 控制平面进行身份验证,并接收诸如“启动此任务”、“停止那个任务”等指令。

这个整体单元(EC2 实例 + ECS 代理)就是 AWS 所称的 容器实例


漏洞的发现过程 🔍

上一节我们介绍了 ECS 的基本工作原理,本节中我们来看看这个漏洞是如何被发现的。

故事始于一个需求:监控 ECS 任务。通过检查运行的容器,我发现 Docker 标签包含了大部分所需信息,但缺少 服务名称

在线搜索后,我发现了 ECS 代理向每个任务公开的一个特殊端点:http://169.254.170.2/v2/metadata。它返回了大量关于任务本身的信息,最重要的是,它包含了服务名称。

但问题来了:ECS 代理是如何获取这些信息的?我检查了实例角色的权限,发现它并没有列出运行中服务的权限。这引发了我的好奇心。

通过设置代理服务器检查 ECS 代理的通信,我注意到它使用 WebSocket 连接到 ECS 服务,并传递了一个特定的查询参数:sendCredentials=true。这让我怀疑:我能否冒充 ECS 代理?


漏洞技术原理深挖 ⚙️

上一节我们了解了漏洞的发现线索,本节中我们深入探讨其技术原理。

ECS 代理的正常工作流程

首先,ECS 代理是完全开源的,这对研究很有帮助。其实例角色拥有几个关键的 ECS 权限,在我们的漏洞中扮演重要角色:

  1. 注册容器实例:代理使用 RegisterContainerInstance API 将自己注册为控制平面中的一个新容器实例。
  2. 发现轮询端点:代理使用 DiscoverPollEndpoint API 获取一个特定的 URL(轮询端点)。
  3. 建立 ACS 连接:代理使用轮询端点 URL 和一系列标识符构建一个 WebSocket 请求,并通过 sentCredentials=true 参数进行身份验证。一旦连接建立,AWS 控制平面就开始通过这个 WebSocket 发送同一实例上所有任务的任务角色和任务执行角色的凭证

这个 WebSocket 使用一种名为 ACS 的内部 AWS 协议进行通信,该协议承载任务元数据、代理级别指令以及最重要的——IAM 凭证。

攻击者如何冒充 ECS 代理?

核心问题是:一个任务能否冒充 ECS 代理?

攻击流程如下:

  1. 获取实例凭证:每个 EC2 实例都有一个特殊的 HTTP 端点,称为 实例元数据服务。在 ECS 中,IMDS 默认启用,且对实例上运行的每个任务可访问。这意味着任何任务都可以获取实例角色的凭证,而 ECS 代理使用的正是这个角色。
    • 代码示例(在容器内执行):
      curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<instance-role-name>
      

  1. 发现轮询端点:使用获取到的实例凭证,调用 DiscoverPollEndpoint API,获得轮询端点 URL。

  2. 构建 ACS 请求:要构建有效的 ACS WebSocket 请求,需要一系列标识符(如集群 ARN、容器实例 ARN)。这些信息可以通过以下方式获取:

    • IMDS:提供实例级信息。
    • 任务元数据端点 (http://169.254.170.2/v2/metadata):提供任务级信息。
    • 容器自检 API:这是 ECS 代理向每个任务公开的另一个端点 (http://172.17.0.1:51678/v1/tasks),它提供了容器实例 ARN 等关键信息,补全了拼图的最后一块。

  1. 连接并劫持凭证:使用所有收集到的标识符和实例凭证,构建一个有效的 ACS WebSocket 请求并连接到 AWS 控制平面。控制平面验证调用者是否拥有 Poll 权限(实例角色拥有此权限),因此连接通过身份验证。随后,控制平面开始通过这个 WebSocket 发送同一实例上所有其他任务的凭证,误以为正在与真正的 ECS 代理通信。

关键点:攻击者获得的是 AWS 已代为担任角色的、立即可用的凭证。在 CloudTrail 日志中,这些操作看起来像是来自合法的 ECS 服务本身,而不是攻击者容器。


漏洞影响 💥

上一节我们弄清了攻击原理,本节中我们评估其实际影响。

1. 任务 IAM 角色劫持

假设一个 EC2 实例上运行着两个任务:一个低权限任务和一个高权限任务。如果低权限容器被攻击者攻陷,利用 ECS-cape,攻击者可以横向移动,劫持高权限任务的凭证,从而访问原本无法触及的资源(如 S3 存储桶)。

2. 滥用任务执行角色

任务执行角色本应仅供 ECS 自身使用。但通过 ECS-cape,攻击者可以劫持该角色的凭证,直接与 AWS Secrets Manager 等服务通信,获取本应注入给其他任务的敏感信息(如数据库密码)。

3. 多租户环境下的租户逃逸

在常见的多租户设置中,不同租户的任务可能运行在同一 ECS 集群的同一实例上。访问控制依赖于 IAM 和任务隔离。ECS-cape 允许租户 A 的攻击者劫持租户 B 的任务凭证,从而访问其数据和服-务,实现租户逃逸

4. 访问 ECS 内部信息

通过模拟 ACS 协议,攻击者还能获取大量关于集群本身、其他任务和实例的元数据,这些信息在漏洞利用前是无法直接获取的。

重要提示:此漏洞无需任何错误配置即可利用。IMDS 在默认 ECS 设置中启用,实例角色也默认拥有必要权限。


演示 🎬

上一节我们讨论了理论影响,本节中我们通过一个演示来直观感受。

我创建了一个包含三个任务的集群:

  1. ECS-cape 任务:任务角色权限为 Deny: *(无任何权限)。
  2. S3 控制任务:任务角色拥有 AmazonS3FullAccess 策略。
  3. 数据库任务:无任务角色,但有一个可访问 Secrets Manager 的任务执行角色。

演示 1:劫持 S3 权限

  • 从 ECS-cape 任务 shell 中,尝试删除一个 S3 存储桶,操作被拒绝。
  • 运行 ECS-cape 利用工具,工具成功劫持了 S3 控制任务的凭证。
  • 再次尝试删除 S3 存储桶,操作成功。

演示 2:劫持任务执行角色以获取密钥

  • 从 ECS-cape 任务 shell 中,尝试读取数据库任务使用的 Secrets Manager 密钥,操作被拒绝。
  • 运行 ECS-cape 利用工具,工具成功劫持了数据库任务执行角色的凭证。
  • 直接使用该凭证从 Secrets Manager 读取密钥,成功获取明文密码。

在 CloudTrail 日志中,这些操作看起来完全来自合法的 S3 控制任务和数据库任务,没有攻击者容器的踪迹。


缓解措施与最佳实践 🛡️

上一节我们看到了漏洞的强大威力,本节中我们学习如何防御。

1. 禁用对任务的 IMDS 访问

这是最重要的措施。如果任务无法访问 IMDS,就无法获取实例角色凭证,从而无法冒充 ECS 代理。

  • 注意:切勿在实例级别禁用 IMDS,因为 ECS 代理依赖它。应仅针对特定任务容器禁用。
  • 方法:可以通过配置 iptables 规则在容器网络命名空间内阻止对 IMDS 端点 (169.254.169.254) 的访问。这通常需要在任务定义或启动脚本中实现。

2. 严格管理任务角色权限

  • 切勿为任务角色授予 ecs:Pollecs:DiscoverPollEndpoint 权限。
  • 避免使用包含通配符 (*) 的 ECS 权限策略,因为它们可能隐含上述危险权限。
  • 遵循最小权限原则:只授予任务执行其功能所必需的最精确权限。

3. 谨慎配置任务执行角色

  • 不要过度授权任务执行角色。尽管它旨在供 ECS 使用,但其凭证可能通过此漏洞暴露。
  • 避免所有任务共享一个高权限的任务执行角色。根据任务需求进行分离和最小化授权。

4. 工作负载隔离

  • 分离高低权限工作负载:不要将低权限和高权限任务部署在同一 EC2 实例上。可以通过配置容量提供者或使用独立集群来实现。
  • 隔离多租户环境:为不同租户使用不同的集群,或至少在 EC2 实例级别进行隔离。


总结与回应 📝

在本节课中,我们一起学习了 ECS-cape 漏洞。我们了解到:

  1. 在 EC2 启动类型下,ECS 任务与 ECS 代理共享同一个安全边界。
  2. 一个任务可以利用 PollDiscoverPollEndpoint 权限(通过 IMDS 获得的实例角色拥有)来冒充 ECS 代理。
  3. 成功冒充后,攻击者可以劫持同一实例上所有其他任务的 IAM 角色凭证和任务执行角色凭证。
  4. 缓解措施的核心在于任务级别的强化:禁用非必要的 IMDS 访问,并严格遵循最小权限原则配置任务角色和任务执行角色。

我将此漏洞报告给 AWS。AWS 的回应是,这不被视为 AWS 的一个安全问题,因为代理运行在客户的安全边界内,容器本身不是安全边界。他们更新了文档以反映这种潜在风险,并考虑长期的防御性改进。

最重要的收获:在云安全中,绝不能盲目信任默认配置或服务边界的承诺。主动实施最小权限和深度防御策略至关重要。

从IP欺骗到隧道技术:红队用于初始访问与规避的新型网络技术 🕵️♂️

在本课程中,我们将学习红队用于网络渗透测试和规避检测的新型技术。课程将涵盖IP欺骗、利用隧道协议(如GRE和VXLAN)进行初始访问,以及如何通过劫持路由协议实现横向移动。这些技术不仅适用于高级红队演练,也揭示了企业网络中可能被恶意攻击者滥用的安全风险。


自我介绍 👨💻

我是来自台湾的Sufo,目前在趋势科技担任红队研究员。我毕业于清华大学,曾是黑客协会会长。我热衷于实验和探索网络协议。这项研究最初只是出于兴趣,但后来发现它对通用网络安全具有重要意义。你可以在我的Github账户上找到相关工具和研究材料。


议程 📋

首先,我将分享一些使用IP欺骗的新红队技术,以及如何利用它们进行初始访问。接着,我将揭示VXLAN配置的噩梦,包括内部劫持以及有缺陷的路由协议如何导致IP劫持甚至域名失陷。最后,在进入问答环节前,我将总结一些关键要点。


第一部分:源IP欺骗技术 🎭

上一节我们介绍了课程概述,本节中我们来看看源IP欺骗技术。

我们都知道,即使在近年,在公共网络上进行数据包欺骗仍然是可能的。例如,一个IP地址为2.2.2.2的攻击者可以发送一个源IP为3.3.3.3的DNS请求,而3.3.3.3并不属于他。当这个IP数据包到达1.1.1.1时,1.1.1.1无法验证数据包是伪造的还是有效的,它会将DNS响应发送回3.3.3.3。这样,3.3.3.3就会收到一个它并未请求的DNS响应。这是一种典型的DDoS DNS放大攻击,至今仍然有效。

接下来,我将深入探讨公司网络结构。出于安全目的,IT人员通常会阻止内部计算机访问公共网络。

以下是两种常见的做法:

  • 最佳实践:当数据包从关键服务器发送到公共IP并到达防火墙时,防火墙会丢弃该数据包。
  • 常见但错误的做法:一些IT人员只是禁用了NAT。数据包仍然会流出到广域网,远程服务器会看到源IP无效,它要么丢弃数据包,要么响应一个未知地址,而客户端将收不到消息。虽然代码逻辑有缺陷,但网络连接可能仍然“工作”。

如果我们同时考虑这两种情况,在互联网上伪造源IP地址会发生什么?

想象一个红队场景:攻击者入侵了公司设备1.1.1.3。他可以在C2服务器与被入侵设备之间建立一个隧道。之后,他可以通过隧道创建一个DNS请求,其源IP是攻击者的公共IP 9.9.9.9。当数据包到达被入侵设备时,它会转发到公司的互联网路由器。路由器查询其IP路由表,然后将数据包转发给第二个受害者1.1.1.2。我们知道,如果没有针对1.1.1.2的防火墙,响应数据包将通过公共互联网发送回攻击者。然后攻击者将收到数据包,而整个TCP或UDP流中没有任何证据表明数据包来自1.1.1.3,只显示源IP是9.9.9.9,目标IP是1.1.1.2

这就是为什么事件响应在典型的横向移动攻击中很困难。攻击者使用先前被入侵机器的IP地址来攻击下一个系统。这意味着当警报触发时,事件响应团队可以简单地使用网络日志来追踪攻击者从一台被入侵机器到前一台的路径。他们可以在前一台被入侵机器上找到相关日志,识别初始入侵点,然后关闭整个攻击链。

然而,当涉及欺骗技术时,日志中的源IP将不是前一台被入侵的机器。因此,事件响应团队将无法找到入侵路径。他们只能看到一个公共IP正在攻击他们的域控制器。这样,即使警报被触发,先前被入侵的机器也不会被发现,并且攻击者可以切换到另一个公共源IP继续攻击。

纵观整个路径,恶意数据包的源IP和目标IP只显示9.9.9.91.1.1.2。因此,没有人会知道先前被入侵的机器是1.1.1.3。另一方面,隧道IP是HTTPS流量,源IP是7.7.7.7。如果9.9.9.9是攻击者,他可以简单地切换到另一个公共IP并攻击不同的目标。事件响应团队将需要检查每个路由器的第二层端口日志,以识别被入侵的设备。

此外,源MAC地址可以在第一跳被伪造。如果ISP过滤源IP是私有IP的数据包怎么办?我们可以使用3.3.3.3:32445的NAT穿透来启用临时目标NAT。攻击者可以发送一个特殊的数据包到9.9.9.9:32445。然后,NAT路由器将为1.1.1.3:445在公共IP端口32445上创建一个临时目标NAT。它允许攻击者通过9.9.9.9:32445连接到1.1.1.3:445

这里有一个快速演示。我们可以看到2.2.2.4:8080上有一个Web服务器。最初,位于1.1.1.4的攻击者无法通过公共IP访问内部Web服务器。在我们创建服务器并从被入侵机器发送一个UDP 2323数据包后,我们可以从受害者路由器收到一个数据包,它给出了连接内部Web服务器的目标端口。此外,我们可以看到Web日志中的源IP来自公共IP而非私有IP。这在攻击链中制造了一个断点。

另一种由Chi Ming Cai发现的方法涉及从被入侵设备伪造一个假的TCP SYN数据包,其源IP使用下一个目标IP地址1.1.1.3,并将其发送到攻击者的C2服务器。源NAT机制可以被滥用作目标NAT来连接内部服务。

这是另一个快速演示。我们可以看到1.1.1.35:8080上运行着一个Web服务器。最初,位于3.1.3.1的攻击者无法通过公共IP访问内部Web服务器。在我们从被入侵机器发送一个SYN数据包后,使用下一个目标IP和端口作为源IP并发送到攻击者C2服务器,我们就可以使用欺骗数据包中的目标端口连接回受害者路由器。SNAT机制将允许我们连接到内部Web服务器。此外,我们可以看到Web服务器日志显示源IP是公共IP而非私有IP。这同样在检测中制造了一个断点。

那么,我们是否可以用官方的VPN来替代C2隧道?答案是肯定的。如图所示,有许多商业SSL VPN解决方案可以欺骗来自客户端的源IP,例如Fortinet、Cisco、Palo Alto Networks的解决方案可能允许这种行为。另一方面,开源VPN解决方案如WireGuard和OpenVPN是否受影响取决于它们的配置。


第二部分:利用现有隧道进行初始访问 🚇

上一节我们介绍了源IP欺骗技术,本节中我们来看看如何利用现有隧道进行初始访问。

关于初始访问:我们是否有可能在没有互联网初始立足点的情况下做到这一点?我们能否使用任何现有的隧道?答案同样是肯定的。在互联网交换中心,每个人都在同一个第二层网络上。攻击者可以将私有网络范围设置为要攻击的公司路由器的下一跳。此外,我们可以滥用现有的隧道,如GRE、IPIP或SIT。但同样,良好的防火墙配置可以阻止这种攻击。

如果我们入侵了内部交换中心的路由器,我们可以强制将私有子网作为受害者公司路由器的下一跳。我们可以使用我们自己的公共IP作为源,私有子网作为目标来创建连接。受害者路由器会将数据包转发到其内部子网,并通过公共IP响应攻击者。

另一方面,我们可以滥用现有的内部隧道,如GRE。GRE是一种无状态的第三层隧道。它被广泛使用,因为它易于设置,只需要设置协议、公共IP和GRE接口IP。如今,仍有许多公司在他们的产品中使用GRE,例如Cloudflare Magic Transit及其客户。他们可以在ISP之间使用GRE,而ISP更安全。AWS Transit Gateway也支持VXLAN,但仅用于内部网络。此外,安全周刊报告称,像Sofacy这样的APT组织创建了巨大的隧道来收集来自被入侵设备的流量。最后,仍有许多公司使用GRE,但我们不知道。

GRE是如何工作的?当一个数据包想要通过GRE隧道时,内核会用一个GRE头封装数据包,并通过公共互联网发送。在接收端,GRE数据包被解封装,内部数据包根据路由表进行转发。GRE是明文且不提供加密的,这意味着任何人都可以通过公共网络发送GRE数据包。例如,1.1.1.2想发送一个数据包给2.2.2.2。数据包将发送到其默认网关。网关路由器会为数据包添加一个头,并通过公共网络发送。当GRE数据包到达2.2.2.2时,它会移除GRE头,并根据其路由表转发内部数据包,反之亦然。

那么我们如何找到隧道?我们可以使用OSINT技术。例如,我们可以在Google上搜索像Arbor这样的Netflow仪表板,并过滤GRE流量。这样,我们就可以获得隧道两端的IP地址。其他OSINT技术也有帮助。

接下来,我们可以使用GRE欺骗技术来扫描现有的GRE隧道。首先,我们可以使用上面提供的命令创建一个假的GRE隧道。然后,我们可以创建一个源IP地址被欺骗的GRE数据包(一个不属于我们的IP),并通过公共网络发送给受害者。如果受害者有一个GRE对等体,其IP与GRE数据包中的源IP(例如1.1.1.1)冲突,它将解封装内部数据包,并根据其IP路由表处理并转发内部数据包。因此,我们可以创建并发送许多具有不同源IP地址的数据包到正确的受害者。如果受害者不将源IP识别为已知对等体,它将丢弃数据包。另一方面,如果源IP与受害者已知对等体之一匹配,受害者将接受GRE数据包,并根据其路由表转发内部数据包。

出于扫描目的,我们将内部数据包的目的地设置为受害者自身。这样,受害者会立即用ICMP响应回复内部数据包。然后,我们就可以识别受害者是我们的GRE对等体IP地址。我们将信息编码到ICMP标识符和序列号字段中,这两个字段一起可以表示所有255.255.255.255个可能的IPv4地址。我们还在Github上创建了一个扫描脚本。如你所见,当GRE源地址与远程GRE对等体地址匹配时,我们可以得到ICMP回复。

然后,我们可以将所有内容整合起来,获得初始访问权限。想象一个场景,受害者1.1.1.12.2.2.2有一个GRE隧道。攻击者可以伪造一个看起来是从2.2.2.2发送的GRE数据包。内部数据包是一个从提供商IP 3.3.3.3发送到内部网络IP的DNS请求。当数据包到达时,受害者会信任并使用这个GRE数据包,因为它声称来自2.2.2.2。然后,受害者将解封装GRE数据包,发现它包含一个目的地是私有网络IP的DNS请求。受害者将根据其路由表将数据包转发到公司内网。当内部DNS服务器收到DNS数据包时,它会响应并通过公共网络向攻击者服务器发送回复。这样,攻击者就可以与受害者内网的服务进行交互,包括那些使用TCP协议的服务。

我们创建了一个演示实验室。架构如图所示。Web服务器托管在内网IP 1.1.1.2上。服务器可以通过SNAT访问公共网络。另一方面,IP为2.2.2.1的路由器可以直接访问互联网服务器。此外,该路由器有一个公共IP,并与IP地址为1.1.1.1的路由器有GRE隧道。最初,位于IP 1.1.1.4的攻击者无法访问内部Web服务器1.1.1.2。攻击者可以创建一个欺骗性的GRE隧道连接到受害者路由器,并通过假隧道直接向内部网络发送流量。然后,攻击者可以直接访问并与内部Web服务器交互。

类似地,如果是像GRE这样的第二层隧道,并且如果我们能获取受害者的MAC地址,我们也可以用同样的方式利用它。通常使用SNMP协议来获取MAC地址。

TL;DR 总结:当公司没有配置防火墙并使用未加密的隧道(即使是遗留配置)时,攻击者可以利用此隧道进行内网的初始访问。


第三部分:VXLAN配置的噩梦 😱

上一节我们介绍了如何利用GRE隧道,本节中我们来看看VXLAN配置的风险。

那么什么是VXLAN?VXLAN是一种无状态且未加密的第二层隧道。它将第二层以太网帧封装到第四层UDP数据包中。每个网络由称为VNI的名称唯一标识。我们可以通过给出远程IP、本地IP、目标端口和VNI来配置VXLAN隧道,类似于GRE。然而,这种配置是脆弱的。

基于先前的配置,设置一个标准的VXLAN隧道对和往常一样简单。那么劫持一个VXLAN隧道呢?是的,这里唯一的区别是更改你的本地IP参数。为什么会发生这种情况?Linux内核不检查VXLAN数据包的源IP吗?为什么它接受具有有效VNI和端口的VXLAN数据包,即使源IP未配置?查看Linux手册后,你会发现这是一个特性而非漏洞,但这并不安全,并且在报告之前默认是开启的,你无法关闭此功能。现在,你可以更改设置为关闭,但它默认仍然是开启的。

那么,当VXLAN中启用学习模式时会发生什么?通常,当配置的对等体发送一个VXLAN数据包时,内核会将其MAC地址添加到FDB(也称为转发数据库表)中,如底部所示。下次需要发送数据包到FDB表中列出的目标MAC地址时,内核会封装并使用FDB表中的信息将数据包发送到远程位置。类似地,当学习模式启用时,任何具有有效VNI和端口的VXLAN数据包都会被添加到FDB表中。此外,远程IP可以是互联网上的任何IP。因此,攻击者9.9.9.9可以创建一个MAC地址为FF:FF:FF:FF:FF:FF的VXLAN数据包,而Linux内核会将此MAC添加到列表中。然后,当内核想要在VXLAN接口上发送广播数据包时,它会查找FDB表并将其发送到9.9.9.9,即攻击者的地址。

那么攻击者需要知道什么才能劫持VXLAN隧道?我们知道自己的IP,但我们不知道受害者的IP、端口、VNI或VXLAN内部子网。然而,所有这些信息都可以通过一次扫描获得。攻击者可以通过发送大量数据包来发现受害者的IP、端口和VNI。

让我们首先关注如何确定VXLAN内部子网范围。我们可以通过发送一个VXLAN数据包来收集信息,其中源和目标MAC地址都设置为广播地址。然后,当从VXLAN接口发送ARP请求时,它们也会被发送到攻击者的VXLAN。另一种方法涉及发送邻居发现协议数据包。当路由器收到广播的NDP消息时,它会用自己的IP和MAC地址响应广播MAC地址。因此,我们可以发送许多具有不同VNI和端口配置的VXLAN数据包,每个数据包包含一个内部NDP数据包,其中源和目标MAC地址都设置为广播地址。当VNI和端口与受害者配置匹配时,受害者设备会将攻击者IP添加到其FDB表中。然后受害者解封装VXLAN数据包,发现它是一个NDP请求。受害者路由器回复NDP数据包,并尝试将响应发送到广播MAC地址。它检查FDB表,发现目的地是9.9.9.9,即攻击者IP。因此,路由器会将数据包发送给攻击者。这样,攻击者就拥有了劫持隧道所需的一切。

我们还创建了一个扫描器。我们可以通过发送大量数据包来发现受害者的IP、端口和VNI。VXLAN的默认端口是47898472。VNI通常小于100。这是扫描器链接。我们还为VXLAN扫描器演示创建了一个实验室,其中包括一个路由器、一个Web服务器。如你所见,我们的目标是扫描2.2.2.200。扫描器发送许多具有不同目标端口和不同VNI的数据包。然后,我们可以收到一个VNI为42、端口为8472的邻居发现协议回复。内部子网是10.0.0.0/24。然后,只需使用上述信息创建一个VXLAN隧道,我们就可以直接访问VXLAN内网。

我们还使用VNI等于1和目标端口在全球范围内扫描了VXLAN配置。我们发现超过900个VXLAN端点响应了扫描器。此外,VXLAN子网内有4000个IP。其中一些是公共IP,这意味着我们可能劫持公共IP。此外,一些端点回复了大量广播数据包。结合IP欺骗技术,这可能导致DDoS攻击。最后,一些VXLAN数据包的源IP是私有地址。这引发了一个问题:为什么私有地址被用作VXLAN数据包的源IP?

我使用加密的隧道,所以我是安全的。答案是否定的。由于VXLAN的行为,VXLAN仍然会在不同接口上发送数据包流量,它仍然可能被劫持。

TL;DR:我们只需要三条信息就可以劫持一个VXLAN隧道:受害者的IP地址、VXLAN端口和VNI。不需要知道对等体IP或内部IP地址。此外,如果你的网络设置包括公共IP接口和任何接口上的VXLAN,它是高度脆弱的。

那么攻击者在劫持隧道后能做什么?攻击者不仅可以访问内网,还可以劫持IP通信或在两个站点之间执行中间人攻击。此外,攻击者可以针对网络服务,例如利用路由器上的RCE漏洞。事件响应具有挑战性,因为源IP不可信。而且,这些隧道通常运行路由协议,如BGP或OSPF。攻击者可以劫持甚至不通过隧道传输的IP,例如域控制器或Exchange服务器的IP。

那么什么是路由协议?它是一种路由器可以与其他路由器交换路由和网络信息的协议。路由协议帮助路由器了解周围的网络,并确定转发数据包的最佳路径。例如,路由器A有192.168.1.0/24。路由器C可以通过路由协议从路由器B学习到这条路由。我们经常看到公司使用VPN连接两个站点,并运行路由协议。但是,当我们将其与学习功能结合时,我们可以劫持路由器A的IP地址。然后,我们可以在路由协议中宣告域控制器的IP为/32。其他路由器将收到并信任这个路由前缀,并将域控制器的流量重定向到攻击者,因为/32的路由比/24更具体。

我们总结了劫持不同服务IP的潜在影响:

  • 如果攻击者劫持了域控制器的IP

滥用网络会议进行隐蔽命令与控制 👻

在本节课中,我们将要学习一种名为“幽灵呼叫”的技术,它通过滥用网络会议基础设施来建立隐蔽的命令与控制通道。我们将探讨其原理、优势、实现方法以及防御考量。


概述

我是 Adam Crossser,Praetorian 的安全工程师。本次课程旨在解决一个实际问题:在红队行动中,我们缺乏一个理想的短期命令与控制通道。本节将定义不同类型的C2通道,并解释为何网络会议服务成为了一个极具吸引力的目标。


C2通道类型定义

在深入探讨之前,我们需要明确几种在红队行动中可能用到的命令与控制通道类型。

以下是四种主要类型:

  1. 短期通道:用于执行需要低延迟和高带宽的任务,例如SOCKS代理、隐藏VNC、远程端口转发或通过主机上的植入程序隧道传输不同工具。
  2. 长期通道:这是系统重启后仍会持续运行的通道,通常部署在你持续操作的系统上。许多人使用同一个通道处理短期和长期任务,但本课程将解释这有时并非最佳选择。
  3. 备用C2通道:旨在应对清除行动,提供多种额外的回连方式。攻击者可以发挥创意,例如利用未加入域、未安装EDR的叉车平板电脑等隐蔽位置。
  4. 点对点通信通道:用于桥接内部网络中的系统。例如,一个系统可以访问内部PCI环境但没有互联网,另一个系统有互联网但不能访问PCI环境,此时可以使用ICMP或命名管道等技术将它们连接起来。

我们当时面临的问题是,缺乏一个令人满意的短期命令与控制通道解决方案。


理想短期C2通道的属性

上一节我们定义了问题,本节中我们来看看一个理想的短期C2通道应具备哪些关键属性。

我们通过头脑风暴,确定了以下四个核心属性:

  • 延迟:指从发送消息到植入程序接收消息所需的时间。对于交互式操作至关重要。
  • 吞吐量:指在特定时间段内可以发送的数据量。对于传输大量数据(如文件)非常重要。
  • 可达性:该通道在企业网络中的普遍程度。如果使用ICMP或Tor等不常见的协议,其可达性就较差。
  • 信任度:指所使用的基础设施是否被目标环境允许列表排除,或免于某些类型的检查(如TLS解密)。使用受信任的基础设施能降低被发现的风险。

理想的短期C2通道应具备低延迟、高吞吐量、高可达性和高信任度


评估潜在通道

基于上述框架,我们评估了几种潜在的通道方案。

以下是我们的评估结果:

  • DNS-over-HTTPS:延迟较低,但吞吐量存在问题。大量数据通过Google的DoH服务器会显得异常。在企业环境中,内部通常使用自定义DNS,因此可达性一般。信任度尚可。
  • 云文件存储:吞吐量不错,但延迟通常较高,不适合需要实时交互的任务。可达性取决于具体服务是否被企业屏蔽,信任度中等。
  • 攻击者自有基础设施:例如购买一个已存在多年的域名。延迟和吞吐量可能很好,但该域名本身就是攻击者资产,缺乏信任度,容易被标记。
  • 电子邮件和即时通讯应用:延迟因服务而异(电子邮件较高),吞吐量一般。可达性和信任度通常能满足要求。

最终,我们将目光投向了网络会议基础设施


为何选择网络会议基础设施?

上一节我们排除了其他选项,本节我们来重点分析网络会议服务为何能完美匹配我们的需求。

将理想属性框架套用在网络会议上,会发现它们高度契合:

  • 低延迟:网络会议设计用于真人实时互动,对延迟容忍度极低。
  • 高吞吐量:需要传输多个视频流,因此必须具备良好的数据吞吐能力。
  • 高可达性:疫情后,Zoom、Microsoft Teams等解决方案被广泛使用,大多数公司用户至少会使用其中一种主流产品。
  • 高信任度:这是关键。许多供应商(如Microsoft和Zoom)在其官方文档中建议,为了确保性能和功能正常,应将流向其服务的流量排除在全局VPN隧道和TLS解密之外。这使得这些流量在企业网络中享有特殊“通行权”。

需要声明的是,供应商提出这些建议并非出于恶意或疏忽,而是其低延迟、高吞吐量系统设计的性能要求使然。


网络会议服务的工作原理

现在我们确定了目标,本节我们来看看这些服务是如何工作的,以及我们可能利用哪些路径来路由流量。

大多数网络会议服务架构相似,我们可以用一个通用模型来描述:

  1. 用户设备通过SaaS应用加入会议。
  2. 系统为该会议分配或查找一个媒体服务器
  3. 通信模式通常有两种:点对点客户端-中央媒体服务器
  4. 为了协助通信(尤其是在NAT或防火墙后),服务还部署了STUN/TURN基础设施。TURN服务器在无法建立直接P2P连接时,充当通信中继。

对于本课程,理解 WebRTC握手过程 至关重要。简单来说,两个客户端(如Alice和Bob)需要通过交换 SDP OfferSDP Answer 来建立连接,协商密钥等信息。

我们研究了Zoom和Google Meet的流量,发现:

  • Zoom使用自定义协议,但本质上是RTP协议的封装。
  • Google Meet使用标准的WebRTC,采用DTLS进行密钥交换,SRTP进行音视频通信。

网络会议服务的适应性

一个有趣的发现是,这些服务在出站连接方面极具适应性。我们可以在严格限制的实验室环境中测试它们的行为。

假设一个极端环境:只允许通过强制执行TLS解密的Web代理出站,阻止所有其他直接连接。

以下是Zoom客户端(桌面版和网页版)的适应过程:

  1. 首先尝试通过443/TCP TLS使用自定义协议连接 -> 被阻止
  2. 切换到通过443/TCP WebSocket连接“区域控制器”来查找媒体服务器 -> 成功
  3. 尝试直接连接媒体服务器(443/TCP 和 8801/UDP)-> 被阻止
  4. 切换到通过WebSocket连接发送本应走上述两条通道的数据 -> 成功

Zoom网页版略有不同,它使用WebRTC数据通道来传输其自定义协议。当UDP连接被阻时,它会尝试回退到使用 TURN over TLS (TURNS) 协议,这通常在严格环境中也能工作。如果还不行,最终会回退到通过WebSocket发送音视频数据。

核心要点:这些解决方案能灵活适应不同的网络环境和出口控制,尽管性能会随着回退而下降(例如,使用WebSocket传输音视频会比直接UDP慢)。


目标选择与凭证获取

我们选择Zoom和Microsoft Teams作为主要目标,因为它们是市场份额最大的两家供应商。即使某个公司内部不使用它们,其员工也极有可能为了与外部客户沟通而使用这些服务,因此相关流量在企业网络中普遍存在。

我们进行了逆向工程:

  • Zoom:重点研究了网页客户端,发现了其用于TURN基础设施的凭证。这些凭证关联于 zoom.us 子域名,该域名正在供应商建议的允许列表和TLS解密排除列表之内。
  • Microsoft Teams:发现了一个无需加入会议即可访问的未认证端点,可以从中获取TURN凭证。

这些凭证的有效期通常为数天,且不绑定于任何特定会议。受害者无需安装或使用这些应用,我们只需获取凭证即可利用。


工具构想与用例

有了理论和技术基础,本节我们来构思需要构建的工具及其应用场景。

我们想构建一个工具,用于创建短期C2植入程序,与现有的长期C2并行使用。它应与植入程序平台无关(如Cobalt Strike、Nighthawk或自定义C2),只要能在目标上执行代码即可。

在网络层面,使用此工具的几个小时流量看起来就像在进行视频通话,但实际上我们正在利用供应商的基础设施进行:

  • SOCKS代理
  • 内部网络扫描
  • 远程端口转发
  • 浏览内部Web应用等高带宽操作

为何需要与长期C2并行?

  1. 性能:长期C2通道可能较慢,不适合高带宽任务。
  2. 隐蔽性:长期C2通道本身可能很隐蔽,但一旦开始传输大量数据(如10GB),异常流量模式就容易引起怀疑。而通过会议通道传输大量数据,观察者会自然地认为是视频流量。

我们构建的工具名为 TurnTunneler。它支持以下关键用例:

以下是TurnTunneler的主要用例:

  1. SOCKS代理:通过TURN基础设施进行代理上网。
  2. 去中心化C2:无需中央C2服务器,可直接在操作员机和受害机之间建立点对点连接,适用于“假定突破”场景。
  3. 本地与远程端口转发
    • 远程端口转发:在受害机上绑定一个端口,所有连接到该端口的流量通过Tunnel(如Microsoft Teams)转发到操作员机上的服务。例如,暴露一个在操作员机上运行的 ntlmrelayx 工具到内网。
    • 本地端口转发:在操作员机上绑定一个端口,通过该端口的流量会通过Tunnel从受害机发起连接。例如,访问一个仅限内网访问、无需MFA的Citrix服务。


演示:Zoom 与 Microsoft Teams

本节我们将通过两个简单的演示来展示攻击流程。

演示1:Zoom

  1. 获取凭证:在操作员机上,使用配置了Burp Suite的浏览器加入一个Zoom会议。会议加载后,在Burp的历史记录中搜索约1200字节的响应,其中包含TURN凭证。
  2. 建立隧道:将凭证填入配置文件。在操作员机上运行控制器组件,生成一个 SDP Offer。通过现有C2通道(演示中用SSH代替)在受害机上运行中继组件,并输入该Offer。WebRTC连接通过Zoom的TURN基础设施建立。
  3. 数据传输:通过建立的隧道下载文件,速度可达约8-10 MB/s。
  4. 网络流量:在Wireshark中可见到往 zoom.us 子域名的TLS连接。

:Zoom在近期已对此进行了缓解,修改了其TURN服务器策略,限制了连接目标。但该技术对Microsoft Teams仍然有效。

演示2:Microsoft Teams

  1. 获取凭证:使用我们编写的凭证获取工具自动从Microsoft Teams端点获取TURN凭证。
  2. 建立隧道与端口转发:流程与Zoom类似。建立连接后,演示下载一个100MB的文件。然后,演示远程端口转发:在操作员机上运行一个简单的Python HTTP服务器,通过工具在受害机的8080端口上创建远程转发。此时,从外部访问受害机8080端口的流量,会被通过Microsoft的TURN基础设施转发到操作员机上的HTTP服务器。
  3. 网络流量:在Wireshark中可见到往 teams.microsoft.com 子域名的TLS连接。

防御考量与未来工作

课程最后,我们来探讨防御思路和该技术的未来发展方向。

防御建议:

  • 检测重点转移:在网络层面检测此类隧道非常困难。建议将重点放在杀伤链的其他环节
    • 不要试图检测隧道本身,而是检测通过该隧道运行的攻击工具(如 secretsdump.py, ntlmrelayx 等)。
    • 关注异常行为,例如从未安装会议客户端的进程发起对会议域名的连接,但请注意这可能有误报。
  • 利用诱饵:考虑在内网关键应用(Confluence, Slack等)或云服务上部署诱饵令牌,攻击者一旦通过隧道访问就会触发告警。
  • 供应商缓解:供应商可以限制TURN凭证的用途。例如,Zoom的缓解措施表明,如果TURN仅用于连接中央媒体服务器(而非通用P2P),则可以进行限制。

未来工作:

  • 扩展研究:研究除Zoom和Teams外的其他网络会议提供商(如Webex, Google Meet)或提供托管TURN服务的厂商(如Cloudflare),寻找可用的凭证。
  • 优化工具:当前中继组件用Go编写,体积较大。探索用C/C++重写以减小体积。
  • 调查安全设备默认配置:了解常见安全设备是否默认遵循了供应商关于排除TLS解密的建议。

总结与资源

本节课中,我们一起学习了“幽灵呼叫”技术。我们分析了短期C2通道的理想属性,发现网络会议基础设施因其低延迟、高吞吐量、高可达性和高信任度而成为理想载体。我们探讨了其工作原理、适应性,并演示了如何通过获取TURN凭证来滥用Zoom和Microsoft Teams的服务建立隐蔽隧道,实现SOCKS代理和端口转发。最后,我们讨论了以检测工具而非隧道为核心的防御思路,以及该领域的未来研究方向。

相关资源:

  • 深度技术博客:包含更详细的技术细节。
  • 工具GitHub仓库:可下载TurnTunneler工具,并提供与Nighthawk等C2平台集成的文档。
  • 联系作者:可通过LinkedIn联系Adam Crossser进行交流。

HTTP/1.1 必须消亡!反序列化攻击的终局 🎯

在本节课中,我们将探讨 HTTP/1.1 协议中一个根本性的安全缺陷——请求反序列化攻击。我们将了解为何这种攻击持续存在,探索新的攻击技术,并讨论如何从根本上解决这个问题。


协议的根本缺陷 🔍

上一节我们介绍了课程主题,本节中我们来看看 HTTP/1.1 协议的核心问题。

这一切始于 2019 年,当时我意识到 HTTP/1.1 存在一个致命缺陷:各个 HTTP 请求之间的隔离性从根本上被破坏了

没有一个单一可靠的方法来确定一个请求在哪里结束,下一个请求在哪里开始。这意味着攻击者只要发现前端和后端之间存在最微小的解析差异,就能混淆请求的实际内容,从而引发反序列化攻击。这种攻击通常能让攻击者完全控制网站。

由于 HTTP/1.1 是一个古老、宽容、基于文本的协议,拥有成千上万种独特的实现,找到解析差异点并不困难。当时的感觉是,几乎可以攻击任何你想攻击的网站。例如,我曾展示过如何利用它两次持久性地攻破 PayPal 的登录页面。

我们知道解决方案是:在前端和后端服务器之间的上游连接中使用 HTTP/2,这几乎可以消除整个攻击类别。


六年后的现状:补丁与漏洞的错位 ⏳

上一节我们了解了问题的根源,本节中我们来看看六年后的现状。

那么,六年过去了,有什么变化?我们并没有开始为后端连接使用 HTTP/2。我们开始在客户端和前端之间使用 HTTP/2,但随后大多只是将这些请求降级为 HTTP/1.1 来与后端通信,这实际上使情况变得更糟。

然后,因为一些系统确实遭到了攻击,我们决定采用被称为正则表达式的终极安全措施来加固。

结果是一团糟。这是一个经典的反序列化检测探针。你发送两个请求,如果目标存在漏洞,那么第一个请求会毒化到后端的连接,意味着第二个请求的前缀会被加上橙色文本所示的内容。

如今,如果你在一个现代目标上尝试这个探针,它很可能会失败,即使目标实际上存在漏洞,因为它会被多个寻找 Transfer-Encoding 头的正则表达式拦截。

或者它会失败,因为那个检测小工具可能在该目标上不起作用,而我们没有使用很多不同的检测小工具。或者它会因为该策略涉及的众多竞态条件之一而失败。是的,还有一种基于超时的替代方法没有竞态条件问题,但它被正则表达式拦截得更严重。

总而言之,在过去的六年里,业界修补了检测方法,修补了扫描工具,但实际的漏洞在很大程度上并没有被修复


反序列化攻击的终局:表面安全下的危机 🎲

上一节我们看到漏洞依然存在,本节中我们来看看这创造的“终局”局面。

这创造了反序列化攻击的“终局”,乍一看一切似乎都很安全,但如果你对方法做最微小的改变,事情就会迅速变得有趣。

让我们看一个例子。几个月前,我收到 Vans 的邮件,说他发现了一个令人困惑的漏洞,想听听我的看法。

他尝试的攻击很普通。你发送这样的请求,它被降级为 HTTP/1.1,毒化了到后端的连接。因此,下一个访问该漏洞网站的用户会被重定向到我们的网站。由于缓存,这个重定向会被保存,所以我们可以重定向 JavaScript 文件,保存它,并持久地控制网站上的任何页面。

它运行得非常好,除了一件小事:被劫持的用户实际上并没有试图访问目标网站

攻击实际上危害了随机的第三方网站,包括银行等。这有点奇怪。

显然,服务器设置不是这样的。它一定更复杂。

在分析了目标基础设施后,我认为,这一定是 Cloudflare 前端和 Heroku 的前端反向代理之间的反序列化,所以我们一定是在利用 Heroku 上托管的随机网站。

然而,这个分析完全错误,因为同样地,那太简单了。

当我尝试复现攻击时意识到了这一点,我想,等等,他在这里犯了个错误。请求被 Cloudflare 的缓存拦截了,这意味着攻击甚至从未到达 Heroku。

所以我通过添加一个缓存破坏参数纠正了他的错误。然后攻击就停止了。

这意味着什么?这意味着 Heroku 与此无关。有一段时间,如果你正确测试任何 Cloudflare 网站,你什么也发现不了。但如果你忘了指定缓存破坏参数,那么你就会在 Cloudflare 自己的基础设施内引发反序列化,使你能够持久地危害几乎每一个使用 Cloudflare 的网站。

这就是反序列化攻击的终局。看起来一切安全,但你犯一个错误,结果就攻破了 2400 万个网站。


为何此类漏洞持续存在?复杂性与根本原因 🧩

上一节我们看到了一个惊人的案例,本节中我们来探讨这类漏洞为何持续存在。

这样的漏洞是如何发生的?部分原因是所涉及系统的过度复杂性。例如,在这个案例中,Cloudflare 通过 HTTP/2 接收请求,然后将其转换为 HTTP/1.1 供内部使用,接着又转换回 HTTP/2 用于上游连接。

但根本问题来自基础。

有一种观念认为 HTTP/1.1 是一种像 TCP 一样的简单架构级事物,可以依赖。我们认为它是安全的,因为我们知道简单的东西往往更安全。

但实际上,一旦你尝试代理 HTTP,它就不再简单,变得非常复杂。为了说明这一点,以下是我个人曾经相信的关于 HTTP/1.1 的五个谎言。

本节中的每一个谎言都将被用于一次漏洞利用。

当结合时,最后三个谎言意味着你的代理需要状态,只是为了从后端读取正确数量的字节。你甚至需要在到达正文之前,就为读取头部块进行特殊处理。整个响应可能在客户端请求接收完之前就已经到达。

这就是 HTTP/1.1。它是 Web 的基础。它由暴露数百万网站的地雷构成,而我们花了六年时间证明我们无法修复它。

它需要消亡。


如何终结它?推广 HTTP/2/3 🚀

上一节我们明确了问题的严重性,本节中我们来看看解决方案。

那么,我们如何终结它?我们需要共同向世界展示,上游的 HTTP/1.1 是不安全的,更多的反序列化攻击总会到来。在本节的剩余部分,我将展示如何做到这一点。

首先,我将介绍一个新的工具包来处理反序列化攻击的终局。然后,我将分享两个全新的攻击类别,暴露数百万更多的网站。接着,我将重点看看我们如何摆脱这种困境。最后,我将总结并在后面回答一些问题。

在本节中,我将大致按时间顺序跟随研究历程。所以在开始时,我们将获得知识,但不会有太多漏洞赏金之类的东西。但随着这些知识将我们带到超越现有技术水平的地方,事情将迅速变得有利可图得多。

本节中提到的所有赏金已在所有相关人员之间平均分配,我所得部分的 100% 已由 PortSwigger 加倍并捐赠给当地慈善机构,所有命名目标中的漏洞均已解决。


赢得终局:新工具与检测方法 🛠️

上一节我们概述了行动路线,本节中我们来看看赢得终局的具体方法。

要在反序列化攻击的终局中获胜,基本上,规则 0 是不要使用 Transfer-Encoding。但要取得任何进展,我们需要一种可靠的方法来检测解析差异,且不会被正则表达式拦截。

早在 2021 年 BlackHat Europe 的一次演讲中,Daniel Thatcher 给了我们一个方法。我对他的演讲中的概念感到非常兴奋,以至于我从头开始实现了一个自己更强大的版本。我很高兴今天在 HTTP Request Smuggler 版本 3 中发布它。这是一个开源的 Burp Suite 扩展,完全兼容专业版、企业版和免费的社区版。

简而言之,这个工具使用广泛的技术来分析和分类目标前端和后端如何解析请求,并找到差异。

例如,在这个目标上,通过查看响应状态码,我们可以看到,如果我们使用空格来掩盖 Host 头,会得到一个独特的结果,这与我们完全省略 Host 头得到的结果不同。从这一点,加上显示的其他响应,我们可以推断出我们找到了一个解析差异。

我称之为“可见隐藏差异”,因为被掩盖的头部对前端可见,但对后端隐藏。通常,你可以通过隐藏 Content-Length 头,将这些差异转化为经典的 CL.0 反序列化攻击。

但关键的是,如果在构建该漏洞利用时遇到任何问题,你可以调整并处理它们,因为你已经找到了根本缺陷。例如,在另一个目标上,他们拒绝带有正文的 GET 请求,但我能够通过切换方法为 OPTIONS 来轻松处理这个问题。

正是这种克服障碍的灵活性使这种方法如此有价值。

此外,通过结合广泛的不同头部、排列和策略,它可以实现非常好的覆盖率。例如,这里我们仍然使用 Host 头作为检测小工具,并用前导空格隐藏它。但这次,我们发送一个带有错误格式值的重复 Host 头。利用这一点,我们在一个银行使用的 Web VPN 上发现了反序列化。

这种策略甚至让你可以预测漏洞。例如,HTTP RFC 允许单独接受 \r 作为行终止符,而工具发现这个特定的服务器不遵守这一点。这意味着如果你将该服务器放在某些代理后面,攻击者可能引发关于正文起始位置的争议,并导致反序列化。当然,那个特定目标不是你会放在代理后面的那种东西。

但我们能够将漏洞追溯到底层 HTTP 库,它被许多不同的系统使用。不幸的是,我不能说出它的名字,因为补丁尚未发布。

该工具还标记了大量在 Amazon 应用负载均衡器后面运行 Microsoft IIS 的服务器。

现在,如果你看这里的服务器标识,你会发现解析差异的发生方向相反:是前端看不到头部,后端能看到,使其成为“隐藏可见差异”。此外,这些目标受到 AWS 的 HTTP 反序列化防护器的保护。当我看到这个时,我想,好吧,这东西有点棘手,我先把它放一边,以后再说。

当它在我架子上积灰时,Thomas Stacy 独立发现了同样的问题,并绕过了反序列化防护器,实现了一个 H2.TE 反序列化。干得好,Thomas。AWS 现在已经修补了那个问题,但他们只修补了反序列化防护器的绕过。底层的解析差异仍然存在。所以你仍然可以利用这个来伪造你的 IP 地址,有时绕过访问控制。如果你想修补它,可以通过更改负载均衡器上的几个设置来实现。

当我看到这个时,我联系了 AWS 说,等等,你们明明有修复这个的设置,为什么不默认修补它?

他们的回应是,他们的客户有一些古老的 HTTP 客户端无法更改,并且依赖于发送格式错误的 HTTP 请求。这就是他们无法修复的原因。所以基本上,如果你使用云代理,你就是将别人的技术债务导入到你自己的安全状况中。

这个发现是事情开始变得非常有趣的地方。现在,我很遗憾不能说出这个目标的名字,因为我将在接下来的 10 分钟里谈论它。所以让我们称它为“目标 X”。这只是另一个隐藏可见的反序列化。但使用 Transfer-Encoding 的明显漏洞利用不起作用,这要归功于 Web 应用防火墙之类的东西。所以它迫使我问:我们如何在这个目标上引发反序列化?如果我们向一个存在隐藏可见差异的目标走私一个 Content-Length 会发生什么?我想那将是 CL.0 反序列化,这是被广泛认为不可能的事情。


突破“不可能”:零内容长度反序列化攻击 ⚡

上一节我们遇到了一个看似无法利用的漏洞,本节中我们来看看如何突破这个限制。

这是因为当前端看不到 Content-Length 头时,它只将头部转发给后端,然后后端在等待正文到达时超时。换句话说,一旦你尝试攻击,就会得到服务器端连接死锁,这对于使网站瘫痪很好,但对于反序列化攻击就没那么有用了。

我偶然发现了这个问题的解决方案。去年,在研究定时攻击时,每当我尝试计算由 Nginx 提供的静态文件加载所需时间,我会得到一个负的响应时间,因为 Nginx 在我完成发送请求之前就响应了我的请求。

这是一个巨大的麻烦,我必须做一个复杂的变通方法才能使定时技术工作,但它表明有时服务器确实会在请求完成之前响应,这将让我们摆脱这个死锁。

不幸的是,这个目标运行的是 IIS 而不是 Nginx。那么,如何让 IIS 在不关闭连接的情况下提前响应你的请求呢?

文档是个好东西。这是一个很好的例子来说明为什么。在 Windows 上,如果你对文件或文件夹使用某些名称,平台会认为你指的是串行控制台或设备驱动程序并崩溃。那么,如果我们在运行 Windows 的服务器上访问那个路径会发生什么?你会遇到一个特殊的代码路径,使服务器提前响应而不等待正文,从而摆脱连接死锁。

这意味着当下一个请求到达服务器时,后端最终会从开头切掉一些数据,你可能会得到一个 400 错误请求响应。

看到这个发生,我立刻情绪激动,原因有二。首先,我知道那个 /con 怪癖已经超过 10 年了,但这是我第一次真正找到它的有效用途,使它可能是我做过的最慢的漏洞利用。其次,在过去的六年里,在进行反序列化研究时,我看到了太多无法解释的 400 错误请求响应,我实际上把它们都作为“我的 400 发现”报告了。当我看到这个时,我意识到所有这些发现很可能都是可利用的。

所以,如果你想进行 CL.0 反序列化,首先需要的是在目标服务器上找到一个提前响应的小工具,一种让它提前响应的方法。一旦你做到了,就该开始着手漏洞利用了。

如果你在第二个请求的头部块内嵌套第二个请求行,并调整第一个请求的 Content-Length,你可以切掉它之前的所有内容,并“解锁”它,如图所示。这很好,因为它让我们超越了 400 错误请求响应,但这还不是一个现实的攻击。我们不能假设受害者自己的请求中恰好有一个用于攻击他们自己的有效载荷。

我们需要的是将我们的有效载荷添加到他们的请求中的方法,而不是仅仅丢弃部分内容。


双重反序列化:构建现实攻击链 🔗

上一节我们找到了提前响应的方法,本节中我们来看看如何构建一个现实的攻击链。

我们可以通过双重反序列化来实现这一点。事情在这里变得有点复杂。

这是一个两阶段攻击,其中第一个请求引发 CL.0 反序列化,然后武器化第二个请求(也来自攻击者)以引发 CL.0 反序列化,接着利用第三个请求(来自受害者)。

最清晰的概念性方法是让第一阶段的有效载荷切掉第二阶段有效载荷的头部,如图所示。然而,虽然这在理论上可行,但在现实中,它基本上总是失败,因为前端服务器倾向于在将请求转发到后端之前注入额外的头部,这使你的长度计算不正确并破坏攻击。

我写了一个脚本来暴力破解注入头部的长度,但这仍然不理想,因为这些头部通常包含可变值,如你的 IP 地址,这意味着你的攻击可能在你把它交给别人复现时就停止工作。这不理想。

幸运的是,有更好的方法。

它们倾向于在头部块的末尾注入头部。所以如果我们的有效载荷在那之前开始,我们的攻击虽然现在看起来有点丑陋和混乱,但会更可靠。在这个特定的例子中,我将该技术与输入反射链接起来,以揭示注入头部的值。

因此,通过将其与经典的 HEAD 技术(将两个响应合并为一个)结合,我能够向随机在线用户提供恶意 JavaScript 并劫持他们的账户。

这个过程涉及某种竞态条件,所以只有当你每秒发送至少几百个请求时才有效。但除此之外,它相当直接。

事情变得有点复杂,但好消息是我们刚刚发布了一个 Web 安全学院实验,所以你可以免费在一个实时系统上自己练习整个攻击链。

使用该技术,我们能够利用相当数量的目标,尽管我们实际上被其他事情分心了,所以我们在影响方面有点敷衍,将它们全部报告为拒绝服务问题,没有得到多少报酬,但我们仍然获得了不错的回报。

这里值得注意的是,大多数这些目标之所以存在漏洞,是因为它们有 Web 应用防火墙,而防火墙正是引入反序列化漏洞的东西。

在这一点上,我想,太好了,我们完成了。反序列化威胁终于被完全描绘出来了,未来的任何问题或新技术都将是奇怪的利基问题,而不是大的类别突破。

这是我每年都会犯的错误。下一个发现让我最终意识到真相,那就是:更多的反序列化攻击总会到来

早在 2022 年,我尝试用 Expect 头引发反序列化漏洞利用。事实证明,我看得远远不够仔细。

Expect 头很特别的第一个线索是它立刻破坏了我的 HTTP 客户端 Turbo Intruder。修复这个问题给代码的敏感部分引入了大量复杂性。当某物给服务器或客户端带来复杂性时,你知道对于代理来说总是会更糟。

Expect 应该将发送请求分解为一个两部分的过程,以便客户端可以提前退出,从而节省带宽。这个头就是这么古老。它所做的,是在服务器和代理代码中一个以前不需要状态的区域引入了状态,因此引发了一大堆边缘情况,基本上让一切以一系列壮观的方式崩溃。


Expect 头:被忽视的攻击面 💥

上一节我们提到了 Expect 头,本节中我们深入探索这个被忽视的攻击面。

这是一个温和的例子。在这个网站上,HEAD 请求(一个特例)工作正常,Expect 也工作正常,但如果你将两者结合,服务器会忘记它是一个 HEAD 请求,意味着它们试图从后端读取太多字节,导致服务器端死锁。

这是你可以预测的那种缺陷。但你也会发现不那么可预测的缺陷,例如在多个不同的服务器上,发送 Expect 头只会让它们泄漏内存,包括密钥。

不幸的是,当我去报告那个时,我发现他们最近关闭了他们的漏洞赏金计划。

因为 Expect 头触发两个响应头部块,它经常破坏移除敏感响应头部的尝试,以向最终用户隐藏它们。所以它做的是,你发送 Expect,就会暴露一大堆额外的内部头部,比如这些在每个使用 Netlify CDN 的目标上都可用的头部。

当我向 Netlify 报告时,我得到了一个有点出乎意料的回应,他们说这是一个功能,但还是为此付了钱。我们很快就会再次看到 Netlify。

大约在这个时候,我收到一个全职漏洞赏金猎人小团队的消息。他们也注意到 Expect 头正在让有趣的事情发生。

通常,研究碰撞不是好消息。事实上,我们有一些非常好的研究样本,计划提交给 Black Hat USA,但由于研究碰撞,我们基本上不得不取消。

但我已经听说过这些好人,因为他们在 T.0 请求走私方面的研究。我想,既然他们知道自己在做什么,并且已经知道这个技术,我们为什么不合作呢?有了他们的帮助,我可能会得到更多案例研究;有了我的帮助,他们应该能赚更多钱。

所以我们合作了,并立即发现,仅仅发送一个普通的 Expect 头就会在许多目标上引发 CL.0 反序列化。

我认为这是由于一个错误造成的:当前端服务器从后端收到响应时,它忘记了自己还没有从客户端收到正文。我选择这个特定的例子是因为它是一个很好的互动,T-Mobile 给了我们 12000 美元的赏金,即使这只影响了一个预生产服务器。所以我将来肯定会对他们进行彻底的测试。

我发现了许多这个问题的案例,但这个特别有趣,原因有二。首先,它只有在你混淆 Expect 头值时才有效。其次,这个域名保存着发送给 GitLab 漏洞赏金计划的漏洞报告的附件。有趣的东西。

所以在这个目标上,我们选择了进行响应

潜入你的日志,欺骗分析师,致盲你的EDR 🕵️♂️

在本课程中,我们将学习 Windows 事件追踪(ETW)的基础知识,探讨安全产品为何依赖它,并深入研究如何通过伪造和滥用 ETW 事件来欺骗安全分析师和端点检测与响应(EDR)系统。我们将从攻击者和防御者的双重角度来审视这一技术。


ETW 简介 🏗️

首先,我们来了解什么是 ETW。ETW 本质上是 Windows 操作系统的一种机制,用于生成遥测数据。它主要设计用于用户模式或内核模式的性能监控和调试。从微软的官方描述中,你找不到任何关于“安全”的字眼,这本身就很有趣。

ETW 是 Windows 的内核级组件,设计目标是高速和可靠。从高层次看,其架构包含三个主要组件:

  • 事件提供程序:生成事件的源头。
  • 跟踪会话:也称为记录器会话,用于组织和缓冲事件流。
  • 事件消费者:接收并处理事件的应用程序。

这种架构在用户模式和内核模式下都适用。ETW 内核位于中间,充当会话控制器,协调消息的流转。


跟踪会话类型 📊

上一节我们介绍了 ETW 的基本架构,本节中我们来看看不同类型的跟踪会话。要监听提供程序,你需要启动一个跟踪会话。ETW 内核会实例化一个会话。主要有四种类型的跟踪会话:

以下是四种主要的跟踪会话类型:

  1. 自动记录器会话:在系统启动时自动启动,并将事件写入磁盘。
  2. 实时会话:实时流式传输遥测数据,数据会缓冲在一个临时文件中,供消费者实时处理。EDR 系统通常使用这种会话。
  3. 文件记录会话:将所有生成的事件写入一个文件。
  4. 私有会话:主要用于应用程序内部调试,其事件无法被外部程序消费。

当你启动一个跟踪会话(例如实时会话)时,ETW 内核会通知你订阅的提供程序开始向该会话发送事件。每个会话都有一个缓冲区池,用于暂存事件,直到消费者将其取走。这个缓冲区机制在后续讨论中非常重要。


常见的 ETW 规避技术 🛡️

当然,我不是第一个研究 ETW 的人。安全社区已经发现了多种规避技术。

以下是几种常见的 ETW 干扰或规避方法:

  • 修补函数:在程序中修补 ntdll!EtwEventWrite 等函数,阻止其发出事件。这常用于绕过反恶意软件扫描接口(AMSI),但不仅限于此。
  • 篡改文件:篡改写入磁盘的 .etl 日志文件。
  • 修改注册表:如果拥有足够权限,可以通过修改注册表来禁用某些会话。
  • 函数挂钩:向进程注入代码,挂钩特定函数以阻止某些事件发出。但这需要向所有目标进程进行注入,容易被 EDR 发现。
  • 内核驱动:如果能够加载恶意内核驱动程序,可以禁用整个跟踪会话,但这需要很高的权限。

对我来说,这些技术还不够有趣。


安全产品为何使用 ETW?🤔

上一节我们看到了攻击者如何干扰 ETW,本节中我们来看看防御方——安全产品为何如此依赖 ETW。这主要有几个原因。

以下是安全产品使用 ETW 的主要优势:

  • 稳定性:需要更少的内核代码,降低了因内核驱动错误导致系统不稳定的风险。
  • 过滤能力:可以在会话级别定义需要收集哪些事件及其属性,而基于内核回调则需要接收全部数据流后再在进程中过滤,性能开销更大。
  • 缓冲机制:ETW 的缓冲设计使得在进程繁忙时不易丢失事件。
  • 灵活性:可以动态启用或禁用新的提供程序来增强遥测收集,而使用内核驱动则可能需要重新加载驱动甚至重启系统。
  • 低侵入性:无需挂钩函数或向进程注入代码,进一步提升了稳定性。

此外,内核回调能收集的信息类型有限,很多时候仍需从其他来源获取数据。


EDR 对 ETW 的依赖实例 🔍

本课程中的示例主要基于 Microsoft Defender for Endpoint,因为我最熟悉它。但请放心,大多数其他 EDR 供应商也存在类似甚至相同的问题。

下图展示了 Defender for Endpoint 使用的内核回调(左侧)与 ETW 提供程序(右侧)的对比,可以看出其信息广度很大程度上依赖于 ETW。

CrowdStrike 等产品的情况也类似。虽然我不完全清楚它们的所有信息源,但机制通常是相同的,因为它们也必须从这些地方获取信息。


ETW 提供程序与事件上限 ⚖️

作为示例,我们深入看一下 Defender for Endpoint 所依赖的一个 ETW 提供程序。在配置中,有一些关键信息。

以下是配置中的关键部分:

  • 提供程序 GUID 和名称:在顶部,可以看到提供程序的唯一标识符(GUID)、名称和一些关键字。
  • 事件上限:许多云端 EDR 会对可上传到云端的事件数量设置上限,原因包括性能、存储成本和带宽考虑。
    • 全局上限:例如,在 24 小时内,每台机器只能记录 1000 个唯一事件。
    • 本地上限:例如,对于“LDAP 首次查询”事件,每个进程每 24 小时对完全相同的搜索查询只记录一次。如果重复 50 次,也只会产生一个事件。

这种上限机制在某些情况下可以接受,但也让我思考:如果存在多个这样的事件,我能否自己开始发送它们呢?


欺骗 ETW 事件的动机 🎯

这就是我想要尝试的。我这么做的动机有几个方面。

以下是研究此技术的主要动机:

  • 防御方验证:作为一名检测工程师,我希望能够通过发出 ETW 事件来模拟攻击,以验证我的检测规则是否仍然有效,而无需在机器上真正运行恶意代码。
  • 攻击方干扰:当然,也可用于攻击目的。例如,制造虚假警报分散分析师注意力,或者伪造从未发生的事件。
  • 淹没上限:由于大多数云端 EDR 存在事件上限,我可以尝试用我的进程发出大量事件,超过上限,从而使其他进程的真实事件无法被记录。

为了实现这些,我们需要理解提供程序的工作原理。


ETW 提供程序的工作原理 🔧

ETW 提供程序有一个 GUID。只要拥有适当的安全权限,机器上的任何进程都可以使用相同的 GUID 注册一个提供程序,这包括已经存在于机器上的提供程序。这听起来有点奇怪,但事实如此。

每个进程的注册是独立的。当你使用一个已存在的 GUID 调用 EventRegister 函数时,你会获得一个指向该现有 GUID 的句柄,然后你就可以开始发出事件了。对于操作系统来说,看起来就像只有一个提供程序在输出数据。

在提供程序类型方面,主要有三种:

  • 基于清单的提供程序:目前最常用的类型,在 Windows Vista 中引入。清单是 XML 文件,通常存储在 System32 目录下。
  • MOF 基于的提供程序:现在已不常见,主要来自 WMI 时代。
  • 跟踪日志提供程序:在 Windows 10 中引入,没有硬编码的清单,可以发出各种类型的事件,更多用于应用程序调试,而非安全日志记录。

可视化欺骗过程 🎨

那么,从逻辑上看会发生什么呢?任何进程都可以注册一个提供程序。在这个例子中,我注册了机器上已经存在的 TCP/IP 提供程序,它已经在向某些会话(比如 EDR 的会话)发送事件了。

由于它已经存在,ETW 内核会给我一个该提供程序的句柄。

利用这个句柄,我就可以开始发出事件了。

现在,我向 TCP 提供程序写入事件,而该提供程序已经连接到一个跟踪会话(例如实时会话),我的事件也会到达那里并被消费进程(如 EDR)接收。

这很有趣,对吧?基本上,只要你有权限(大多数情况下你都有),你就可以注册这些提供程序之一,并开始发出各种事件,它们会被当作真实进程产生的事件一样对待。

ETW 通常不记录是哪个进程发出了遥测数据。事件中会包含一个进程 ID,但那不一定是生成该事件的进程。例如,真实的网络连接事件可能来自 Windows 的某个子进程,而不是发起连接的用户进程。遗憾的是,这个 ID 无法被欺骗,因为它由 ETW 内核处理。否则,我就能让 EDR 以为自己在做坏事然后自杀,可惜没能实现。


内核模式与安全模型 🔐

在内核模式下,工作原理类似。但更大的缺点是,你需要一个经过签名的驱动程序才能实现同样的事情。不过,你仍然可以注册提供程序并进行事件发送。

ETW 有一个源自 WMI 的安全模型,并做了一些小补充。大多数 ETW 提供程序在注册表中存储了一个安全描述符。如果没有,则会获得一组默认权限。

安全描述符主要控制哪些主体可以将提供程序添加到跟踪会话、创建跟踪会话等。默认的安全权限是,Everyone 组对“启用提供程序”的权限非常有限,但也没有关于“发出事件”的明确限制。有趣的是,如果你安装了 Visual Studio 等开发工具,会自动被添加到“Performance Log Users”组,这会显著增加你的权限。


枚举提供程序与权限测试 🧪

我曾有兴趣找出我关心的所有提供程序的权限情况,于是编写了一个小工具来枚举它们。你可以看到,有些提供程序在注册表中注册了安全描述符(SD),有些则没有。

例如,对于“Microsoft Antimalware Service”提供程序,所有组都有相当多的权限。而对于“Microsoft-Windows-Windows Defender”AV 组件提供程序,则没有注册特定的安全权限,因此任何人都可以执行操作系统允许的基本操作。

我收集了 Defender for Endpoint 依赖的所有提供程序,并开始枚举。我写了一个简单的工具,尝试注册每个提供程序,获取句柄,写入一个事件,然后查看输出。

看起来我拥有大量权限,很多都返回了成功。但深入研究后,我发现了一些误报。你可以从用户空间注册许多实际上是内核模式的提供程序的 GUID 并发送事件,但这不一定是真的有效。同样,跟踪会话的处理方式也略有不同。从用户模式无法欺骗任何内核模式事件,这至少说明两者是隔离和受保护的。


概念验证与事件上限测试 🧪

我选择 LDAP 客户端作为测试对象。我用 Go 语言编写了一个基本的 PoC,基于现有的开源包(主要是用于消费事件的)。我找到了一个允许注册提供程序和发出事件的包,并写了一个简单的程序。

在左侧,你可以看到它以一种特定模式运行。在右侧,我启动了一个小型跟踪会话,可以看到事件流过。

我很高兴,但查看 Defender for Endpoint 时,却没有收到任何遥测数据。经过长时间调试和解码真实的 LDAP 搜索事件后,我发现字节序(Endianness)在 Windows 中非常重要,而且很多包不允许我控制正确的头部信息(如关键字)。于是我采用了新方法,直接进行系统调用,用新的 PoC 发出事件。这次,事件成功出现在云端 Defender for Endpoint 中。


测试事件上限 🧪

现在,我觉得这很有趣。我能用它做什么呢?我再次查看了那些上限。我发现,发出一个事件后,就没事了。我们之前提到过全局上限。我运行我的工具,将其重命名为 canary.exe,再次运行,发出相同的事件。

结果两个事件都出现在了云端!这证明了“首次查询”事件的理论:如果进程不同,就会被视为不同事件。

然后,我生成了 10 个垃圾事件(随机创建搜索过滤器),这 10 个也都出现在了云端,这仍然符合预期。接着,我想测试那个全局上限(1000 个事件)。我发出了略多于 1000 个事件,过了一段时间(需要时间摄取),在云端只看到了 1000 条记录。这很有效!我找到了一种可靠地超过上限的方法。

但这都是来自同一个进程。为了确保,我用真实的 canary.exe 发出了一个稍有不同的搜索查询,所有内容都不同,以确保它仍按预期工作。但我再也没有收到日志。这证明了我的理论:我可以超过事件数量上限,从而永远看不到真实数据。

因此,我可以强制 Defender for Endpoint 对每种事件类型进入全局上限模式。当然,你需要对你关心的每个提供程序都这样做,但这仍然有用。然后,你可以运行真正的攻击而不会被检测到。只要杀毒软件没有因为某种原因识别出你的二进制文件,这确实可靠有效。


其他攻击场景与应用 🎭

我还在一个 DLL 中测试了这一点,将其注入并查看目标跟踪会话,仍然能看到事件发出。你也可以用相同的事件进行淹没,这些信息仍然会进入 Defender for Endpoint。

根据条件访问策略在组织中的实施方式,还可以做其他事情。如果用户达到特定风险级别,可能会被策略阻止访问资源。作为攻击者,我可以为该用户生成警报,提高其风险级别,导致他无法再访问某些资源。这可以作为红队干扰蓝队的一种方式。同样,对于设备,如果基于 Intune 的设备有合规性检查,生成过多警报可能导致设备被标记为不合规并被阻止访问。


反恶意软件提供程序测试 🦠

另一个我感兴趣的提供程序是“反恶意软件服务提供程序”,因为它是 Defender for Endpoint 反病毒和恶意软件检测引擎的固有提供程序。我写了另一个工具,发出一堆随机的恶意软件事件,使用真实的名称和检测 ID,但对应系统中不存在的虚假文件。同样,由于配置的上限,只有 1000 个事件被记录。

这意味着,如果我发出 1000 个事件,然后投放真正的恶意软件(即使可能被检测到),也不会再被分析师看到。攻击者甚至可以伪装成勒索软件操作者,在机器上伪造大量勒索软件检测警报,分散分析师对真正受攻击机器的调查注意力。你还可以伪造各种 AV 检测、缓解事件等,它们甚至会出现在普通事件日志中。


向微软报告与“修复” 📨

我认为这很严重,于是给微软写了一封信。我报告了这个问题,附上了 PoC 工具和一份我能滥用的 ETW 提供程序列表。几周后,他们回复很快,但认为这不重要,不是需要立即修复的障碍,因此案例关闭了。

或许并没有。几周前,我想为演示准备一些录制内容。我尝试发出各种勒索软件事件,但它们不再可见了。事件仍然出现在我的日志中,但警报再也没有出现。这让我感到惊讶,但也很高兴,以为他们修复了。

但深入研究后,我发现我仍然可以生成各种其他警报,模拟 SharpHound 扫描或各种 AD Explorer 克隆工具等。基本上除了“反恶意软件”提供程序外,其他都还能触发警报。他们甚至为我的二进制文件中的一些字符串构建了签名,我不得不通过混淆字符串来绕过安全检测。

在将演示文稿提交给会议方后,他们回复说也在构建修复程序,将于 8 月 7 日(第二天)可用。这个时间点很巧合。他们后来解释说,重点是加固 Defender 产品的提供程序,防止非特权用户滥用。我很好奇,于是在一台 Windows Insider 机器上测试,发现针对 Windows Defender 和 MC 提供程序仍然成功,但针对“反恶意软件”提供程序(即我 PoC 中的那个)不再工作了。他们确实修复了这一点,但只修复了这一个问题。我报告了超过 100 个项目,他们只迈出了一小步。他们表示鼓励 Windows 生态中的其他提供程序也开始采取措施,但攻击者通常已具备代码执行能力,所以这并非完全修复。


缓冲区淹没攻击 💥

后来,我也开始研究之前提到的缓冲区。每个 ETW 提供程序都有一个缓冲区池,可以由实例化跟踪会话的人配置大小和数量。这些缓冲区被分配在非分页内核内存中。

从逻辑上讲,缓冲区池会被提供程序发出的事件逐渐填充。当池满时,如果消费者还没有取走数据,ETW 内核会告诉提供程序“内存不足”,并停止接收。关键是,这会影响到该提供程序连接的所有会话

这意味着,如果我用自己的会话淹没 TCP 提供程序,导致其缓冲区满,那么 TCP 提供程序也将无法向 EDR 的会话发送事件。这很可怕,但这是设计如此。

我写了一个简单的工具来尽可能快地发出大量事件,并为一个测试提供程序启动了一个真实的跟踪会话(但忘了连接消费者)。你可以看到,左侧的 LDAP 客户端 ETW 提供程序出现了大量失败,右侧则显示所有事件都在底部丢失了。

右侧显示的工具 etwtop 是我将在演讲后发布的,用于监控这类情况。我发布的主要工具是 bambu_edr,它可以用来做我前面提到的所有事情:发出事件、针对许多 EDR 触发上限、模拟真实攻击工具(如 SharpHound)以测试检测规则,以及启动跟踪会话但不连接消费者,从而淹没缓冲区并使依赖这些提供程序的进程“失明”。


防御者与攻击者的视角 ⚖️

接近尾声了。防御者能做什么?我们至少可以用它来测试我们的自定义检测规则。我们可以尝试基于日志峰值构建检测,但可能很复杂。我们可以尝试修改安全描述符来阻止此类事情发生,但这可能很棘手,因为你不知道会破坏什么。本质上,我们只能希望微软最终能意识到需要在这方面做更多工作。

对于攻击者来说,这实际上更有趣。我们可以为一个提供程序发出足够多的事件,使其在至少 24 小时内因全局上限而“失明”。我们还可以注册一个跟踪会话并淹没缓冲区,这将使其在机器重启前一直“失明”。我们仍然可以伪造事件,分散分析师注意力。如果条件访问策略允许,我们甚至可以将用户或设备踢出网络。此外,跟踪会话在机器上也有数量限制(通常是 64 个),因此你也可以通过注册大量会话来阻止 EDR 添加新的会话。


总结与思考 🤔

现在,核心问题是:你不能再完全信任你的日志了。我与 ETW 专家确认过,情况确实如此。我们陷入了一个有点奇怪的境地:我们想

内核强制的 DNS 数据外泄安全 🔐

在本课程中,我们将学习如何利用 Linux 内核和 eBPF 技术来主动检测和阻断基于 DNS 的命令与控制攻击,保护云环境中的端点安全。

概述:为什么 DNS 是关键的 C2 后门

大多数高级持续性威胁在利用云环境时,更倾向于将 DNS 作为其通信通道。DNS 协议是互联网的基础和骨干,但作为命令与控制的隐蔽通信通道时,它变得极具破坏性。它默认不加密,防火墙日志很少被监控,并且由于其基于 UDP 的无状态特性,攻击者可以轻松地从投掷基础设施进行控制。

攻击向量与 C2 基础设施

以下是三种主要的 DNS 攻击向量:

  1. DNS C2:最具破坏性。攻击者将命令嵌入 DNS 子域名中,主要目的是持久性和高级驻留。
  2. DNS 隧道:通过 DNS 隧道传输被防火墙阻止的协议。
  3. 原始数据外泄:最简单的形式,通常是一次性的大量数据外泄。

攻击者不会只注册单个域名。他们会部署服务器舰队以实现最大化的规避。域名生成算法IP 地址突变 相结合,使得静态黑名单难以应对。

现有方法的挑战

现有的方法主要分为两类:

  • 半被动分析:较少使用,通常通过可编程软件交换机进行深度包检测。
  • 被动分析:主流方法,依赖于异常检测、流量威胁签名和域名信誉。

这些方法面临的主要挑战是检测和响应速度慢,难以跟上不断演变的 C2 植入程序的规避手段。它们本质上是主动的,而非反应性的。

内核强制的端点安全解决方案

上一节我们讨论了现有方法的局限性,本节中我们来看看我们提出的解决方案:一种反应性的、基于内核的端点安全方法。

核心思想是:与其在网络层面被动地追捕 C2 活动,不如让端点引擎在内核层面主动追捕正在发生的事件。这确保了无论恶意软件在用户空间如何隐藏,都无法逃避检测。

eBPF:内核可编程性的关键

eBPF 是一种安全地重新编程 Linux 内核的现代方式。可以将其视为运行在内核中的虚拟机,允许你注入运行时程序并将其附加到内核子系统。

// eBPF 程序示例结构(概念性)
SEC("kprobe/tcp_connect")
int handle_tcp_connect(struct pt_regs *ctx) {
    // 在内核中执行安全检查逻辑
    bpf_printk("TCP connect event detected!\\n");
    return 0;
}

eBPF 程序通过验证器确保安全,并可以附加到网络栈、LSM 等关键子系统。它们通过 eBPF 映射环形缓冲区 与用户空间代理通信,传递威胁情报。

系统架构与工作流程

我们的解决方案是一个多层安全代理:

  1. 用户空间:包含 eBPF 代理加载器、信誉域名缓存、用于数据混淆检测的量化深度学习模型以及指标导出器。
  2. 内核空间:由代理注入的多个 eBPF 程序,分别负责进程追踪、网络包深度检测等。

以下是其工作流程:

  • 当受感染的 C2 植入程序发送恶意 DNS 数据包时,数据包首先到达内核的流量控制层。
  • eBPF 程序会追踪与此数据包关联的进程及其父进程。
  • 在网络栈中,程序检查进程是否在黑名单中。如果不是,则对数据包进行深度检测。
  • 检测可能涉及将数据包重定向克隆到用户空间代理进行更复杂的分析(如模型推理)。
  • 如果用户空间代理判定为恶意,它会更新内核 eBPF 映射,将相关进程加入黑名单。
  • 此后,内核会丢弃该进程的后续数据包,打乱其心跳模式,同时继续收集其行为遥测数据。
  • 最终,代理根据收集到的足够行为分析,终止恶意进程。

两种运行模式

  1. 主动进程安全执行模式:适用于可容忍一定延迟但不能接受任何命令执行的端点。它通过重定向数据包进行实时深度检测。
  2. 被动深度包检测与行为分析模式:适用于不能接受重定向带来延迟的场景(如 TCP)。它通过克隆数据包在用户空间进行分析和跟踪,积累足够证据后在内核层面实施拦截。

检测模型

检测的核心是一个经过量化的深度学习模型,用于识别 DNS 查询中的恶意模式。

模型输入特征包括:

  • 内核特征:查询长度、标签数量、标签长度等(基于 DNS 协议规范的限制)。
  • 用户空间特征:查询模式、词汇特征、熵值(用于测量子域名字符串的随机性)。

该模型使用约 6000 万个合成域名数据集进行训练,这些数据模拟了正常和恶意流量。模型被转换为 ONNX 格式以实现高效推理,其架构是一个用于二分类的密集神经网络。

云环境部署架构

为了在云环境中大规模对抗 C2 基础设施,我们需要一个协同的防御体系。

部署架构包含以下组件:

  • 数据平面:每个端点(如虚拟机、容器)都运行着 eBPF 安全代理。
  • 控制平面:由控制器节点组成,消费来自各代理的遥测数据流。
  • 消息总线:用于传输遥测数据和命令(如 Kafka)。
  • DNS 基础设施:本地权威 DNS 服务器、解析器等。

工作流程如下:

  1. 某个端点被感染并发送恶意 DNS 查询。
  2. 该端点的 eBPF 代理检测并阻断攻击,同时将攻击详情(如恶意域名)发送到消息总线。
  3. 控制器节点消费这些信息,动态地在全网 DNS 层(如通过响应策略区)黑名单该域名。
  4. 控制器还可能进行反向溯源分析,了解 C2 重定向器网络。
  5. 更新后的黑名单和防护策略通过消息总线下发到所有数据平面的 eBPF 代理,实现全网同步防护。

这种架构提供了双重防御层:即使某个端点操作系统不支持 eBPF,受保护的 DNS 基础设施也能作为一道防线。

演示与效果

通过演示可以看到,当启动 C2 植入程序(如 Sliver)并执行远程命令、端口转发时,会产生大量 DNS 流量。一旦启动 eBPF 安全代理,代理会立即注入程序并开始检测。恶意进程的 DNS 查询开始出现错误并被丢弃,其行为遥测(如进程ID、存活时间、外泄尝试次数)被实时导出到仪表板。最终,代理收集到足够证据后终止了恶意进程。整个响应时间在微秒级,模型精度高达约 99.89%。

未来方向

  1. TLS 指纹识别:将 eBPF 附着于内核 TLS/加密隧道组件,实现进程关联的 TLS 流量分析。
  2. 持续模型进化:采用持续学习机制,使模型能适应新的数据混淆技术。
  3. 行为分析增强:利用 LSTM 等模型对内核收集的进程行为序列进行更深入的分析。
  4. DDoS 防护:利用 eBPF 在网络驱动层的支持,实现内生的 DDoS 攻击防护能力。

关键要点与总结

本节课中我们一起学习了如何利用 eBPF 和 AI 增强端点安全。

  • eBPF 成熟了 EDR:它允许重新编程内核,获取更深层的系统遥测数据。
  • AI 与 eBPF 的结合:使得 EDR 代理能够基于丰富的行为指标实施动态的内核级强制策略,更具弹性。
  • 自底向上的全面防护:通过加固操作系统内核(eBPF EDR)→ 提升安全信息和事件管理系统的质量 → 实现智能的云防火墙(动态 L3/L7 过滤),从而构建一个能够抵御大规模、多变 C2 基础设施的弹性云网络。

即使未来 DNS 普遍加密,这种基于内核深度遥测和行为分析的方法,仍然是应对加密隧道攻击的有效途径。

感谢你的关注。

利用微架构竞态条件从任意英特尔系统泄露特权内存 [ULXuhxj-WgA] 🔓

概述

在本节课中,我们将学习一种名为“推测执行”的漏洞利用范式。我们将深入探讨一个具体的攻击案例,该攻击利用英特尔处理器微架构中的一个竞态条件,绕过名为“增强型间接分支限制推测”的安全缓解措施,从而能够从高特权域(如操作系统内核)中泄露任意内存信息。


背景故事:幽灵漏洞的诞生

上一节我们提到了推测执行漏洞的威胁。本节中,我们来看看这一切是如何开始的。

2017年,英特尔召开了一次紧急会议,召集了全球行业内的专家。会议主题是一种新型的漏洞类别,它能够突破各种安全边界,包括执行环境、操作系统内核与用户空间之间,乃至云环境中的客户机与宿主机之间的边界。这个漏洞就是幽灵

幽灵漏洞存在于处理器的微架构中。微架构是CPU核心的一部分,包含分支目标预测器缓存等关键组件。程序执行时,其行为会反馈到这些微架构结构中。例如,分支指令的目标地址会被缓存到分支目标预测器中,以便后续快速预测。

问题在于,这些微架构结构在不同程序、甚至不同特权域之间是共享的。对于缓存,通常使用物理地址进行标记,可以避免冲突。但对于分支目标预测,它使用虚拟地址进行寻址,这就导致了不同虚拟地址空间之间可能出现别名冲突

以下是幽灵漏洞的基本攻击流程:

  1. 注入预测:攻击者程序训练分支预测器,使其记住一个特定的目标地址。
  2. 准备缓存:攻击者将缓存置于一个已知状态(例如,清空特定缓存行)。
  3. 切换到受害者域:通过系统调用等方式,进入高特权域(如内核)执行。
  4. 触发误预测:如果受害者域执行了一个分支指令,且其虚拟地址与攻击者训练时使用的地址发生冲突,CPU可能会错误地使用攻击者注入的预测。
  5. 执行披露小工具:在短暂的推测执行窗口中,被劫持的控制流会执行一段“披露小工具”代码。这段代码通常形如:
    mov rax, [rsi]      ; 读取一个秘密值到寄存器rax
    mov rbx, [rdi + rax] ; 以该秘密值为偏移量访问内存
    
    第二个内存访问是秘密值相关的,它会根据秘密值不同,触及不同的缓存行。
  6. 传输信息:攻击者返回自己的上下文后,通过测量缓存命中/未命中的时间,就能推断出受害者访问了哪个缓存行,从而泄露秘密信息。

英特尔的缓解措施:EIBRS

上一节我们看到了幽灵漏洞的原理。本节中,我们来看看英特尔提出的解决方案。

英特尔最初的缓解方案称为“间接分支限制推测”,但效果不佳。最终的长期解决方案是增强型间接分支限制推测

EIBRS 可以看作一个开关。通过向一个特定的模型特定寄存器写入,可以启用它。一旦启用,它会在分支预测条目中额外记录一个预测模式信息,用于标识该预测是属于虚拟机监控程序、内核还是用户空间。

这样,当从用户空间切换到内核执行分支时,由于预测模式不匹配,CPU 将不会使用来自用户空间的预测,从而理论上阻止了攻击。


发现问题:竞态条件

上一节我们介绍了EIBRS的理论防护。本节中,我们通过实验来检验它是否真的有效。

我们设计了一个实验:

  1. 在用户空间训练分支预测器。
  2. 准备缓存。
  3. 通过系统调用切换到内核模块。
  4. 在内核中触发分支,尝试造成误预测并泄露信息。

当EIBRS启用时,实验失败,这似乎是好消息。但当我们尝试在更新的处理器上,偶尔(百万分之一)会观察到微弱的泄露信号。更奇怪的是,即使启用了EIBRS,这个信号依然存在。

为了探究原因,我们进行了大量实验。一个关键发现是:将缓存准备步骤移到内核空间执行后,泄露信号变得非常强。这不合逻辑,因为缓存操作本应与分支预测无关。

进一步的测试表明,系统调用本身与分支预测注入的成功与否密切相关。如果在训练分支后立即执行系统调用,注入就有效;如果在两者之间加入足够长的延迟,注入就会失效。


根本原因:延迟更新与特权切换

上一节我们发现了系统调用的关键作用。本节中,我们提出一个可能的硬件层面的解释。

我们认为,在英特尔处理器上,分支预测的更新不是瞬间完成的。执行分支指令后,预测信息的收集、存储到预测器数据结构中这一过程可能存在一个延迟队列

我们的假设是:

  1. 攻击者在用户空间执行分支指令,一个预测更新被放入这个延迟队列。
  2. 在预测信息被正式写入预测器之前,攻击者执行了系统调用,导致CPU特权级从用户态切换到内核态。
  3. 当延迟队列中的预测条目最终被写入分支目标预测器时,它错误地携带了当前(内核态)的特权模式,而不是分支执行时(用户态)的模式。
  4. 这样,一个来自用户空间的预测就被“注入”到了内核的预测器中,绕过了EIBRS的预测模式检查。

这本质上是一个微架构竞态条件:在预测更新完成前切换特权域。


攻击构建:从理论到实践

上一节我们理解了漏洞原理。本节中,我们来看看如何构建一个完整的攻击。

我们的目标是让一个用户空间程序攻击操作系统内核,并泄露受保护文件 /etc/shadow 的内容。攻击需要:

  • 本地代码执行能力(例如,通过浏览器漏洞、共享CI runner等)。
  • 知道目标内核镜像(在标准系统上通常可以获取)。

攻击在内核中的工作流程如下:

  1. 找到一个间接分支指令(如 call [rax])。
  2. 找到一个披露小工具(能执行 mov rax, [rsi]; mov rbx, [rdi + rax] 这类模式的代码片段)。
  3. 利用内核地址空间布局随机化找到这些代码在内存中的实际地址。
  4. 找到要泄露的秘密(/etc/shadow)在内存中的位置。
  5. 找到一段攻击者和内核都能访问的共享内存,用于通过缓存侧信道传输信息。

我们利用发现的漏洞构建了一个工具,它能将分支预测注入内核,并让内核在推测执行中为我们运行任意代码。我们将这个工具当作“锤子”,把其他复杂问题(如地址发现)都变成“钉子”来敲打。

以下是简化的攻击步骤:

  1. 定位内核代码:通过分支预测器碰撞,探测内核代码的可能位置。
  2. 定位共享内存:同样使用推测执行工具,探测并确认共享内存区域。
  3. 定位秘密/etc/shadow 文件开头有已知字符串(如 root:$)。我们可以在可能的内存页中搜索这些字符。
  4. 泄露数据:一旦找到所有必要组件,就使用我们的工具触发完整的泄露链,逐字节地将 /etc/shadow 内容通过缓存侧信道传输出来。

我们在一个搭载第13代英特尔酷睿处理器、运行最新Ubuntu LTS且启用了所有缓解措施的系统上进行了演示,并成功泄露了 /etc/shadow 文件的开头部分。


影响与结论

本节课中,我们一起学习了一种利用微架构竞态条件的新型攻击。

主要结论如下:

  1. 漏洞核心:我们发现了英特尔处理器分支预测器更新机制中的一个竞态条件。通过在分支训练后立即执行特权切换(如系统调用),攻击者可以绕过关键的硬件安全缓解措施EIBRS
  2. 广泛影响:此漏洞影响了自第一代包含EIBRS缓解措施的英特尔CPU以来的大量处理器,甚至包括一些尚未发布的型号。它不仅破坏了EIBRS,也破坏了另一个重要的隔离机制间接分支预测屏障
  3. 攻击扩展性:利用此漏洞,我们演示了从用户空间攻击操作系统内核的能力。理论上,该技术也可用于虚拟机逃逸,攻击宿主机。
  4. 缓解措施:英特尔已通过微码更新提供了修复。然而,由于微码是加密的“黑盒”,其完整性和有效性难以独立验证。
  5. 更广泛的启示:推测执行漏洞的攻防是一场持续的“猫鼠游戏”。硬件厂商提供的黑盒缓解措施本身也可能包含软件中常见的漏洞类型,如类型混淆、竞态条件和未初始化结构,因此需要持续地评估和审视。

这项研究表明,在追求高性能的微架构设计中,安全边界依然面临严峻挑战,需要研究人员、厂商和开发者持续保持警惕。


论文与代码:关于本研究的更多细节、完整论文以及攻击代码,请访问我们的项目网站。

利用LLM识别信息窃取器感染途径并提取IoC 🕵️‍♂️

在本节课中,我们将学习如何利用大型语言模型(LLM)分析信息窃取器(Info Stealer)感染后留下的截图,从而自动化地识别感染途径、提取攻击指标(IoC)并追踪恶意活动。

概述

信息窃取器是一种恶意软件,它感染用户计算机后,会窃取各种凭证、密码、加密货币钱包等信息。攻击者通常会将窃取的数据打包,通过Telegram等渠道进行售卖。有趣的是,许多窃取器在运行时会自动截取受害者屏幕的截图。这些截图就像“犯罪现场的自拍”,包含了大量关于感染源(如诱饵软件、下载链接)的线索。我们将构建一个基于LLM的自动化分析管道,从海量截图中高效提取这些关键信息。

信息窃取器现象

信息窃取器恶意软件是一种常见的威胁。其感染流程通常如下:用户下载并执行了恶意软件(通常是伪装成破解软件或其他诱饵),该恶意软件随后在受害者计算机上运行。它之所以被称为“信息窃取器”,是因为它会窃取计算机上所有可访问的信息,包括凭证、加密货币钱包、密码管理器数据、系统信息、剪贴板内容等。这些数据随后被打包并上传到攻击者的命令与控制(C2)基础设施,最常见的是通过Telegram。

这些感染产生的数据(或称“日志”)会被打包,并由网络犯罪分子在Telegram上再次转售。因此,这里存在两级Telegram活动:一级是窃取器上传数据,另一级是犯罪分子转售这些数据日志。

为什么关注截图?📸

攻击者在恶意软件中加入了截图功能,可能是为了检测沙箱环境(因为沙箱环境很容易通过截图识别),或者为了获取更多受害者上下文信息。然而,对我们防御方而言,这些截图就像是攻击者留下的“犯罪现场自拍”,包含了大量可用于追溯感染源的信息。

例如,一张截图可能显示一个关于“破解《堡垒之夜》软件”的YouTube视频页面,其中包含下载链接和解压密码。另一张截图可能显示一个包含Office套件破解版下载链接的MEGA网盘页面。这些视觉线索正是我们理解感染故事所需的关键。

我们通过渗透相关Telegram群组和网络犯罪团体,收集了超过1100万张截图,涉及11个不同的恶意软件家族。手动分析如此大量的截图是不现实的,因此我们转向利用AI和LLM技术来解决这个问题。

LLM分析管道设计 🤖

我们设计了一个两层的LLM分析管道来处理截图。

以下是该管道的核心流程:

  1. 第一层LLM(视觉评估层):接收原始截图,输出结构化的文字描述。
  2. 第二层LLM(推理分析层):接收第一层的描述,识别具体的感染途径(如“通过YouTube视频下载破解软件”)和攻击主题(如“《堡垒之夜》作弊工具”)。
  3. IoC检查管道:对提取出的潜在攻击指标(如下载链接)进行有效性检查,区分存活链接、已失效链接以及仅包含攻击主题的条目。

你可能会问,为什么需要两层LLM?这是一个很好的问题。接下来我们将解释背后的原因。

为何需要两层LLM?

最初,我们尝试使用单层LLM,直接让其“识别感染途径”。但这并没有成功。原因在于,人类分析师在分析截图时,实际上无意识地执行了两个独立的任务。

以一张截图为例:人类首先会视觉评估整体情况(“这是一个关于《堡垒之夜》的YouTube视频,涉及下载”)。然后,基于领域知识,进行推理分析,指出具体的感染载体(“用户下载了视频描述中的FortniteHack.zip文件,这很可能是感染途径”)。

对于单层LLM,我们要求它在一个步骤中完成这两个任务,这超出了其能力范围。LLM无法像人类一样“自己领悟”,我们必须将分析师的直觉分解成明确的指令。因此,我们最终设计了两层结构:第一层专门负责客观描述截图内容,第二层则基于描述进行安全分析推理。

第一层LLM:提示工程与视觉评估

我们首先对大量截图进行了人工分析,发现它们大致可分为三类:纯网页内容、纯文件系统界面以及两者混合的界面。

针对不同类型的截图,我们为第一层LLM设计了不同的提取要求:

  • 对于网页内容:要求提供页面的一般描述、可见的链接以及浏览器标签页信息。
  • 对于文件系统内容:要求提供描述、文件资源管理器中的文件名,如果正在安装软件,还需指出安装的程序。
  • 对于混合内容:要求提取以上所有信息。

此外,为了给第二层分析提供线索,我们还要求第一层LLM指出任何看起来可疑的元素,例如提及“破解”(crack)的YouTube视频、分享链接等。

最终的第一层提示词结构如下:

主要描述:[描述截图主要内容]
文件和程序:[列出文件和安装的程序]
链接:[提取所有可见链接]
浏览器标签页:[识别所有标签页]
可疑元素:[指出任何可疑内容,如提及破解、要求禁用杀毒软件等]

我们将一张截图输入第一层LLM,它成功输出了格式化的描述,识别了Eset安全警告窗口、YouTube视频、相关文件,并将YouTube视频和许可证密钥输入提示标记为可疑元素。这为第二层分析提供了良好的输入。

第一层性能评估与优化

在将第一层输出送入第二层之前,我们必须评估其准确性,因为第二层的输入质量直接决定最终结果。

我们在1000张截图上评估了第一层LLM的性能:

  • 场景描述:正确率96%。
  • 文件资源管理器识别:正确率100%。
  • 链接提取:正确率100%。
  • 可疑元素识别:正确率95%。
  • 浏览器标签页识别:非常不一致,仅30%完全正确,32%信息缺失,36%完全错误。

例如,在一张失败的案例中,LLM没有正确识别所有标签页,反而错误地列出了书签栏的内容。由于标签页识别的不稳定性且对后续分析影响不大,我们决定从提示词中移除这项要求。移除后,整体管道准确率并未下降,从而简化了流程。

第二层LLM:识别感染途径与主题

第二层LLM的职责是基于第一层的格式化描述,识别具体的感染途径(Vector)和攻击主题(Theme),并将结果格式化以便后续利用。

其输出格式类似:

感染途径:文件分享平台(MEGA)
攻击主题:Microsoft Office 2019 破解版

至此,我们成功构建了一个能够自动从截图描述中提取关键安全信息的LLM层。

IoC检查与分类管道 🎯

运行整个管道后,我们发现提取出的许多IoC(如下载链接)已经失效。这对于威胁情报而言价值不大,因为我们需要的是当前活跃的威胁。

因此,我们引入了IoC检查管道,旨在区分三类结果:

  1. 存活IoC:链接当前有效,可以下载或访问。
  2. 失效IoC:链接已失效(如文件被删除、视频下架)。
  3. 主题IoC:链接本身可能失效,但其中包含的攻击主题(如“Adobe Photoshop 破解”)仍然具有跟踪价值。

我们针对不同类型的IoC(主要是URL)采用了不同的启发式方法进行检查:

  • 文件分享平台(如MEGA):这些平台有清晰的错误信息和HTTP状态码,易于判断文件存活与否。即使文件需要密码(密码常在视频描述中),只要平台链接有效,我们仍视其为“存活”,因为用户最终可能通过输入密码完成下载。
  • YouTube视频:通过视频是否“不可用”来简单判断。如果视频存活且描述中包含下载链接,则提取该链接作为存活IoC。如果视频存活但下载链接已被移除,则将其归类为“主题IoC”,用于跟踪攻击活动趋势。
  • 其他网站:我们主要寻找下载按钮等指示器。如果能确认可以触发下载,则视为存活。

追踪攻击主题非常重要,它允许我们监控特定诱饵(如“Office破解”)的活动规模,并向公众发出预警,从而改变潜在受害者的行为,降低感染风险。

系统演示与输出

我们的系统能够自动处理截图。在演示中,系统分析了一张显示ZIP文件(名为“Office 2019 Crack”)的截图。第一层LLM正确识别了内容并提取了URL。第二层LLM判定感染途径为“Microsoft Office破解软件”。系统会持续循环处理截图。

最终输出为结构化的JSON文件,包含恶意软件家族、提取的URL、爬取的关联链接等信息。这构成了我们自动化分析的基础。

信息窃取器“攻击手册”分析

让管道运行数周并分析数万张截图后,我们得以洞察攻击者最常用的感染策略,即他们的“攻击手册”。

我们主要发现了两大类诱饵主题:

  1. 破解软件:针对主流或创意软件,如Adobe套件、Vegas Pro、Midjourney、Figma等。这些软件价格昂贵,用户有强烈的“免费获取”动机。攻击者利用用户想绕过正版许可费用的心理,用破解版作为诱饵。选择主流软件能确保最大的潜在受害者池。
  2. 游戏作弊与模组:针对《堡垒之夜》、《无畏契约》(Valorant)、《我的世界》等主流游戏。这些游戏受众广泛,尤其是年轻玩家。游戏内的皮肤、武器等虚拟物品通常需要付费,而年轻玩家可能缺乏支付意愿或能力。攻击者利用他们“免费获取”稀有物品的渴望进行钓鱼。

在分发策略上,攻击者主要利用两大平台:

  1. YouTube作为分发系统:攻击者上传教程式视频,标题常包含“100%有效”、“安全”、“免费”等字眼,并在描述中提供下载链接和密码。视频内容会指导用户“禁用杀毒软件”。YouTube的广泛覆盖和教程式内容使其成为完美的恶意软件分发启动台。
  2. 谷歌广告赞助恶意网站:攻击者创建知名软件官网的高仿钓鱼网站,并通过购买谷歌广告,让这些网站在用户搜索相关软件时出现在结果顶部。用户出于对谷歌排名和品牌官网的信任,极易点击这些恶意链接。

实战案例分析

通过分析IoC和主题的重复出现频率,我们追踪到了一些非常成功的攻击活动。这里介绍两个典型案例,它们占我们分析感染的5%以上。

案例一:Midjourney钓鱼活动

  1. 用户搜索“Midjourney”。
  2. 搜索结果顶部出现赞助广告(恶意仿冒站),下方才是真正的官网。
  3. 用户点击广告,进入一个制作精良的仿冒网站。网站已预先植入心理暗示:“计算机安全系统可能会错误触发警报”,为后续要求用户禁用杀软做铺垫。
  4. 用户下载并运行恶意可执行文件。当安装失败时,用户回想起网站的“警告”,认为是杀软阻止,从而主动禁用安全软件,最终导致感染。

案例二:Blitz Java活动

  1. 攻击者针对Java软件创建了多个不同语言版本的高仿钓鱼网站。
  2. 通过谷歌广告将其推至搜索结果顶部。
  3. 用户下载得到一个存档文件,内含恶意安装程序。该安装程序图标与正版略有不同,但普通用户难以察觉。
  4. 安装失败后,用户上网搜索解决方案,进一步陷入困境。
  5. 该活动的高明之处在于,其广告集中投放于某个周末的19小时内。周末人们有更多休闲上网时间,而企业安全团队响应速度较慢,从而最大化感染窗口。

这两个案例都运用了简单的策略:瞄准主流软件/官网、制作高仿副本、利用谷歌广告或YouTube视频进行分发。关键在于,攻击者依然严重依赖简单的心理战术,因为这对操纵用户非常有效。

方法的优势与局限

我们构建的系统有其独特的优势和不可避免的局限性。

优势:

  • 对抗代码变更的鲁棒性:传统恶意代码分析依赖特征码,容易被加壳、混淆等技术绕过。而我们的方法分析的是感染后的截图,无论恶意软件代码如何变化,只要它还在截图,我们就能追踪其感染活动。这适用于不同家族的窃取器。
  • 成本可控:处理一张截图大约需要5-10秒,综合成本约为0.3美分/张。随着云服务和模型进步,成本和效率有望进一步优化。

局限:

  • 依赖截图存在:如果攻击者意识到截图功能暴露了其攻击途径并移除此功能,我们的方法将失效。
  • 依赖截图质量:如果截图内容模糊、无关紧要(如只显示桌面),我们将无法提取有效信息。分析质量受原始截图质量限制。

结论与未来展望 🚀

信息窃取器仍然是当前非常活跃的威胁。只要攻击者继续在日志中包含截图,我们就能利用所述方法大规模追踪攻击活动和主题。

关键收获:

  1. 安全意识至关重要:组织应教育用户(包括IT人员)认识到使用破解软件的极高风险,以及“禁用杀毒软件”这一行为本身就是强烈的危险信号。
  2. LLM应用于网络安全:我们将LLM应用于一种特定的网络安全数据(截图)。安全从业者可以将这种思路应用于自己关心的其他安全数据源,关键在于将分析师的直觉编码成具体、明确的指令

未来工作:
我们目前专注于截图分析。下一步,我们计划将LLM应用于窃取器日志中的所有其他数据,如已安装软件列表、进程信息、浏览历史、系统信息等。我们对每种数据应用不同的分析思路,然后综合所有结果,让LLM回答“受害者是如何被入侵的?”这一问题。我们将这个项目称为 “SherLog” (或Sherlock),旨在构建一个更全面的自动化感染事件重建系统。

最后,本课程中展示的所有研究成果已发表在学术论文中,可供深入查阅。


本节课总结:我们一起学习了如何利用两层LLM管道自动化分析信息窃取器的感染截图,从而识别感染途径、提取并分类攻击指标(IoC),并深入了解了攻击者常用的诱饵主题(破解软件、游戏作弊)和分发策略(YouTube、谷歌广告)。我们还探讨了该方法的优势、局限以及未来将LLM更广泛应用于安全日志分析的前景。

利用Unicode规范化绕过安全检测 [ETB2w-f3pM4] 🔐

在本节课中,我们将学习Unicode规范化如何被攻击者利用来绕过Web应用的安全检测。我们将通过“传话游戏”的类比,理解数据在多层处理流程中如何被意外改变,从而引发安全漏洞。课程将涵盖解码错误、混淆字符、大小写转换和组合字符等核心概念,并提供实用的工具和案例研究。


概述:Web传话游戏 📞

上一节我们介绍了课程的整体目标。本节中,我们来看看问题的核心类比。

想象一个“传话游戏”:一个人说一句话,经过多人传递后,最终的话可能变得面目全非。Web应用的数据处理流程与此类似。

一个Web请求从客户端发出,会经过多个中间系统(如CDN、WAF、应用服务器等),每个系统都可能对数据进行处理或安全检查。问题在于,安全检查之后,数据可能被后续处理逻辑(如解码、规范化、转换)意外改变,从而将一个原本无害的输入变成有效的攻击载荷。

这种处理顺序问题是许多安全漏洞的根源,对应通用缺陷枚举CWE-180。


第一部分:解码错误 🔍

上一节我们了解了处理流程错位的问题。本节中我们来看看第一类具体问题:解码错误。

当系统在处理Unicode(多字节)和ASCII(单字节)字符之间的转换时,如果缺乏“多字节感知”,就会产生解码错误,可能导致数据被误解。

多字节感知与CWE-172

Unicode字符长度可变(多字节),而ASCII是单字节。系统在转换时如果错误处理字节长度,就会产生乱码(Mojibake)。

核心概念:一个多字节Unicode字符(如<)的UTF-8编码是 %C2%BC。如果一个解码器不是多字节感知的,它可能会将 %C2%BC 当作两个独立的单字节ASCII字符解码,产生乱码,而不是原字符。

以下是使用Burp Suite Decoder插件的对比:

  • 无多字节感知:输入 %C2%BC 可能输出三个无关的Unicode字符(乱码)。
  • 有多字节感知(如Decoder Improved插件):正确解码并显示 < 字符。

过长编码与KPEC-80

过长编码是指用多于必要的字节数来表示一个字符(例如,用两个字节表示原本只需一个字节的ASCII字符‘A’)。早期UTF-8允许这样做,但现在被视为无效。问题在于,应用程序会如何响应这种编码?是阻止、正确规范化,还是产生乱码?

历史案例:2001年的Nimda蠕虫就利用了过长编码(将 ../ 编码)来绕过一些简单的目录遍历检测过滤器。

现代工具利用:SQLMap等工具的篡改脚本会使用过长编码来混淆空格等字符,尝试绕过安全检测。

例如,一个正则表达式 select\s+from 用于检测SQL注入。如果攻击者使用过长编码的“空格”(非单字节),而安全检查前未正确解码,则检测会失败。

字节截断

当系统为字符串分配固定长度的缓冲区(如单字节),但遇到多字节字符时,可能只存储第一个(或最后一个)字节,丢弃其余部分,这就是字节截断。

案例研究:攻击者向Microsoft端点提交UTF-8编码的“回车换行符”(%E2%80%A8%E2%80%A9)。安全检查将其视为中文字符而放行。但后端处理时,如果使用单字节缓冲区并以小端序存储,则可能只存储了%A8%A9这两个最低有效字节,它们恰好对应ASCII的回车(CR)和换行(LF)符,从而成功注入了HTTP头。

测试工具

  • CyberChef:使用“Encode text”配方并选择“ASCII 7-bit”可以模拟服务器端的字节截断。
  • Shazzar:输入一个十六进制值,可以找出哪些Unicode字符截断后会变成该值。


第二部分:混淆字符(视觉欺骗) 👁️

上一节我们探讨了因解码产生的漏洞。本节中我们来看看另一类问题:视觉上相似的字符。

这不是指钓鱼攻击中的域名欺骗,而是指Web应用层将输入的Unicode字符“最佳匹配”或“规范化”为视觉相似的ASCII字符。

规范化形式与最佳匹配映射

当应用收到非ASCII字符(如希腊字母Alpha Α)但只接受ASCII时,它可能会将其“映射”为看起来相似的ASCII字符(如字母A)。这种映射可能由Unicode规范化形式(如NFKD)或特定代码页(如Windows-1252)完成。

案例研究:.NET Nuke漏洞

  1. 攻击者上传文件,文件名包含全角的斜杠和点(看起来像\.,但实际是Unicode字符)。
  2. 应用使用正则表达式检查文件名,寻找ASCII的点字符以阻止路径遍历。由于文件名是Unicode字符,检测通过。
  3. 随后,应用使用代码页1252进行“最佳匹配映射”,将全角字符转换回标准的ASCII反斜杠和点。
  4. 此时,文件名变成了有效的UNC路径(如\\oaasify.burpcollaborator.net\...),导致应用向攻击者控制的服务器发起出站连接,可能泄露凭证。

测试工具

  • Unicode实用工具:在Unicode官网可以输入一个ASCII字符,查询所有能规范化回该字符的Unicode变体。
  • ActiveScan++更新:包含“可疑输入转换”检查。它在输入中插入特殊的Unicode字符(如开尔文符号),如果响应中该字符被转换为ASCII的K,则表明存在规范化操作,值得深入调查。

第三部分:大小写转换 🔠

上一节我们了解了字符的视觉映射。本节中我们来看看大小写转换可能带来的问题。

应用可能对输入进行大小写转换(如转为大写)以实现标准化。但某些Unicode字符在进行大小写转换时,会变成完全不同的、在浏览器中可执行的字符。

案例:攻击者输入包含ı(拉丁文无点小写I)的字符串。安全检查寻找<script>标签,由于字符不同,检测通过。
随后,应用对输入执行uppercase()操作。在特定语言环境下,ı的大写形式是I。于是,原本无害的<scrıpt>在转换后变成了可被浏览器执行的<script>标签。

核心要点:任何进行大小写转换的地方都可能存在此类映射风险。

测试工具

  • Python演示payload = “<scrıpt>”.encode(‘utf-8’).decode(‘utf-8’).upper() 会输出<SCRIPT>
  • ReCollapse工具更新:新增了标志位,可以生成在大小写转换后能映射到目标字符的不同Unicode字符变体,用于测试。


第四部分:组合字符(组合变音符号) ✨

上一节我们讨论了字符转换的风险。最后,我们来看看最精妙的一类:组合字符。

Unicode可以将一个带音调的字符(如á)分解(规范化形式NFD)为两个码点:基础字符(a)加上一个组合变音符号( ́)。这种特性可能被用于欺骗数据库或修改上下文。

案例研究1:零点击账户接管

在密码重置流程中:

  1. 攻击者使用邮箱 attacker@gmail.com(注意a是带双重重音的Unicode字符)请求重置受害者的密码 victim@gmail.com
  2. 数据库使用“口音不敏感”的排序规则(如 utf8mb4_0900_ai_ci)。它认为 attacker@gmail.com 等价于 attacker@gmail.com
  3. 数据库确认用户存在,生成重置令牌。
  4. 关键:令牌被发送到攻击者提供的邮箱(attacker@gmail.com),而不是数据库里存储的受害者的标准邮箱。攻击者从而接管了受害者账户。

案例研究2:通过组合字符实现XSS

在一个XSS实验室中,用户输入被放在 <textarea> 标签之后:<textarea>用户输入</textarea>
攻击目标是让“用户输入”与前面的 > 符号结合,改变HTML上下文。

利用过程

  1. 攻击者输入一个组合字符“长竖线叠加符”(̸)。
  2. 后端处理时,这个组合字符与前面的 > 符号进行组合。
  3. 组合后的结果变成了“不大于”符号()。
  4. 这破坏了 <textarea> 的闭合,使得攻击者可以在其后注入JavaScript代码(如 onfocus=alert(1) autofocus),从而执行XSS攻击。

工具更新:ActiveScan++也增加了对此类组合字符的检测,寻找输入是否能与上下文字符组合成新字符的迹象。


总结与要点 ✅

本节课中我们一起学习了Unicode规范化如何被利用来绕过Web安全检测。

核心要点总结

  1. 首要问题(CWE-180)安全检查在数据转换之后进行是根本原因。必须确保安全逻辑在处理链上的正确顺序。
  2. 验证解码流程:确保URL解码、字符集转换在任何安全过滤之前正确完成,且系统具备多字节感知能力。
  3. 了解规范化行为:查明应用程序使用了哪种Unicode规范化形式或代码页,并评估将Unicode转换为ASCII的“最佳匹配”行为是否带来风险。
  4. 注意内置转换:警惕那些可能隐式进行大小写转换、口音折叠或字符组合的第三方库、数据库排序规则和框架功能。
  5. 利用更新工具:使用Burp Suite ActiveScan++、ReCollapse等工具的更新版本,可以帮助自动化探测这些复杂的Unicode处理问题。

对于防御者和漏洞猎人而言,理解这些模式有助于发现和修复此类深层次的Unicode相关问题。

利用大语言模型与定制化数据流分析增强静态应用安全测试 🔍

在本课程中,我们将学习如何结合大语言模型(LLMs)与定制化的数据流分析(DFA)技术,来增强静态应用安全测试(SAST)的能力,从而提高发现代码安全漏洞的效率和准确性。

什么是SAST? 🛡️

SAST,即静态应用安全测试。使用SAST工具,我们可以在不运行应用程序的情况下分析源代码。例如,检测SQL注入漏洞。

从右侧的图片中,我们可以看到,SAST现已成为DevSecOps中自动化安全检查的重要组成部分。流行的工具包括CodeQL、Fortify等。

什么是CodeQL? 💻

CodeQL现已成为GitHub旗下的一个产品。其查询和库在MIT许可证下是开源的,包括其数据流分析部分。但其核心引擎是专有的。

CodeQL的工作流程包含四个步骤:

  1. 下载项目的源代码。
  2. 使用CodeQL命令行工具创建数据库。
  3. 编写QL查询语句。
  4. 针对数据库运行查询,并最终展示是否存在漏洞。

在CodeQL的“荣誉墙”上,我们可以看到所有被CodeQL发现的漏洞。这不是一个完整的列表,但截至目前,它已发现了418个漏洞,并且这个数字仍在增长。此外,在GitHub上,我们可以为项目设置CodeQL扫描,可以定期执行,也可以在每次拉取请求时触发。

挑战:误报与漏报 ❌

那么,这是否意味着没有漏洞了呢?我们尝试使用CodeQL来检测近期的一些高风险漏洞,例如本表中列出的那些。我们发现存在大量的漏报。我们分析了根本原因,如最后一列所示,并发现了两个主要原因:

  1. 内置污染传播规则中,对“源”(source)和“汇”(sink)函数的覆盖不完整。
  2. 由于对某些语言特性支持不足,导致数据流中断。

对于第一个问题,我将介绍如何使用大语言模型(LLMs)来自动识别源和汇函数。

利用LLMs自动识别源与汇函数 🤖

我们注意到,当前的方法严重依赖人工工作。一种方法是手动定义,即开发者必须手动审查源代码以识别源和汇。另一种方式是通过社区贡献,例如CodeQL有默认规则。从图中我们可以看到,关键信息包括库、模块、函数名。但我们发现这两种方法都相当耗费人力。

那么,有没有办法自动化这个过程呢?

问题一:在哪里寻找源和汇?

我们发现,源和汇函数实际上是来自第三方框架的API函数。从左边的图片中,我们可以看到,SSRF的汇实际上是Resty框架中的一个API。这些API函数的实现代码可以在开源框架中找到。因此,我们可以通过扫描这些框架来检测源和汇。

问题二:LLMs如何提供帮助?

右边是我们方法的工作流程。它包含三个AI智能体:

  1. 首先,我们使用“发现”智能体来识别框架中潜在的源和汇函数。
  2. 接着,“判断”智能体应用专家规则来检查这些函数,并移除不符合专家经验的结果。
  3. 最后,“验证”智能体编写查询来验证这些函数是否在真实项目中被使用。

文件级粗粒度检测

首先,我们在文件级别运行粗粒度检测。我们将源代码文件和一个提示词(prompt)输入给模型。在提示词中,我们会描述需要识别的函数的特征,这些特征与编程语言和漏洞类型相关。例如,对于SSRF漏洞,汇函数通常是那些发送HTTP请求的函数。此外,我们还可以对响应的格式和风格设置约束。你可以尝试不同的提示词以获得最佳结果,这只是一个参考。

对于LLM的结果,我们会移除置信度分数较低的结果,阈值可以根据你使用的提示词和模型进行调整。最终,我们将得到一个源和汇函数的列表。

函数级细粒度过滤

为了移除上一步产生的误报,我们继续进行函数级别的过滤。我们同时检查函数名和函数代码。例如,对于SSRF,汇是发送HTTP请求的函数;而对于SQL注入,汇是执行SQL语句的函数。我们注意到,大型语言模型在此阶段往往表现更好。同样,任何不符合标准的函数都将被移除。最终,我们收集了每个框架中存在的所有源和汇函数。

集成专家经验

除了让LLM直接扫描,我们还需要集成专家经验。这些经验来自社区的长期实践。例如:

  • 函数应该是公开可访问的。
  • 函数的返回值应该传播被污染的数据。
  • 函数的返回值不应是布尔类型。

这样的专家规则还有很多。同样,它们可以根据不同的漏洞类型或框架类型进行添加或修订。我们将使用LLM来应用这些专家规则,检查函数名和函数体,并移除不匹配专家规则的函数。

验证实际使用情况

最后一步是确认我们识别出的源和汇是否确实在真实项目中被使用。

  1. 首先,我们需要访问框架项目的主页,找到其依赖页面。这个页面列出了大多数使用该框架的开源项目。
  2. 接下来,下载这些项目的源代码,按星标数从高到低排序。
  3. 最后,运行像CodeQL这样的SAST工具,应用新的源/汇规则来扫描这些项目。根据扫描结果,验证新添加的源和汇是否被实际使用,任何未被使用的源或汇都将被移除。

增强数据流分析(DFA) 🧩

对于第二个问题,即数据流中断,我将介绍我们对数据流分析(DFA)的增强。

什么是CodeQL中的数据流分析?

在CodeQL和其他SAST工具中,数据流分析是核心。左边是CodeQL中数据流分析的一个例子。它通过扩展DataFlow::Configuration类,并在第10行实现isSource接口,在第16行实现isSink接口,然后在第27行调用flowPath来执行全局污点分析。

右边是分析结果。我们可以看到一系列编号的路径节点,这个列表代表了一条完整的数据流路径。每个路径节点包含两部分:节点(Node)和访问路径(Access Path)。

DFA的工作流程

这个图表展示了DFA的工作流程。首先,CodeQL提供了配置用户接口,你可以调用flowPath API(如上一张幻灯片所示)。其中有两个关键概念:节点(Node)和访问路径(Access Path)。

节点通过正向流(forward flow)和反向流(reverse flow)计算得出。正向流是从源点开始的向前传播,而反向流则相反,是从汇点向后追踪。它们共同形成了一条从源到汇的完整路径。

访问路径的计算分为五个阶段,从阶段1到阶段5。每个阶段都会添加更多细节以产生最终结果。

节点计算:正向流示例

我们使用正向流来说明节点是如何计算的。右边是CodeQL源代码的示意图,它包含不同的步骤,如jumpstore等,细节在表格中。

  1. 源步骤:设置数据流的起点。
  2. 局部流步骤:处理过程内(intra-procedural)分析。
  3. 跳转步骤:提供从一个节点到另一个节点的自定义传播接口。有两个接口:通过additionalFlowStep的用户级接口和通过additionalValueStep的系统级接口。
  4. 存储和加载步骤store是将污点节点写入字段、数组、集合或映射内容中,而load是从中读取污点节点。这是访问路径的核心。
  5. 调用入、调用出和贯穿步骤:处理过程间(inter-procedural)分析。callIn处理从实际参数到形式参数的传播。callOutgoThrough处理返回值的传播,区别在于返回值是从外部源还是参数传播而来。注意,这里的postUpdateNode代表作为函数调用结果而隐式更新的节点。

什么是访问路径?

访问路径由一个内容列表和一个类型组成。内容本质上是描述数据如何存储在对象内部的一种方式,细节在左边的表格中。对于一个字段类型,其内容就是字段名;对于其他类型,它更像是表格中所示的广义结果。

访问路径跟踪在存储和加载步骤期间,四种类型节点(字段、数组、集合和映射)的内容传播关系。这里的表格展示了访问路径的示例。例如,在这个角色中,内容是name,类型是string

如何计算访问路径?

在右边这里,我们根据表格编写了一个示例代码。你可以看到在每个阶段,内部值的访问路径是如何变化的。在阶段1开始时,根本没有访问路径。在阶段2,访问路径变为布尔类型,表示是否存在内容传播操作。在最后阶段,我们发现完整的访问路径是一个内容列表和一个类型。

应对DFA的挑战:以Java为例 ⚔️

在概述了DFA之后,我们现在介绍它面临的一些挑战,以Java为例。

静态分析工具(包括CodeQL)面临着诸如跨线程问题、反射和值传递等挑战。

挑战一:跨线程分析

这是一个跨线程分析的例子。静态main方法的参数是源点,而println方法的参数是汇点。左边是代码,右边是静态分析的中间结果。

正如我们在默认分析中看到的,我们无法找到从源到汇的路径。它在第14行RunnableDemo的构造函数调用处中断了。

解决方案:利用跳转步骤

我们如何连接它?回想一下之前介绍的跳转步骤,我们可以使用跳转步骤,从RunnableDemo调用跳转到run方法的实例参数,即this参数。打上补丁后,我们得到了完整的路径。

总结一下,当污点通过Runnable实例的构造函数传播时,我们的方法是从构造函数调用跳转到run方法。这是使用additionalValueStep接口的实现,我们在此完成了跳转步骤。

但如果污点不是通过构造函数传递的呢?例如,通过函数调用中的赋值语句(如第8行所示),我们如何处理这种情况?

我们的解决方案是:如果污点在start接口被调用之前就已存在(如第17行所示),我们获取start方法的调用者,并跳转到run方法的实例参数。所以是从这里跳到这里。在这种情况下,从第18行跳转到第10行。打上补丁后,我们可以得到完整的路径。

如果污点出现在start接口之后呢?在这种情况下(第23行),我们的方法是找到一个满足三个条件的节点:

  1. 该节点是一个postUpdateNode
  2. 该节点是一个Runnable实例。
  3. 该节点有一个存储操作。

我们从该节点跳转到run方法的实例参数。所以在这种情况下,从第8行跳转到第10行。打上补丁后,你可以看到完整的流被检测到了。

挑战二:Java反射

接下来,我们介绍第二个挑战:Java反射。以这段代码中的invoke方法为例(第13行),我们面临两个困难:

  1. 我们如何确定invoke实际对应的是哪个方法?即,第13行的方法是什么?
  2. 我们如何修复过程间调用(如callIncallThrough)的传播关系?从红线我们可以看到,参数传播逻辑与正常的调用过程不同。

解决方案一:确定反射方法

对于挑战一,有两种解决方案。一种方法是跟踪方法实例,如图所示。另一种是根据invoke方法中参数的数量和类型来确定方法。我们已经实现了这两种方法,并注意这种跟踪需要全局数据流分析。

解决方案二:在CodeQL数据流中整合反射分析

第二个挑战,如何让反射分析在CodeQL的数据流中工作?我们之前提到,additionalValueStep可以定义边来连接两个节点。但这里有个问题:你不能在additionalValueStep内部使用数据流接口,因为这样做会导致非单调递归问题。基本上,你需要在additionalValueStep中使用数据流接口,但数据流接口又依赖于additionalValueStep,如图所示。

如何解决这个问题?我们可以创建一份数据流分析实现的副本,让我们的反射分析依赖于这个副本,如图所示。然后我们修补原始的数据流以避免任何依赖问题。

为了支持invoke方法,我们修复了callIncallThrough的参数传播逻辑。例如,对于callInaugment传播到参数,object传播到参数this

这里是一个反射的例子。首先,数据流在第13行的invoke方法处中断。通过添加反射分析(如步骤1-4所示),我们可以将污点从这里的source传播到这里的object。因此我们得到了完整的路径。

挑战三:Java中的值传递

接下来,介绍Java中的值传递问题。首先,什么是编程语言中的值传递?参数通常通过值传递或引用传递。在Java中,实际参数传递给方法的方式是值传递,而不是引用传递。因此,如果参数是基本类型,传递的是基本类型实际值的副本,并且会创建一个副本。如果是引用类型,传递的是实际参数所引用对象在堆中地址值的副本。就像基本类型一样,会创建一个副本。

那么问题是什么?右边是一个副本存储在字段中的案例。但问题是存在许多副本,例如这个例子中的Person pd.a。所以核心问题是,当一个副本中的值被修改时,所有副本都需要更新。

在这种情况下,它是DemoField实例构造函数中的参数Person p,副本用这里的蓝线表示。

解决方案:处理值传递副本

以下是我们的解决方案:

  1. 首先,我们必须定位非基本类型的字段。在这个例子中,它对应于字段a
  2. 对于这个字段,找到存储操作,识别出非postUpdateNodepostUpdateNode。在这个例子中,它对应于第7行和第11行。第7行是非postUpdateNode,而第11行是postUpdateNode
  3. 对于非postUpdateNode的存储操作,使用全局数据流来定位参数和实际参数。在这个例子中,如红色虚线所示,我们定位到了DemoField构造函数中的参数p
  4. 对于postUpdateNode的另一个存储操作,我们添加一个从该节点到该节点的映射。这就是我们之前介绍的跳转步骤。

我们必须使用全局数据流,因为我们可能会遇到过程间调用、存储和加载操作等场景。

研究成果与案例 🏆

接下来,我将介绍我们的研究成果。

识别结果

我们在大约18个Go框架中发现了约190个源和汇函数。我们还扫描了超过5000个项目,发现检测到的数据流增加了15%以上。

案例一:发现新的SQL注入漏洞

我们使用这个CVE来展示一个新的汇如何导致漏洞检测。这是Apache Traffic Control项目中Traffic Ops组件的一个SQL注入漏洞。这个项目启用了CodeQL扫描,这意味着它对CodeQL来说是一个漏报。

以下是该漏洞的数据流:

  1. 第一步是从用户输入中读取参数,这里是用户的评论。
  2. 然后处理和验证请求参数,如这个info.go文件所示。
  3. 最后,当将用户评论插入数据库时,调用了QueryRowx函数。

但当我们检查CodeQL的检测规则时,我们注意到QueryRowx函数没有被包含在汇模型中。我们扫描了sqlx框架,并发现了这个汇,如图所示。因此,我们检测到了这个漏洞。

案例二:增强检测历史CVE

通过我们的增强,我们可以检测到以前无法检测到的历史CVE。在这个案例中,添加源函数使得能够检测到三个CVE,影响了几个开源项目。

案例三:验证跨线程和反射增强

这个CVE证明了跨线程补丁和缺失汇规则的有效性,因此我们可以复现这个CVE。而这个CVE则证明了反射增强的有效性。

此外,我们还发现了许多新的漏洞,下面是一些案例。

总结与要点 📚

在本课程中,我们一起学习了如何利用大语言模型自动识别安全分析中的源与汇函数,并对静态分析工具(以CodeQL为例)的数据流分析机制进行了定制化增强,以应对跨线程、反射、值传递等复杂场景。

我们的主要收获如下:

  1. 代码的语义分析特别适合LLM辅助分析,二者的结合是一个有前景的研究方向。
  2. CodeQL的数据流分析机制具有高度代表性,是学习数据流分析的一个良好起点。
  3. CodeQL的数据分析并非完美,可以被研究、修改和改进。

希望本教程能帮助你理解如何利用现代技术增强传统的安全测试方法。

无需VPN?针对OPC UA协议的密码学攻击 🛡️🔓

在本节课中,我们将学习OPC UA协议的基础知识、其内置的安全特性,并深入探讨两种针对其加密机制的潜在攻击方法。我们将了解这些攻击的原理、实现方式以及防御措施。


OPC UA协议概述

OPC UA是一种用于工业自动化的通用通信协议。它被广泛应用于各种行业和场景,用于实现工业控制系统、监控与数据采集系统、可编程逻辑控制器等设备间的通信。与许多该领域的其他协议不同,OPC UA不是专有协议,而是一个开放的标准协议,得到了多家供应商的支持,可以实现互操作性。它也不是基于半个世纪前的串行协议。

我个人发现它最有趣的一点是,它具备安全特性。得益于这些安全特性,如传输加密和身份验证,许多用户认为可以跨信任边界暴露此协议。这与许多其他操作技术协议不同,那些协议通常需要隔离在不同的网络段中。

特别是当你有像现场设备(例如,某个需要远程控制或监控的风力发电机)时,能够通过互联网建立连接会非常方便。由于OPC UA的安全和加密特性,它甚至被广泛用于各种无需建立VPN连接的场景,这被视为该协议的一大优势。

这促使我去研究这个加密协议的实际工作原理。


协议架构与加密层

OPC UA协议基于两个不同的层构建。

上一节我们介绍了OPC UA的基本概念,本节中我们来看看其核心架构。

安全通道层 负责建立传输加密以及客户端与服务器之间的设备身份验证。这通常用于自动化系统连接时。

会话层(或应用层) 负责用户身份验证和授权。这通常用于有人(例如使用人机界面)直接与系统交互的场景。你可以同时使用两种身份验证方法,也可以关闭加密,或者仅使用加密完整性保护而不进行实际加密。

当使用客户端证书进行身份验证时,信任模型通常基于证书。在许多实现中,当客户端首次连接到服务器时,连接会被拒绝,因为证书不受信任。然后,服务器端的管理员可以查看被拒绝的证书列表,并选择信任它们。这是一种相当实用的“首次使用即信任”解决方案。当然,也有基于公钥基础设施或完全预配置的不同设置。


安全通道握手流程

现在,让我们深入了解安全通道层的具体握手过程。

安全通道层以一个典型的加密握手开始。客户端预先知道服务器的证书(包含公钥)以及支持的加密套件。这些信息要么是预配置的,要么是通过发现协议获取的(这超出了本次讨论的范围)。

以下是握手步骤:

  1. 客户端生成一个随机数,用自己的私钥签名,并用服务器的公钥加密。
  2. 客户端将此消息发送给服务器。
  3. 服务器也响应一个包含其自身随机数的签名和加密消息。
  4. 双方将这两个随机数输入密钥派生函数,从而派生出用于后续通信的对称会话密钥。

该协议支持多种不同的“安全策略”,即在此过程中使用的底层密码套件集合。在实践中,目前实现最多的基本上都是RSA和AES的变体。


会话建立与身份验证

在完成第一个安全通道握手后,客户端和服务器将继续建立会话。即使不使用用户身份验证,每次连接也需要此步骤。

在此协议中,先前派生的密钥用于加密每条消息,并使用相当标准的AES-CBC和HMAC结构进行身份验证。

以下是会话建立步骤:

  1. 客户端生成一个随机挑战值并发送给服务器。
  2. 服务器通过签名此挑战来证明其身份,然后生成一个新的挑战要求客户端签名。
  3. 客户端签名该挑战,身份验证完成。
  4. 可选地,客户端还可以通过多种方式添加最终用户的身份验证信息。

如果所有这些都成功,双方就知道,使用此特定会话密钥的特定会话已经过身份验证。

从性能角度来看,值得注意的是,这两个步骤的组合并不是一个非常高效的协议,因为双方都需要执行三次昂贵的RSA解密或签名操作。而如果基于RSA进行相互身份验证和密钥交换,实际上只需要执行一次。当然,效率低下并不意味着协议不安全,拥有这些多层结构实际上可能使攻击变得更加困难。


发现协议设计缺陷

上一节我们介绍了会话建立的流程,本节中我们来看看其中存在的一个设计缺陷。

在协议的第二阶段(即会话握手)中,引起我注意的是客户端和服务器相互发送挑战的方式。它们通过获取该值,将其与对方站点的证书值连接,然后对其进行签名。但这种方法在两个方向上基本上完全相同。

它们没有包含任何上下文元数据来说明“这是一条从服务器发往客户端的消息”或“从客户端发往服务器的消息”。这有点问题,因为在OPC UA的许多用例中,一个系统可以同时充当客户端和服务器,并且它们通常使用完全相同的证书。因此,你可以使用相同的公钥来签署任一方向的消息,但这些消息的结构完全相同。

理论上,这开启了一种潜在的签名预言机攻击,你基本上可以交换这些类型的消息,并诱骗一个服务器签署它本不应该签署的内容。


攻击一:反射/中继攻击

基于上述缺陷,我构思的第一种理论攻击是中继攻击。

以下是攻击场景:

  • 假设有两个相互信任的服务器:服务器A和服务器B。
  • 攻击者连接到服务器A,并声称自己的身份是服务器B。它提供从服务器B发现的证书和一个挑战。
  • 服务器A签署该挑战,然后提供自己的挑战要求攻击者签名。
  • 攻击者无法自己签名(因为不知道私钥),于是建立到服务器B的连接。
  • 攻击者将从服务器A获得的挑战复制过来,要求服务器B签署该挑战(此时攻击者假装是作为客户端的服务器A)。
  • 服务器B提供签名值。
  • 攻击者切断与服务器B的连接,将该值填入发送给服务器A的消息中,从而绕过身份验证步骤。

实际上,你甚至不需要两个服务器,因为在许多实现中,默认情况下服务器信任自己的证书。然后,你可以对同一个服务器执行基本相同的操作。攻击者尝试登录服务器A并假装是服务器A(这实际上是被允许的)。然后,他们建立到同一服务器的第二个连接,让它签署自己的挑战,切断第二个连接,继续第一个连接,从而绕过整个会话身份验证步骤。


攻击一的限制与绕过

但是,冗余的RSA操作在这里起到了作用。我们可能在技术上绕过了第二层的身份验证协议,但我们仍然有第一层——安全通道,我们需要用自己的私钥解密某些内容,并用私钥签署某些内容。而攻击者在这种情况下没有私钥,因此无法执行此操作,也就无法派生出正确的对称密钥,甚至无法生成可用于此协议的有效消息。

那么,我们如何绕过这一点呢?

事实证明,有一种相对简单的方法可以绕过它,那就是使用协议的变体。默认情况下,OPC UA是直接通过TCP使用的二进制协议。但有一个可选变体,通过服务器身份验证的HTTPS进行隧道传输。

因为HTTPS已经提供了传输加密,协议设计者认为可以跳过这个握手步骤,因为整个TLS层会处理它。然而,问题在于,这个握手步骤隐含地已经验证了客户端,因为客户端必须使用私钥进行操作。但当使用服务器身份验证的HTTPS时,服务器验证自身,但客户端不验证。

因此,当通过HTTPS使用OPC UA时,你完全依赖于这个会话层的身份验证。而这正是我们刚刚绕过的部分。我为这个协议变体实现了这个攻击,制作了一个工具,并且它完全奏效。你只需提供一个启用HTTPS的OPC服务器,该工具将通过执行反射攻击(或如果有两个服务器则执行中继攻击)立即绕过身份验证,服务器将泄露其所有秘密,基本上让你获得完全访问权限。


攻击二:利用脆弱的RSA填充方案

现在,如果仅仅因为实践中没有多少用户实际使用这个HTTPS协议变体,那么攻击的影响就相当有限。所以,更有趣的是攻击更常见的变体,即针对通过TCP的OPC UA。

我的方法是利用其中一个受支持的密码套件,该套件基于使用PKCS#1 v1.5填充方案的RSA。这个方案基本上在1998年就被Daniel Bleichenbacher明确攻破了。但由于某种原因,此后许多协议设计者没有注意到这一点,仍然继续使用这种特定的RSA填充方案。因此,看看我们是否能在OPC UA的背景下实际利用这些众所周知的漏洞可能是值得的。

唯一的问题是,这个方案(或至少使用此方案的密码套件)已被OPC基金会弃用,建议实现者仍然支持它,但默认将其关闭。那么,尝试攻击一个已弃用的功能有什么意义呢?首先,许多实现并没有真正遵循这个通知,仍然默认启用它。其次,可能有很多用户使用的是在此弃用之前设置的配置,而且可能没有多少供应商会发布破坏先前配置的补丁。因此,它们仍然会支持这个密码套件。此外,非常有趣的是,有些实现默认不提供此方法,但当它被显式禁用时,它们只会在已经尝试使用该协议解密消息后才检查它是否被禁用。所以,我尝试发送使用此脆弱方案加密的消息,服务器尝试解密它,然后决定:“哦,等等,我不应该使用这个,我要阻止连接。”但此时,它已经进行了解密,这已经为攻击创造了条件。同样有趣的是,即使你只有一个支持此协议的服务器,你也可以使用该攻击来针对其他可能从未使用过它、并且可能已将其关闭或使用更安全RSA填充方案的系统。


Bleichenbacher攻击原理简介

上一节提到了利用脆弱的RSA填充,本节我们来简要了解其攻击原理。

Bleichenbacher对RSA加密的攻击,简而言之,RSA加密基本上就是对一个大整数进行模幂运算。RSA填充的全部意义在于将字节序列(你的消息)变成一个大整数。PKCS#1 v1.5方案的做法是添加一个0x00字节、一个0x02字节、一堆随机字节、一个0x00字节,然后是实际数据,以确保你得到一个非常大的数字,而不仅仅是像数字1这样的消息(如果对它进行幂运算,它会保持不变)。

服务器解密后,会检查这个填充并移除它以获得原始消息。如果你作为攻击者,能够看到服务器无法移除这个填充(服务器给出错误或某些指示填充失败的信息),这就会泄露一点关于你的密文所代表的消息的信息。因为如果填充失败,显然它不符合这种格式;如果它没有失败,它必须匹配这种格式,这意味着加密后的数字必须大于以0x02开头的数字,但小于以0x03开头的数字。

如果你有一个未知的、加密的RSA秘密值,你可以利用RSA的同态特性,基本上用已知值乘以密文,得到秘密值和你选择值的乘积结果。通过选择大量特定值,并观察每次结果是“有效”还是“无效”,每次填充有效时都会泄露一点信息。当你以巧妙的方式进行时,最终可以一点一点地解密整个消息,在大约一百万次查询后将其范围缩小,这就是为什么这种攻击有时也被称为“百万消息攻击”。


将攻击应用于OPC UA

那么,我们如何将其用于攻击OPC UA呢?我们需要绕过两个涉及RSA私钥的不同操作:对初始消息的签名,以及完成签名后,你仍然需要解密返回的消息以获取其中的随机数。

解密是直接的,但你也可以使用Bleichenbacher攻击来伪造签名,因为RSA签名基本上可以归结为对哈希值的RSA解密。你可以使用几乎相同的技术来伪造签名。

因此,你需要做的是:开始执行Bleichenbacher攻击,直到你在某个消息(包括你发送的某个随机数)上伪造了一个签名。发送此消息,得到一个加密的响应,然后再次执行攻击以解密该响应。

第一阶段,一旦你伪造了一个签名,你就可以重复使用该签名。所以你实际上只需要执行第一步一次。第二步有点棘手,因为在执行攻击时,你必须保持原始连接打开,因为一旦连接关闭,随机数就不再有效和有用。在实践中,你基本上只需在一个连接上不断发送TCP保活消息以保持其打开,然后使用不同的连接来执行Bleichenbacher攻击。

当然,要在实践中使其工作,你仍然需要一个填充预言机。你需要一种方法来区分有效填充和无效填充。对于某些实现,这非常容易,因为它们只是给出不同的错误消息。如果填充错误,你会看到某种错误代码或错误字符串;如果填充正确,则有所不同。然后你可以区分这两种情况,并基本上实现这种标准攻击,而不会遇到太多麻烦。

但不幸的是,我测试的大多数实现都显示完全相同的错误消息,无论填充检查失败还是填充通过但签名无效。因此,利用此攻击的另一种典型方法是利用基于时间的侧信道攻击,基本上尝试利用正确填充和不正确填充之间的时间差。


实施时间侧信道攻击

起初,这听起来非常困难且不切实际,至少需要确保没有太多网络抖动,进行大量额外测试,花费很长时间,并使用统计技术过滤误报。进行这样的时间攻击听起来非常困难。

但请记住,并非所有时间攻击都很难。如果你有包含sleep语句的传统SQL注入,那是一个非常容易的时间攻击,因为你可以影响时间差,使其变得非常大。在OPC UA协议中,你可以做类似的事情,因为它们进行RSA加密的方式有点奇怪。它有点像RSA运行在一种ECB模式下。如果消息太长,无法放入单个RSA块(在实践中总是如此,因为消息还包括相同大小的签名,所以通常是两个块的大小),它们只是拆分这些消息块并单独加密每个块。

这真的不是你应该使用RSA的方式。这是一种非常奇怪的结构,尽管它与在分组密码中使用ECB具有非常不同的属性,但你实际上可以将此机制与RSA一起使用来加密你的企鹅图片。然而,这确实会带来许多理论上的选择密文攻击。但我可以利用这个方案的什么属性呢?那就是,你可以获取Bleichenbacher攻击的一个猜测值,并将你用于攻击的密文重复100次。

然后,你将这条长消息发送给服务器。如果猜测的填充错误,服务器尝试解密第一条消息,看到填充错误,抛出异常,停止处理。但如果第一条消息的填充正确,它将进行解密第二个块(你重复的是同一个块,所以它也会正确),因此它将解密所有这100个块。RSA解密是一项非常昂贵的操作。只有在完成这100次解密后,它才会注意到消息是错误的,然后失败。这导致了相当大的时间差。你实际上可以稍微调整消息的长度,这在一定程度上取决于它们的消息限制。当然,如果你的消息更短,你可以更快地执行攻击。但在这个例子中,你可以看到,重复密文100次,时间差的数量级大约是几十秒。这是一个非常大的时间差。

为了利用这一点,我真的不需要任何花哨的统计方法,除了如果我看到某些东西花费的时间稍长,可能会重复几次以避免误报,但实际上计时真的非常容易。所以,我采用了标准的Bleichenbacher攻击,但不是查看错误消息之间的差异,而是进行一些相对简单的时间测量。如果处理时间短于某个阈值(实际上绝大多数情况都是如此,因为在Bleichenbacher攻击期间,绝大多数消息的填充都是无效的),那么我就认为填充无效。但如果处理时间明显长很多,我就认为填充有效,并将此结果返回给算法实现,说在这种情况下填充是正确的。

这听起来像是一个非常缓慢的攻击。但因为像99%你发送的消息实际上都是快速情况,只有那些相对罕见的、填充正确的情况才需要长时间,所以这个攻击实际上并不比使用错误预言机慢多少,这令人惊讶。


攻击工具与影响

我将所有这些集成到我的工具中,并添加了一个漂亮的小进度条,上面有一个旋转的条形图和不断增高的数字,你可以在工具工作时盯着它看。几秒钟后,数字慢慢上升,再上升一点。然后工具暂停了第一阶段,它已成功伪造了签名。所以它将此签名存储在一个文件中,这样如果第二阶段失败,你可以重复使用它。然后,它只是尝试发送带有伪造签名的消息,得到回复,保持连接打开,然后再次尝试执行攻击以解密从服务器接收回来的消息。

它成功了。我可以将其指向一个服务器,并再次绕过客户端身份验证步骤。在这个例子中,正如你从秒表上看到的,只花了15分钟。公平地说,这是一个相对较快的情况。这是一个用C语言编写的相当高效的实现,所以比其他实现快一些。我测试此攻击的其他实现可能需要大约30分钟,也许一小时,最坏情况是两小时。当然,这是在实验室设置中进行的,网络干扰不大,尽管我也尝试通过托管虚拟机来测试(仍在同一个国家)。总的来说,攻击实际上会奏效,有时只是比其他情况慢一点。对于攻击者来说,如果你的攻击需要15分钟到两小时,这其实没什么区别,只是意味着你需要在攻击期间喝杯咖啡或者出去吃个午饭。

从防御者的角度来看,我还发现,这种攻击发生在握手的第一个步骤,许多服务器实际上不会在此阶段记录任何加密失败。所以如果你去查看日志,情况并非总是如此,我有一个实现,但所有日志都充满了各种奇怪的错误,这可能会引起一些注意或填满日志。但在大多数情况下,攻击实际上是隐形的,你在另一端看不到任何相关信息。所以,如果你是攻击者,你可能不会介意为此花一点时间。

当然,这仍然取决于各个实现的特殊性。这些是协议缺陷,但它是否有效确实取决于一些细节和配置。


漏洞影响范围与披露

我测试了7种不同的OPC UA实现。其中两种完全不受影响,两种攻击都无效,但其余五种中有漏洞。在这五种中,有四种在其默认配置下容易受到其中一种或另一种攻击。因此,如果你使用启用客户端身份验证的默认安全配置,你将容易受到攻击。

所有这些都假设你的设置仅使用客户端-服务器证书身份验证机制。如果你有用户身份验证,如果你有密码,我的攻击将无法帮助你猜测密码。所以,如果你只使用密码身份验证,这些攻击不相关。但如果你使用基于证书的身份验证(对于自动化系统建立连接来说,这是一个合理的设置),那么这可能导致身份验证绕过。

我选择这7种实现是因为我可以在合理的时间内让实验室设置工作,并且它们不需要昂贵的硬件或软件许可证。但还有更多的实现。如果在这个样本中有5/7存在漏洞,你或许可以推断,许多其他实现也会容易受到同样的攻击。在披露之后,我看到来自多家供应商(特别是西门子的许多产品,如WinCC服务器)发布了针对这些漏洞的补丁通知,甚至给出了相对较高的CVSS分数。由此我推测,它们在常见配置中可能也存在漏洞。

我发现了一些协议缺陷。嗯,这有点取决于具体情况,这些协议缺陷在不同的实现中表现略有不同。当然,这听起来像是披露的噩梦,必须联系所有这些不同的供应商,而且还有我甚至没有测试过的其他供应商。但幸运的是,有OPC基金会,它负责管理标准。它的成员基本上涵盖了几乎所有协议实现者。所有这些供应商已经在这个基金会中聚集在一起。

他们实际上有一个非常好的系统,安全漏洞可以直接披露给基金会,而不必逐个联系像西门子这样的供应商。我向他们披露了漏洞。他们基本上在一小时内回复,并在同一天邀请我与OPC基金会成员会面。这是一个非常迅速的响应,与我习惯的情况有些不同。他们基本上完成了将所有漏洞协调给所有这些不同供应商的艰巨工作,让所有这些供应商首先就如何处理这些棘手的密钥问题达成一致,并在相对较短的时间内实施补丁,这真的令人印象深刻,我真的很佩服基金会所做的努力。

发布了一些CVE。可能有点令人困惑的是,一些供应商使用他们自己的

Nostr 去中心化协议的实际攻击分析 🔓

在本课程中,我们将学习一个名为 Nostr 的去中心化、抗审查协议。我们将探讨其设计原理,并深入分析在实际客户端实现中发现的安全漏洞。这些漏洞并非理论上的,而是可以被实际利用的。我们将通过具体的攻击示例和代码片段,理解这些漏洞如何破坏数据的完整性机密性可用性


背景介绍

中心化的社交媒体平台可以随时更改政策或审查内容。因此,出现了像 Mastodon、Bluesky 和 Nostr 这样的替代方案,它们旨在让用户控制自己的数据和身份。

本次研究聚焦于 Nostr,这是一个基于密码学的分布式社交网络协议。

分布式社交网络主要有两种模型:

  • 联邦模型:例如 Mastodon,不同的服务器相互连接,但用户身份仍然锚定在特定服务器上。
  • 自托管模型:例如 Nostr,用户持有自己的密钥,身份不由服务器拥有。服务器仅负责中继消息。

在 Nostr 模型中,信任的重心转移到了客户端验证上。这带来了自由,但也将所有责任转移给了用户。这引出了两个核心问题:

  1. 在没有中心服务器的情况下,客户端能否正确验证消息?
  2. 这种模型是否会带来新的攻击面?

我们通过深入研究 Nostr 的规范和客户端代码验证来回答这些问题。


Nostr 协议概述

Nostr 是一个简单、开放、无中心服务器的协议。用户拥有私钥,公钥即其身份。目前有超过 110 万用户账户,任何人都可以运行中继服务器,用户可以选择应用商店中的任何客户端。

它支持以下功能:

  • 公开帖子
  • 个人资料
  • 加密私信
  • 小额支付
  • 多设备签名

Nostr 规范包含一系列模块,旨在使不同的实现能够互操作。从密码学角度看,关键的规范包括:

  • NIP-01:定义了基础事件结构、中继和加密签名。
  • NIP-04:定义了使用 ECDH 密钥协商和 AES-CBC 加密的私信。
  • NIP-46:用于多设备签名,其加密结构与私信类似。
  • NIP-57:提供小额支付功能。


研究发现概览

我们的研究主要有三项贡献:

  1. 我们分析了 56 个中继服务器和 9 个客户端(包括开源和专有软件),发现了 7 个漏洞,并演示了 8 种攻击手法。
  2. 我们为每个漏洞构建了概念验证,并成功实施了破坏机密性、完整性和可用性的攻击。
  3. 我们提出了缓解措施,并与开发者合作了两年多来修复这些问题。

我们将发现的漏洞分为三大类:

  • 完整性破坏
  • 加密私信的机密性破坏
  • 小额支付劫持

这些都不是理论漏洞,而是可以实现实际攻击的。


攻击演示

以下是三种攻击的概念验证演示:

1. 伪造 Nostr 事件
攻击者可以轻易创建并广播伪造的事件。在演示中,伪造的事件成功出现在受害者的客户端屏幕上。

2. 破坏加密私信的机密性
攻击者可以篡改加密的私信内容。在演示中,攻击者将消息中的 URL 替换为包含自己服务器地址的恶意链接。当受害者客户端尝试预览该链接时,其中的秘密令牌(如认证令牌)就被发送到了攻击者的服务器。

3. 劫持小额支付
这是伪造事件攻击和篡改私信攻击的组合。攻击者拦截包含受害者比特币地址的个人资料事件,将其替换为自己的地址。当用户试图向受害者付款时,资金实际上被发送给了攻击者。


漏洞根源分析

要理解这些漏洞,我们需要从设计和实现两个层面来看。

设计层面:

  • 协议视图密钥管理是一个重大问题。
  • 像 AES-CBC 这样的加密模式选择也存在重大问题。

实现层面:
存在一些常见错误,包括:

  • 跳过签名验证
  • 不完整的验证逻辑
  • 缓存验证违规

这些错误出现在不同开发者开发的不同客户端中。我们认为,部分原因是规范中某些部分不够清晰,导致不同客户端行为不一致,从而放大了安全风险。


具体漏洞剖析

上一节我们概述了攻击类型,本节我们将深入每个漏洞的具体实现细节。

1. 签名验证缺失

首先,我们来看看 Nostr 中签名验证的正常流程。
每个事件都应由作者的私钥签名。例如,Alice 使用她的私钥签名一个事件。Bob 收到后,应使用 Alice 的公钥验证该事件。

核心问题在于:Nostr 规范并未强制要求中继服务器验证签名。
一些中继服务器会进行验证,但这主要是为了防止垃圾信息,而非为了保护客户端。规范明确指出,服务器无需被信任。

因此,我们假设服务器不验证签名,事件直接从发送者中继到接收者。

以下是实际客户端实现中的一个简单示例,许多客户端甚至省略了签名检查:

# 伪代码示例:缺少签名验证的客户端
def receive_event(event):
    # 许多客户端直接处理事件,跳过了 verify_signature(event) 步骤
    display_event(event)

这对于个人资料事件尤其危险,因为个人资料中可能包含用户的比特币地址。缺乏签名强制执行,使得恶意事件能够在网络中传播。

小结: 缺乏签名验证是一个简单但影响巨大的问题,它为多种攻击打开了大门。


2. 利用缓存绕过签名验证

接下来,我们看看另一种情况:客户端虽然实现了签名验证逻辑,但存在可被绕过的缺陷。我们以流行的 Nostr 客户端 damus 为例。

起初,damus 似乎有正确的签名验证逻辑。但经过分析,我们发现它在验证前会先检查缓存:

# 伪代码:damus 的缓存检查逻辑
def verify_event(event):
    if event.id in cache and cache[event.id].verified:
        return True # 如果缓存中存在且已验证过,则直接返回真
    # 否则,执行标准的密码学签名验证
    return standard_crypto_verify(event)

攻击链可以总结如下:

  1. 当事件不在缓存中时,damus 会进行严格的密码学验证。
  2. 攻击者需要控制决策点,使验证函数在未经验证的情况下返回 True
  3. 攻击者通过注入一个具有伪造内容但相同事件ID的事件来实现这一点。事件ID是事件内容的哈希值。

攻击步骤:

  1. 正常通信:Bob 收到 Alice 的真实事件 Event_A,其 ID 为 ID_A,内容包含 Alice 的比特币地址。
  2. 攻击:攻击者创建一个伪造事件 Event_A‘,其内容被替换为攻击者的比特币地址,但保持事件 ID ID_A 不变(这意味着攻击者需要精心构造内容,使其哈希值与原来相同,这通常通过暴力碰撞实现,对于短文本是可行的)。
  3. 当 Bob 收到这个伪造事件时,客户端在缓存中找到了 ID_A,并认为它已经过验证,于是直接接受了伪造的内容。

小结: 将缓存机制与验证逻辑错误地结合,可能导致签名验证被完全绕过。


3. 密文完整性破坏 (AES-CBC 问题)

在中心化平台中,即使密码学检查失败,服务器仍可能提供帮助。但在 Nostr 这种完全自托管的去中心化系统中,客户端必须在设备上自行检查所有内容。这对分布式社交网络的安全性提出了更高要求。

一个简单但严重的问题是加密私信的完整性。NIP-04 使用 ECDH 进行密钥交换,使用 AES-CBC 进行加密。但正如我们所见,许多客户端跳过了签名验证。这意味着私信只是经过 AES-CBC 加密,没有任何完整性保护

攻击者可能想将消息 “Send Bob 1 BTC” 改为 “Send Attacker 1 BTC”。虽然他们没有共享密钥,但在 CBC 模式下,攻击者可以通过修改密文来操纵解密后的明文。

CBC 模式的工作原理是: 每个明文块在加密前会与前一个密文块进行异或操作。
攻击者翻转初始向量或前一个密文块中的某些位,可以导致解密出的对应明文块发生可预测的位翻转,而无需知道密钥。

有两种利用方式:

  • 随机前缀攻击:攻击者无法控制修改结果,解密出的明文是乱码。
  • 非随机前缀攻击:如果攻击者能控制或预测明文的前缀(例如固定的消息开头 “Hi, ”),他们就可以计算差异,从而注入特定消息。

关键在于如何在真实系统中获得或控制明文前缀。我们的解决方案是跨协议攻击
例如,利用 Nostr 的 NIP-46(远程签名)协议。在该协议中,授权过程会建立一个会话并加密一些已知的元数据。攻击者可以从这个会话中获取到已知的明文和对应的密文,从而为攻击其他私信会话创造条件。

本节要点:

  1. 必须使用认证加密或消息认证码来提供密文完整性。
  2. 必须为不同协议使用不同的密钥。

4. 通过链接预览破坏机密性

在讨论具体攻击前,我们先了解链接预览功能。许多 Nostr 客户端支持自动链接预览,即当消息包含 URL 时,客户端会尝试获取该网页的元数据。

预览生成有两种方式:

  • 服务器端生成:由客户端后台服务生成。
  • 客户端生成:由接收者设备生成。

已知的问题是,接收者生成的预览可能泄露隐私,但这通常不直接破坏机密性。我们思考:这种行为是否能帮助攻击者恢复加密私信中的明文?

答案是肯定的。即使加密算法本身是强安全的,我们也可以利用链接预览作为“预言机”。

攻击场景: 私信中包含一个敏感 URL,例如会议邀请链接或云存储共享链接,其中包含秘密令牌。

攻击步骤:

  1. 攻击者拦截加密私信。
  2. 利用 CBC 的位翻转特性,篡改密文,使得解密后的 URL 域名部分指向攻击者控制的服务器(例如,将 example.com/secret-token 变为 attacker.com/secret-token)。
  3. 受害者客户端解密消息后,尝试为这个 URL 生成预览,于是向 attacker.com 发起请求。
  4. 攻击者的服务器收到请求,从而获得了 URL 中的秘密令牌。

更进一步:恢复非 URL 明文
如果攻击者想恢复消息中 URL 之外的普通文本怎么办?
假设攻击者知道消息以 “https” 开头,但不知道前三个字节的具体内容。他可以:

  1. 通过翻转 IV 中的位,暴力猜测并强制解密后的第一个字节变为 ‘h’。
  2. 观察受害者客户端是否向攻击者服务器发起 “http” 请求(因为解密后以 ‘h’ 开头,客户端可能错误地尝试将其作为链接预览)。
  3. 重复此过程,依次猜测第二个、第三个字节,最终可以逐字节恢复出完整的明文前缀。

本节要点: 与密文完整性一样,客户端侧的链接预览功能可能泄露隐私信息,甚至帮助攻击者恢复加密消息内容。必须谨慎处理此类功能。


总结与启示

本节课我们一起学习了针对 Nostr 协议的深入安全分析,涵盖了密码学设计和实现缺陷。

主要发现总结:

  1. 去中心化放大了风险:责任转移到客户端,但许多客户端未能履行验证职责。
  2. 实际攻击路径:我们演示了如何伪造事件和资料、利用 CBC 模式篡改密文、通过链接预览窃取令牌和恢复明文。这些问题源于有缺陷的设计和实现。
  3. 强密码学并不足够:我们的结果表明,仅靠强大的密码学算法是不够的,需要安全的协议设计、清晰的规范和正确的代码实现。

如何设计更安全的去中心化系统:

  • 清晰的规范:规范必须明确规定如何以及何时进行签名验证,而不仅仅是“应该”验证。
  • 密钥分离:客户端必须为消息、身份和远程签名等不同用途使用不同的密钥。
  • 零信任客户端:客户端必须验证来自中继服务器的所有内容。协议应用密码学替代信任。
  • 升级挑战:去中心化系统的更新比中心化系统更耗时,因为涉及众多独立的中继服务器和由不同社区开发的各种客户端实现。因此,从一开始就做好设计至关重要。

最终结论: 构建安全的去中心化系统,不仅需要强大的密码学基础,更需要良好的代码实践和审慎的密码学协议设计。

失控:KCFG与KCET如何重新定义Windows内核控制流完整性 🛡️

在本节课中,我们将学习Windows内核中的控制流完整性缓解措施。我们将探讨它们的重要性、工作原理,并重点分析这些措施在内核模式下的实现,与其在用户模式下的实现有何不同。


概述

控制流完整性旨在解决现代漏洞利用的一个核心前提:攻击者需要能够改变程序的合法控制流。我们将首先了解CFI要解决的问题,然后深入探讨Windows用户模式下的经典实现——控制流防护,以及其硬件增强版本——控制流强制技术。最后,我们将聚焦于这些技术在内核模式下的实现,即内核CFG和内核CET,并分析它们如何利用基于虚拟化的安全技术来应对更高权限的攻击者。


CFI旨在解决什么问题?🎯

在深入CFI本身之前,有必要先看看CFI旨在解决什么问题。

当今大多数试图执行未签名代码的漏洞利用通常需要两样东西。

首先,需要有能力诱使目标程序执行一条它本不会执行的代码路径。

其次,利用同样的能力,将数据加载到目标程序中,并让操作系统或应用程序将这些数据当作代码来执行。

因此,CFI试图解决漏洞利用的第一个原则,即验证并缓解任何试图改变目标程序合法控制流的尝试。


用户模式CFI:控制流防护 🛡️

Windows中典型的例子是控制流防护,它自Windows 8.1起在用户模式中引入,这是微软实现的前向边缘CFI缓解措施,用于防护间接调用和跳转。

CFG的工作方式是在编译时,所有已知的间接调用目标都存储在一个位图中。这个位图是只读的,并且是每个进程独有的。每当发生间接调用或跳转时,我们首先查询位图,以获取关于即将调用的目标地址的更多信息。

就我们的目的而言,CFG位图的状态实际上就是“允许”或“不允许”。其具体表现形式略有不同,因为位图经过了一些内存管理器优化以压缩大小,并且根据编译器生成调用目标边界的方式,我们实际上需要两位来表示。但如前所述,就我们的理解而言,它就是允许或不允许。

以下是CFG出现前后的对比示意图。

在CFG出现之前,假设有一个漏洞利用,例如针对C++或浏览器。对象有一个虚函数表,其中包含一系列函数。拥有读写权限的攻击者可以定位这个虚函数表,覆盖其中的一个条目,然后诱使应用程序调用该函数。显然,在这种情况下,我们不会调用合法的目标,而是会跳转到ROP gadget或栈转移指令,从而偏离了正常的控制流。

在CFG出现之后,漏洞利用的步骤基本不变。但在调用任意目标之前,我们会先检查CFG:使用目标地址作为索引查询位图,获取相关的位状态,然后判断是否应该真正执行这个调用,还是应该终止进程。

由此可见,CFG确实对漏洞利用产生了影响。但攻击者总是选择阻力最小的路径。与其费心绕过CFG的实现,不如寻找其他不受CFG保护的控制流转移方式。


用户模式CFI的挑战:返回地址与CET 🔄

一个显而易见的突破口就是栈上的返回地址。栈上有一系列返回地址,函数执行完毕后会依次弹出。最终,某个返回地址被取出,导致执行流偏离到内存中的其他位置。

微软显然从一开始就知道这个问题,甚至在开发CFG时就提出了一个基于软件的解决方案,称为返回流防护。但由于其内部红队的发现,该方案被弃用了。因为该缓解措施的“真相源”几乎可以被确定性地泄露。微软做出了正确的决定,他们认识到无法在软件层面完美解决这个问题,因此决定等待基于硬件的缓解措施成熟。

英特尔的实现称为控制流强制技术,特别是其中的影子栈功能。Windows也支持AMD的等效功能。自Windows 10 1903起,用户模式CET已可用。

CET是一种硬件缓解措施,因此需要更新的处理器。这些处理器引入了一个新的架构寄存器——影子栈指针。SSP不能作为内存操作的源或目的操作数被编码。特别是对于用户模式CET,有一条特殊的指令WRUSS只能在处理器运行于当前特权级0时执行。因此,对于用户模式攻击者而言,影子栈是完全不可变的。

每当发生调用时,除了更新指令指针和将返回地址压入常规栈,我们现在还会将返回地址压入这个不可变的影子栈。每当发生返回时,我们同时从影子栈和常规栈弹出返回地址并进行比较。如果两者不匹配,CPU会触发一个特殊的中断。


从用户模式到内核模式的挑战 ⚠️

显然,这些缓解措施极大地阻碍了漏洞利用。但你可能已经注意到一些问题。

那就是,这两者都依赖于一个给定的“真相源”。例如,用户模式CET和用户模式CFG都受到用户-内核安全边界的保护。如果你想写入影子栈,要么需要某种方式请求内核使其可写,要么需要能够在处理器运行于内核模式时执行那个特殊操作码。位图也是如此,你需要某种方式使其可写,这通常通过系统调用实现。

但是,如果你首先就有能力执行代码来做这些事,那么这些缓解措施对你来说就形同虚设。我们依赖用户-内核安全边界。

问题在于,如果你试图针对内核模式攻击者实现这些缓解措施,但缓解措施本身与你要防御的攻击者处于相同的特权边界内,那么你的缓解措施显然不会有好结果。


基于虚拟化的安全:更高的边界 🏰

幸运的是,Windows实际上有一个更高的安全边界,那就是Windows Hyper-V 管理程序。

微软在“基于虚拟化的安全”这一总称下实现了一系列功能,这为CFG和CET等机制的“真相源”提供了保障。

VBS的工作原理是利用第二层地址转换。虚拟机位于物理内存的隔离区域中。VM1和VM2访问它们认为是物理地址1000的内存,但实际机器上只有一个物理地址1000。因此,虚拟机在自身上下文中访问内存,并通过一个次级机制执行最终级别的转换,将虚拟地址映射到真实的系统物理内存。

利用这一点,我们可以将操作系统划分为两个“虚拟信任等级”。VTL 0是我们的正常世界,即典型的内核页表,也就是我们熟知的Windows。现在我们还有安全世界,即VTL 1。它被称为安全世界,并非因为它天生安全,而是因为它被允许对VTL 0的安全策略施加影响。

我们将要分析的一个例子是内核数据保护。这是VBS下较新的缓解措施,它有效地保证了VTL 0(即正常Windows运行的地方)中的某个内存区域始终保持只读,无论攻击者是否拥有内核模式的读写权限。

再次假设有一个内核漏洞利用。我们在用户模式下运行,并泄露了KDP保护内存区域的关联内存。我们定位其关联的页表项并将其标记为可写。现在我们去执行写操作。但这个写操作发生在VTL 0中,VTL 0就像一个虚拟机。因此,该内存访问被委托给管理程序,由管理程序执行额外的转换级别。

KDP所做的是为VTL 0设置一个只读的EPT条目,表明该页面实际上是只读的。这些权限通过只有管理程序才能访问的扩展页表条目来体现。因此,在这种情况下,即使内核模式攻击者将常规内核管理的PTE标记为可写,扩展页表条目作为最终的真相源,仍然规定其为只读。这实际上等同于向只读内存区域写入,会导致EPT违规,机器将崩溃。

由此可见,我们确实有办法保证VTL 0(传统内核)中内存的完整性。但事情并非简单地将用户模式的实现照搬到内核模式并加上一些管理程序功能那么简单。


内核模式CFG的实现 🧩

工程师们必须考虑很多事情。一个例子是VM退出。当处理器在客户机上下文中运行时,客户机调用管理程序的服务,这有点像系统调用。然后处理器切换到VMM模式或管理程序模式运行。这会产生上下文切换,处理器必须更新其状态等。这绝非免费操作。因此,仅仅请求管理程序服务就可能引发VM退出,这是我们必须牢记的。

基于此,现在让我们来看看这些缓解措施在内核模式下的实现。

首先,内核模式CFG出现在Windows 10 Redstone 2中。用户模式CFG作为可选更新出现在Windows 8.1中,而内核模式的实现则花了更长时间。

KCFG仅在启用了基于虚拟化的安全的另一项功能——管理程序保护的代码完整性时才会完全启用。HVCI的工作方式与KDP类似,它试图保证VTL 0中内存的完整性,但它关注的是被指定为代码的页面变成数据页面,或者数据页面变成代码页面。这是未签名代码执行的两个先决条件。

以下是KCFG的工作流程。

NT内核仍然负责指定内核模式CFG位图的存放位置。只有一个内核模式CFG位图。每个进程都有自己的CFG位图,但内核模式地址空间是共享的,因此有一个2TB的内存区域是所有镜像共享的内核模式CFG位图。

NT内核在初始化时负责确定其位置,并通过一种称为安全系统调用的机制通知安全内核。因为常规内核和安全内核是物理内存的隔离区域,它们彼此不知道对方的布局。

这个安全系统调用通过超级调用接口进行。因此,在初始化时,安全内核通过一个NT地址范围结构来跟踪与位图关联的内存区域。NR结构允许安全内核标记:“我知道这个内存区域很重要,它位于常规内核中,我需要管理它。”

通常,每个内核模式镜像加载都会创建一个NR结构,其中包含该镜像所有可执行代码的内存范围。但我们也有不直接与内核模式镜像绑定的特殊项,例如CFG位图或影子栈。这些是安全内核需要知道的内存区域,它们被称为静态NR。

在安全内核接收到位图位置信息后,后续的每个镜像加载都会发生以下步骤。

每个支持CFG编译的内核模式镜像加载时,都会从位图范围进行新的分配。显然,我们无法一次性提交2TB内存,这会耗尽提交限制,且大多数系统不支持。因此,一个优化措施是:先保留2TB地址空间,然后随着镜像的后续加载按需分配。

然后,该分配在VTL 0的EPT中被标记为只读。因此,即使攻击者在VTL 0中拥有内核模式读写权限,他们可以将页表项标记为可写,但由于管理程序负责设置只读的EPT条目,所以它实际上并不可写。

此外,新分配中的相关位状态会被更新,以标记需要跟踪的间接调用目标。

在此屏幕截图中,我使用源点JTAG调试器调试安全内核,可以看到一个超级调用正在发生,其掩码为GPA可读,从而设置了只读的EPT条目。


KCFG的局限性与绕过 🕳️

我们不仅需要关心位图本身。例如,考虑用户模式下的GetProcAddress调用。你提供一个字符串,导出的函数地址会返回给你。然后你可能会调用那个内存地址。由于这是通过函数指针进行的间接调用,而间接调用受CFG检查,但通过GetProcAddress解析出的调用目标在编译时是未知的,因此它不是一个有效的调用目标。

这里的要点是,内核模式下等效的GetProcAddressMmGetSystemRoutineAddress。如果你调用这个函数,调用目标会自动在位图中被标记为有效,这很有趣。

到目前为止,我还没有过多讨论漏洞利用,但CFG的一个已知弱点是它是一种粗粒度的CFI缓解措施。这意味着CFG并不验证你调用的目标是否是开发者预期的目标。它只是获取调用目标的地址,在位图中查找,如果有效,就跳转执行。

由于整个CFG位图被所有内核模式镜像共享,没有什么能阻止我们,例如,在win32k的间接调用中,用一个来自NTNTFS等其他地方的有效调用目标覆盖原有的调用目标。因此,你显然仍然可以调用其他函数。

微软从一开始就知道这个问题,并最终提出了扩展控制流防护的解决方案。XFG在编译时创建函数原型的哈希,包括参数数量、参数类型、返回值和返回类型。这些信息在理论上对于给定函数应该是唯一的,并被放置在每个调用目标的上方。当间接调用发生时,我们获取调用点的XFG哈希,并与预期的哈希进行比较,如果不匹配,则发生CFG违规。

不幸的是,尽管这将“有效调用目标”的范围缩小到了“开发者预期的目标”,但XFG已被弃用,不再使用。

那么,内核CFG的现状如何?没有XFG,它就像普通的CFG一样工作。由于Windows中引入了一项称为热修补的新功能,其机制略有不同。这意味着不再通过间接调用来调用分发函数,而是被修复为一个新的分发函数,并通过直接调用进行。这里还有更多细节,但值得指出。


KCFG的其他方面与绕过技巧 🧠

另一个有趣的注意事项是,内核CFG充当了软件SMEP的角色。过去,内核模式攻击者会分配一些用户模式内存,使用内核中的读写权限破坏一个函数指针,使其指向该用户模式内存,然后诱使内核调用那个被破坏的函数指针,从而将执行重定向到用户模式。这里唯一的问题是处理器仍然在内核上下文中运行,因此用户模式内存是以内核权限执行的。

KCFG,即使HVCI被禁用,也几乎是一个空操作,但有一个例外:对地址进行位测试,如果它是用户模式地址,即使HVCI未启用,我们仍然会使机器崩溃。

攻击者知道的另一件事是,导入地址表在CFG的文档中被明确指出不受保护。

在这种情况下,我们再次进行内核模式漏洞利用。我们在用户模式下运行,拥有内核模式读写权限。我们定位与driver.sys关联的导入表。在这种情况下,我们破坏PTE将其标记为可写。你可能会想,HVCI应该会起作用。你怎么能破坏这些页表呢?再次强调,HVCI关注的是代码变成数据或数据变成代码。导入表是一个数据内存区域,它只是变成了可写。因此,HVCI不关心这个。我们用ROP gadget破坏导入条目,然后诱使内核调用这个导入。因此,我们调用ExAllocatePool2,它会进行内存读取以获取它认为是ExAllocatePool2的地址,但实际上是ROP gadget。因此,即使启用了CFG,我们也调用了ROP gadget。


与Retpoline的交互 🔗

实际上,你可以将内核CFG与一个不太知名、不直接相关的缓解措施Retpoline结合起来。Retpoline旨在缓解一种称为Spectre v2的CPU分支预测漏洞。较新的CPU可以防御此漏洞,因此Retpoline现在已不太使用或讨论。

但就我们的目的而言,Retpoline所做的一件事是,它修补或修复了所有对导入表的间接调用,使它们变成直接调用,并指向一个特殊的Retpoline分发函数。但在99%的情况下,一个称为导入优化的附加功能实际上会导致它直接调用导入表。

在此屏幕截图中,我们可以看到,来自NTFS的调用是调用NtZwClose,但它不是通过间接调用进行的,而是通过相对调用进行的。即使较新的CPU不使用Retpoline,所有Windows镜像仍然为Retpoline支持而编译。因此,你得到了导入被修复为直接调用的好处。

我喜欢指出的一个有趣之处是它的实现方式。有一个称为动态值重定位表的功能。早在Windows 10 1607时,像PFN数据库、PTE数据库这样的分页结构的静态地址最终被随机化了。实现这一目标的方式是通过这个特殊功能,它得到了安全和编译器团队的支持,允许你将一个静态值重定位到其他值,从而实现随机化。Retpoline使用了DVRT的扩展,允许所有这些修复发生,我认为这非常有趣。

这对我们来说意味着我们不再需要从导入表读取。因此,在这种情况下,我为本次会议演讲编写了一个驱动程序。它通过导入表对ExAllocatePool2进行了一次调用。

但在调试器中,在R10寄存器中,我已经用一个任意的读写权限将该条目破坏为0x41414141。如果没有Retpoline支持,我们就会简单地调用0x41414141,因为这就是导入条目中的内容,然后我们会崩溃。但在这种情况下,你可以注意到没有崩溃,并且返回值中有一个有效的池块。这是因为,我们不需要对导入表进行内存读取。因此,无论攻击者是否破坏它,镜像加载时导入表中的内容都保持不变。指出这一点的意义在于,内核CFG的一个已知局限性实际上受到了Retpoline的保护。


转向内核CET:保护返回地址 🛡️

显然,攻击者可以做诸如覆盖返回地址之类的事情。在这种情况下,我有一个线程。该线程处于挂起状态,这意味着有一个异步过程调用排队告诉该线程:什么也不做。

然后,我使用内核模式读写权限破坏栈上的一个返回地址,用一个简单的ROP gadget替换它。当这个线程恢复时,栈将展开,我的ROP gadget显然会被执行。

这首先由一种称为“内核锻造”的技术概述。因此,我们显然仍然可以覆盖栈上的返回地址。

这正是内核模式CET的用武之地。现在返回地址受到了保护。

内核CET与内核模式CFG略有不同,它不是二元的。CFG是二元的,要么开启要么关闭。你需要编译支持。但对于CET,有一种称为审计模式的东西,你可以有效地将机器置于审计模式。当发生控制流保护故障时,中断处理程序不会直接蓝屏死机,而是会修复影子栈或其他需要的东西。最重要的是,它会发出一个Windows事件跟踪事件,你可以获取更多关于此次CET违规原因的信息。

如前所述,我们仍然需要HVCI。


内核CET的实现细节 ⚙️

与所有内核模式影子栈关联的内存区域仍然由NT管理。有些情况下我们需要内核模式影子栈,例如中断服务例程或DPC。但最典型的例子是线程创建。每当你创建一个线程,你就有一个关联的栈。那么,如果你有一个关联的栈,你现在就有一个关联的内核模式影子栈。

常见的例子是:线程被创建,新栈被创建,然后我们需要创建影子栈。我们通过安全系统调用接口内联调用安全内核,通知安全内核:“我们希望这个新的影子栈分配在这里,请将其标记为只读。”但此外,还有一个特殊的位,我们稍后会讨论,称为超级影子栈位,它是英特尔超级影子栈控制功能的一部分。

如前所述,每个线程创建都需要一个影子栈。如果每个线程创建都需要一个影子栈,那就意味着每个线程创建现在都会导致对安全内核的调用,而安全内核会做什么?它会进行超级调用并引发VM退出。如果我们不必这样做,我们并不想每次都这样做。

因此,NT管理着两个缓存。请放心,此缓存中的所有成员都至少走过一次慢路径。因此,它们在VTL 0的EPT中都是只读的。

我们有两种缓存:每处理器缓存和每NUMA节点缓存。NUMA节点实际上是关联到一定内存范围的处理器分组。

发生的情况是,如果条件合适,我们将不再需要的旧影子栈发送到这些缓存之一。这样做的原因是线程通常有一个理想处理器或理想NUMA节点。分配通常会被缓存在它们被发出或执行的处理器上。这里的想法是,如果我们可以将这些影子栈缓存在一个处理器或NUMA节点上,我们可能获得性能提升,因为当我们需要获取一个新的影子栈时,该内存可能已经缓存在给定的处理器上。

因此,我们有两个缓存

关注线索:LLM在真实世界恶意软件分析中的线索驱动逆向工程 🕵️♂️

在本节课中,我们将学习如何利用大型语言模型进行稳健且可靠的恶意软件逆向工程。我们将介绍一种名为“线索驱动”的方法,该方法通过检测LLM的“幻觉”来确保分析结果的准确性,并构建一个自动化分析系统。


引言:逆向工程的挑战与LLM的幻觉

大家好。在演讲开始前,我有一个问题。请举手示意,如果你热爱逆向工程,特别是恶意软件分析。看来有很多人。但似乎也有很多人没有举手。这意味着你不喜欢逆向工程。你讨厌逆向工程。这没关系。我也讨厌逆向工程。我认为你们来对了地方,因为今天我将展示如何构建一个没有逆向工程痛苦的世界。

今天,我们的演讲主题是“关注线索”。我们将介绍如何让语言模型能够非常稳健和可靠地进行逆向工程。

现在,让我介绍一下自己。我叫谭驰,是Scraft公司的研究团队负责人。Scraft是一家专注于网络安全的人工智能公司。我的研究重点集中在人工智能和语言模型上。

这是我的联合演讲者,魏杰。他是一名高级网络安全研究员,也是恶意软件分析专家。实际上,今天我们将介绍的系统,是我试图通过语言模型克隆另一个魏杰。

第三位贡献者是赵明。他是一名网络安全研究员,同样专注于恶意软件分析和二进制自动化分析。

让我们开始吧。在演讲开始时,我想让每个人都真正理解语言模型面临什么样的挑战。我需要大家为我做点事。请假装你是语言模型两分钟。

这是系统提示:请扮演一名专业的恶意软件逆向工程师,尝试重命名变量 V1。现在,是时候生成答案了。请告诉我你的答案,如果你认为是 A、B、C 或 D。

看来很多人都认为答案是 C。让我们看看。正确,很好。

接下来是第二轮。请重命名变量 V3。请举手示意,如果你认为答案是 A、B、C 或 D。看来有些人认为是 C,有些人认为是 D。让我们看看。哦,答案不是它们中的任何一个。正确的答案是不要举手。

我们很容易忘记,当我们面对我给出的提示时,我们总是有选择权。这对于语言模型来说也是如此,它倾向于生成最可能的答案,也更容易犯这种错误。

接下来,我们将看看为什么“面积”不是正确答案,以及这种错误会带来什么影响。

首先,我们可以看到这个代码块。这是语言模型的输出。它看起来非常合理,将 V3 重命名为“面积”。但当我们深入研究 sub_ 函数时,我们可以看到,它实际上不是计算面积,而是检查面积。语言模型不知道这一点,没有这个上下文。它试图生成答案,并在重命名局部变量 V3 时出现了一些错误。

这种错误不会在这里停止。它开始传播到 then 函数,然后 then 函数也传播到 color 函数,color 函数给出了错误的结果。我们可以看到,这个单一的错误,就像一个滚雪球,变得越来越大,直到我们对整个程序产生完全误解。

那么,什么样的语言模型会犯这种错误呢?




你可以看到,所有最先进的 R 语言模型都没有拒绝回答问题。它们都认为 V3 是结果面积。基于此,它们导致了我刚才提出的问题中的错误。

这种错误在恶意分析场景中尤其危险,因为我们没有恶意软件的“基本事实”。恶意软件作者不会告诉我们我们的理解是否正确。因此,人类需要花费大量时间和精力来验证语言模型得到的结果。这会让我们更难提前下班。

为了让语言模型成为我们的好伙伴,让我们能够提前下班,我们需要知道它何时在“幻觉”,何时在“撒谎”。

这就成了我们需要解决的快速问题。


现有策略的局限性

根据 OpenAI 的优化指南,有两个主要策略:语言模型优化和上下文优化。大多数与逆向工程相关的主题都集中在这两种策略上,但这两种策略无法修复“幻觉”问题,因为它们都是单一来源信任。

单一来源信任的问题是,我们不能盲目信任语言模型的输出,即使它声称有很高的置信度。那么我们如何知道语言模型是否处于“幻觉”状态呢?我们需要退回到人类场景。


灵感来源:人类调查策略

即使没有人被 FBI 逮捕或调查过,我想大家都看过一些关于 FBI 的电影。大家都知道,FBI 有两种主要策略来判断某人是否在撒谎。

第一种是“参考检查”。通过参考检查,我们不只是信任单一来源。我们会去收集证据和外部线索,把它们放在一起,看看故事是否一致。

对于“测谎仪”,调查人员会在询问某人时监控信号,比如压力或心率,以判断某人是否在撒谎。这两种策略都非常有用。

接下来,我们将看看如何将这种策略引入语言模型领域。


方法一:参考检查——利用注意力机制

在我们深入之前,这是现代语言模型 Transformer 的架构。其中有一种称为“注意力”的机制。这就是我们如何进行参考检查。接下来,我们使用 softmax 来进行测谎。我们将重点介绍这两种不同的方法。

首先,让我们看看参考检查是如何进行的。

在参考检查中,我们需要知道什么是注意力。注意力是语言模型内部的一种机制,帮助语言模型知道它需要关注哪些标记。在现代语言模型中,有多个层,每层有多个注意力头。因此,有几十种不同的注意力头。

有些注意力头执行类似句法的功能。它们关注语法和结构。

有些可能像这样。它是一个代词,所以它会关注它代表什么。而“past”是动词,所以它会关注宾语和主语。还有其他类型的注意力头,比如更高级的句法头。其中一个句法头可能关注推理。它会发现“harder”关注“past”,因为“past”是测试未通过的原因。

是的,有很多不同类型的注意力头。但我们感兴趣的注意力头是,它能告诉我们模型在生成答案时关注了哪些信息。我们希望找到这种注意力头。如果这种注意力头存在的话。

让我们考虑一下这篇来自顶级 AI 会议的论文。在这篇论文中,他们使用复制和粘贴操作来找到一种称为“检索头”的注意力头。这种注意力头会在执行复制和粘贴时,检索它想要复制的标记。

但今天,我们不是在做复制和粘贴。我们是在重命名变量。所以我们需要找到另一种注意力头。我们称之为“线索焦点注意力头”。以下是我们如何找到线索焦点注意力头。

首先,我们需要识别高信息量的线索。接下来,我们将执行我们的任务。记住,我们的任务是重命名变量和函数名。第三,在我们完成重命名任务后,我们还会查看模型内部的注意力,提取注意力,看看这个注意力头关注了什么。如果它关注我们在第一步中识别的线索,我们就给它高分。如果没有,我们就给它低分。通过这种方式,我们可以对它们进行排序和排名,得到一组线索焦点注意力头。

接下来,让我们看看我们的一个线索焦点注意力头是如何工作的。

我们可以看到,我们期望在这里可视化一个线索焦点注意力。我们发现,当我们输入代码时,右侧是生成的输出。在它生成 V1 的答案之前,它高度关注“width”。同样,对于 V2,当它输出 V2 的答案时,它也高度关注“height”。这种注意力集中在高信息量的线索上。

但是当我们上传 V3 时,我们可以看到 V3 没有高信息量的线索。所以它关注了一些随机的、不可用的东西。我们可以看到 V3 的答案不是基于某些信息线索,所以我们可以拒绝 V3,因为 V3 不可信。

此外,我们还对线索焦点注意力头在语言模型中的重要性感兴趣。所以我们进行了一项消融实验。在这个实验中,我们将关闭一些注意力头,并监控它对语言模型输出的影响。绿色表示输出正确,红色表示输出不正确。

我们可以看到,当我们随机关闭一些注意力头时,对语言模型的影响不大。但当我们关闭线索焦点注意力头时,它对语言模型输出的影响非常大。因此,我们可以知道线索焦点注意力头对语言模型非常重要。

在介绍了第一种方法——参考检查(利用注意力机制了解模型生成答案时关注的信息)之后,接下来我们将讨论测谎仪,即如何使用 softmax 层进行测谎。


方法二:测谎仪——利用Softmax概率分布

在 softmax 层,会有一个标记概率分布。我们可以看到,如果分布集中在一个标记上,这意味着答案可能只有一个。就像我们看到的例子,V1 的答案可能只有“width”。但是,当分布分散在不同的标记上时,这意味着答案可能是“area”,也可能是“result”。就像大家举手一样,有人认为“area”,有人认为“result”。语言模型也处于低置信度状态,对此感到困惑。这意味着我们可以知道它处于低置信度状态,并可以拒绝它的重命名。这就是我们的测谎仪。

至此,我们已经介绍了检测语言模型何时处于“幻觉”状态的两种主要方法。第一种是参考检查,第二种是测谎仪。


构建自动化系统:Celebi

现在,让我们把这两样东西放到我们的自动化工作流中。这就是我们要介绍的系统。

现在,让我介绍一下我们的系统,Celebi。这个系统的灵感来自宝可梦 Celebi。就像 Celebi 可以逆转时间一样,我们期望我们的系统能够将混淆的代码逆转回人类可读的源代码。

这是我们的分析流程。首先,输入是来自 IDA Pro 的反编译函数。第一步是预处理步骤。在这个步骤中,不涉及语言模型。我们将使用一些静态分析工具为我们生成线索。这些线索对后续步骤至关重要。

在第二步中,一旦我们有了这些线索,我们就可以使用我们的线索驱动策略来帮助我们决定需要先分析哪些函数。我们将对这些函数进行优先级排序和排序。我们知道我们想先分析哪个函数。

接下来,一旦我们知道要分析哪个函数,我们将要求语言模型帮助我们重写这些函数。我们将要求语言模型帮助我们重命名变量和函数名,并给出摘要。

一旦我们有了语言模型的输出,在最后一步,我们不会盲目信任结果。我们将使用前面提到的方法——测谎仪和参考检查——来评估结果。我们将拒绝那些低质量的重命名。最后,高质量的重命名本身也是新的线索。所以我们将更新我们的线索集,然后调整语义,最后重复这个过程。


案例研究:分析真实恶意软件

现在,让我通过一个案例研究来看看我们的系统如何对抗真实的恶意软件。

这个恶意软件来自中国 APT 41 组织。该恶意软件的核心技术是进程注入,注入到一个 EDR 进程中。这里有两个关键挑战。首先,这个恶意软件有超过 800 个函数,并且函数名被剥离了。所以有很多函数。其次,这个恶意软件有很多 Windows API 混淆,这些 API 只在运行时解析。

面对这些挑战,如果我们手动进行逆向工程,这将非常耗时且困难。

步骤一:线索提取与标注

让我们看看我们的系统是如何工作的。第一步,我们将看看我们在这里定义了哪些线索,以及我们如何生成这些线索。

我们将线索分为两种类型。第一种是内部线索,第二种是外部线索。对于内部线索,我们会高亮反编译函数中的模式,例如可疑字符串或可疑 API。这些线索对后续步骤有帮助。对于外部线索,我们会运行一些静态分析工具,比如仿真工具,尝试解析 Windows API 混淆。我们会在代码后面标记正确的 API。

其次,我们还会找到一些加密常量,比如 AES S-box 或其他如 SHA-1 函数,并在代码后面标记正确的算法名称。

例如,在这个恶意软件中,我们看到在第一行,我们的系统可以识别出像 agent.exe 这样的模式。在我们识别出这个模式后,我们的系统会在代码后面添加注释,添加一个可疑字符串。这样语言模型就能看到这里有些情况。

其次,对于接下来的几行,我们看到这里有一个 Windows API 调用,这个 API 被混淆了。所以在静态分析中,你看不到调用了哪个 API。但我们使用一些仿真工具,比如 CBEasy,来帮助我们解决这个问题,我们会在后面添加正确的 API 名称。例如,这里工具帮助我们添加了注释,如 OpenProcess,这样语言模型就能清楚地看到这个 API 是调用 OpenProcess 的。

步骤二:线索驱动的规划器

现在,我们有了线索。在第二步,我们将看看我们的规划器是如何工作的。

我们想要逆向整个二进制文件,而不仅仅是单个函数。因为这个恶意软件有超过 800 个函数。有很多函数,我们不知道从哪里开始,先看哪个函数。

如果你手动操作,过程会像这样:你会在函数中四处查看,看看哪个函数重要。最终,一旦你找到重要的函数,它们可能对你隐藏,不是因为它们是恶意的,而是因为它们被混淆了。

但好消息是,我们有线索。例如,在这里,你可以看到 2.9B 函数比其他函数有更多的线索。例如,agent.exeOpenProcessVirtualAllocEx,这些都是这个函数中的线索。显然,这个函数是我们分析的一个良好起点。

但我们如何量化这种行为?我们如何量化哪个函数比其他函数更重要?这里我们使用一个启发式评分函数来帮助我们计算分数。例如,第一行,可疑字符串会给 1 分。而 OpenProcess 会给 3 分。不同的线索有不同的重要性分数。最终,我们会得到这个函数的最终分数。例如,这里是 7.5。

一旦我们为每个函数计算了分数,我们就可以生成一个热图。这个热图可以帮助语言模型清楚地看到哪个函数重要。比如这里的 2.9B 函数是 7.5 分,非常重要。

但我们不只是先分析分数最高的函数。热图还会向语言模型提供已分析函数的历史记录。基于上下文,语言模型代理可以选择它想要分析哪个函数。例如,在分析了 inject_code 之后,它可能想分析 DLLMain,因为 DLLMain 调用了 inject_code,代理可能想看看它是如何调用的。

一旦我们分析了一个函数,被分析的函数也会成为强大的新线索。例如,这里的 inject_code 调用,在我们分析了 DLLMain 之后,我们会看到这个 inject_code 调用也是一个新线索。这样在某个时刻,你就知道 DLLMain 在做一些注入行为。所以我们会调整父函数的分数,并将这个线索传播给父函数。

最后,我们会为分析设置一个阈值,这样我们不会分析每一个函数。我们只分析选定的重要函数。这样,我们就不分析那些我们不关心的库函数或工具函数。我们只分析选定的函数,就能得到这个恶意软件的整体行为。这可以帮助我们节省标记,运行得更快。

步骤三:LLM重写与验证

现在,我们知道了我们的线索驱动策略是如何工作的。在第三步,我们将要求语言模型帮助我们重写这些函数。

总共有三个任务我们希望语言模型完成。第一,我们希望它重命名变量。第二,我们希望语言模型帮助我们重命名函数。最后,我们会要求语言模型给出关于这些函数的整体摘要。


在这个步骤之后

电动汽车充电桩安全与防护失效调查 🔌⚡

在本课程中,我们将深入探讨电动汽车充电桩的安全与防护问题。我们将分析其攻击面,回顾在安全竞赛中发现的漏洞,并通过实验研究当充电桩被恶意控制时可能引发的物理安全风险。课程最后将讨论可行的缓解措施。

攻击面概览 🎯

上一节我们介绍了课程主题,本节中我们来看看电动汽车充电桩的典型攻击面。

电动汽车充电桩通常包含以下核心组件:

  • 主处理器:运行操作系统(如Linux、Android或RTOS),负责用户界面、网络通信等主要子系统。
  • 辅助处理器:通常负责控制电源开关和测量。
  • 多种外围设备与连接:包括Wi-Fi、蓝牙、蜂窝网络、RFID读卡器、云连接等,共同构成了庞大的攻击面。

此外,充电桩通常配备移动应用程序。该应用程序用于配置Wi-Fi凭证(通过蓝牙传输给充电桩)、进行远程控制和遥测。对于安全研究人员而言,从分析应用程序入手是了解系统工作原理的有效途径。

Pwn2Own竞赛中的发现 🏆

了解了攻击面后,我们来看看在实际安全竞赛中发现了哪些问题。以下是我们在2024至2025年Pwn2Own竞赛中观察到的一些关键结果和漏洞类别。

关键发现:

  • 漏洞数量并未减少。
  • 新增了“充电协议修改”类别,参赛者若能篡改充电桩与车辆间的通信协议,将获得额外奖励。去年有4支队伍成功实现了这一点。
  • 新增了“充电接口直接入侵”类别,即通过充电枪的物理接口直接入侵充电桩。

漏洞类型统计(CWE分类):

  • CWE-121/122(缓冲区溢出):两年间共发现8-9个此类基础漏洞。
  • 其他高频漏洞:包括身份验证绕过、证书问题、命令注入等。

总体而言,发现的漏洞级别较低,反映了行业整体安全状况不容乐观。

深入分析竞赛案例 🕵️♂️

上一节我们概述了竞赛中的发现,本节我们来深入剖析几个具体案例。

以下是几个具有代表性的漏洞实例:

  1. 特斯拉壁挂连接器漏洞:攻击者使用树莓派和CAN控制器将固件降级到一个包含调试服务的旧版本。利用该调试服务获取Wi-Fi凭证后接入网络,再利用调试服务自身的全局缓冲区溢出漏洞(该设备无内存保护)实现远程代码执行。
    • 核心问题无内存保护机制
  2. 某品牌充电桩USB漏洞:该设备侧面的塑料挡板下有一个USB接口。攻击者发现其USB设置包存在越界读取漏洞。代码仅检查缓冲区长度非零,但未检查最大长度。缓冲区后方恰好是关键函数指针,通过写入这些指针即可控制程序流,同样由于缺乏内存保护而实现远程代码执行。
    • 核心代码逻辑if(buffer_len != 0) { copy_without_bounds_check(); }
  3. 某品牌充电桩RF卡漏洞:设备附带的用于恢复出厂设置的RFID管理卡是MIFARE Classic 1K卡,极易克隆。更严重的是,此卡能重置所有同型号充电桩。重置后,在配对过程中可提取固件加密密钥,并利用一个未公开的固件更新功能,通过发送加密的JSON数据包来安装恶意固件。
  4. 某品牌充电桩云服务漏洞:研究人员发现一个云服务漏洞,允许攻击者访问所有已连接的该品牌充电桩,并可能安装恶意固件。该漏洞修复耗时很长。

这些漏洞包括远程漏洞、本地漏洞乃至整个产品线被完全控制的漏洞。它们通常简单直接,无需利用漏洞链,且缺乏有效的缓解措施,令人担忧。

后续研究问题 ❓

在见证了Pwn2Own竞赛中的各种攻击后,我们提出了一系列更深入的研究问题。

我们已确认电动汽车充电桩存在广泛漏洞,攻击面多样,且充电协议可被篡改。同时,我们还需考虑电网和车辆电池本身所蕴含的巨大能量,这些都可能被恶意攻击者利用以制造危险。

我们的研究问题如下:

  1. 未被入侵的充电桩上,其内置的软件安全机制(安全基线)是什么?
  2. 已被入侵的充电桩上,是否存在独立于软件之外的次级硬件安全机制?如果软件被攻破,这些机制能否生效?
  3. 如果缺乏次级保护,充电桩能否承受过载电流?会造成多大程度的损坏?损坏是否会超出设备外壳,影响周围环境,甚至对基础设施或人身安全构成威胁?

充电桩技术与测试方法 ⚙️

为了回答上述问题,我们首先需要了解相关技术并建立测试方法。

电动汽车充电桩和车辆遵循J1772标准,该标准规定了最高80安培的二级充电。充电枪上的黄色引脚是高压导电极,绿色是保护接地,还有两个控制信号:接近引导信号和控制引导信号。控制引导信号是一个1 kHz的脉宽调制信号,其占空比用于告知车辆当前允许的最大充电电流(标准规定10%占空比对应6安培,96%占空比对应80安培)。攻击者的目标就是最大化这个电流值。

典型的充电桩硬件架构包括:处理用户界面和通信的主处理器、负责底层功能(如控制导引信号生成)的辅助处理器、控制主电路通断的继电器、电流测量传感器和温度传感器等。辅助处理器通常也可通过功能丰富的接口(包括固件更新)进行访问,因此我们认为其与主处理器同样易受攻击。

我们的研究任务包括:

  • 任务一:模拟攻击者,击败充电桩的软件安全机制。
  • 任务二:让充电桩输出超出其设计规格的电流。

为此,我们构建了一个测试平台,使用电阻负载元件来模拟车辆,最大可提供27.5千瓦的负载。平台包含断路器、充电桩(被测设备)、负载银行控制器以及测量电压电流的仪器。我们使用多组不同功率的加热器来产生不同等级的测试电流。

为了统一测试8款不同设计的充电桩,我们采用了硬件修改的方法来“模拟被入侵”状态。我们通过逆向工程,定位到软件控制继电器的最终输出点(通常是处理器的一个引脚),然后切断这条线路,并将两端引到外部。这样,我们可以通过跳线恢复原状进行基线测试,也可以断开跳线,使软件安全机制失效,从而测试硬件是否具备独立的过流保护能力。

测试结果与分析 📊

上一节我们介绍了测试方法,本节中我们来看看具体的测试结果。

首先进行未入侵状态(基线)测试:缓慢提升电流,大多数充电桩能检测到过流状态并断开继电器停止充电。但有两款设备未能响应:其中一款进入了“寿命终止”状态(虽未继续恶化,但对用户无益);另一款设备虽然其应用界面显示具备多种保护功能(如接地故障中断、继电器粘连检测等),但过流保护似乎未启用,可能是配置问题或默认关闭。

模拟入侵状态测试中,我们移除了软件保护。测试视频集锦显示,所有充电桩在持续过载(约80安培)下均发生了严重故障:

观察到的故障现象包括:

  • 电缆过热与失效:电缆成为最薄弱的环节。由于发热与电流的平方成正比(P = I²R),过载导致电缆温度急剧升高(超过350°F/177°C),足以造成烧伤、熔化电缆护套并将其从墙壁上熔脱。所有测试电缆均失效,或剧烈故障,或熔融、冒烟,无一可安全复用。
  • 电弧与爆炸:电缆内部短路产生电弧,引燃设备内部产生的有毒且可燃的挥发气体,导致剧烈的爆炸和火焰喷发。
  • 内部电路损坏:高电流窜入控制导引信号等低压电路,将其完全烧毁。至少三款充电桩出现类似损坏,这可能也会对连接的车辆造成损害。

测试结论: 所有受测充电桩在软件被控制后,均缺乏有效的独立硬件安全机制来防止这种危险的过载破坏。半数充电桩在1.5小时内失效,最快的在1小时内失效,其余的也在5.5小时内失效。

缓解措施与行业建议 🛡️

面对这些风险,用户和行业可以采取哪些措施呢?

关于电路断路器:常见的误解是断路器在电流超过额定值时会立即跳闸。实际上,断路器(特别是热磁式)的跳闸需要时间。对于典型的48安培充电桩,专业安装会使用60安培断路器(留有裕量),加上断路器本身的特性,可能导致充电桩在41%的过载下持续运行,或在短时间内承受近双倍的额定电流。环境温度、不当的断路器升级建议或用户自行升级以“未来验证”等行为,都会恶化这一情况。

关于电缆管理

  • 切勿将电缆盘绕在充电桩下方(火焰向上蔓延会加剧风险)。
  • 充电时,确保电缆未盘绕且未接触易燃物。
  • 较短的电缆相对更安全。
  • 升级电缆可能只是将风险转移到下一个薄弱点。

其他缓解建议

  • 用户层面:将车辆端的充电电流限制设置为与充电桩额定值相同(如果车辆支持此功能)。
  • 购买选择:考虑购买额定电流为80安培的充电桩,这样即使在入侵状态下达到最大电流,也在其设计范围内。但这类产品通常价格昂贵。
  • 高级保护:使用特殊断路器(如ZS断路器或电子断路器),但成本高昂。

根本解决方案在于制造商:设备应实现本质安全,即使在软件被完全入侵的情况下也能防止危险过载。这需要通过独立的硬件安全机制来实现,例如:

  • 在软件控制点之后,增加一个硬件电流检测电路
  • 该电路在检测到电流超过预设的硬件阈值(设定为设备最大额定值)时,直接切断继电器
  • 此安全系统应被锁定,一旦触发需断电才能复位,且软件无法干预。

一个简单的保险丝也能提供基础保护。这些硬件解决方案的成本并不高昂。制造商需要承担起责任,设计并内置这类无法被软件漏洞绕过的安全机制。

总结 📝

本节课中,我们一起学习了电动汽车充电桩的安全现状。

我们通过研究表明,当充电桩被入侵时,可能引发财产损失甚至人身伤害。尽管关于漏洞普遍性和可能性的讨论会继续,但风险确实存在且非零。

行业对漏洞的响应参差不齐,同时市场上不断涌现的新产品往往重复着相同的低级漏洞。在任何情况下,设备都不应持续输出数倍于其额定值的电流,这是一个严重的安全设计缺陷。

制造商不应仅仅依赖我们敦促其改善软件安全,而应主动采用不受软件漏洞影响的、可被独立测试验证的硬件安全设计。过去我们讨论漏洞影响时,可能忽略了最重要的一点:你的房屋可能会起火

希望行业能正视这些问题并做出切实改进。我们已证明漏洞广泛存在,设备可被过载,行业亟需改变以提升安全水平。


扩展阅读:关于电动汽车充电桩攻击态势及更多技术细节,请参阅ZDI博客上的相关文章。

AI机器人时代下小型组织的防护策略 [S5DJtN1FDYo] 🛡️

概述

在本节课中,我们将探讨在AI机器人流量日益增长的背景下,如何保护小型组织的网络服务器。我们将从一个具体的案例出发,分析问题根源,并介绍一种基于行为分析和子网聚合的非AI解决方案,以有效区分并过滤机器流量,保障服务器对人类用户的响应能力。


互联网流量的现状:机器成为主导

根据Imperva 2025年的《恶意机器人报告》,目前互联网上51%的流量是非人类流量。这意味着我们已经跨过一个阈值,机器成为了互联网的主要组成部分。

更严峻的是,根据2021年的一项观察,高达80%的恶意机器人IP地址并未被列入流行的公开IP封锁列表中。因为这些恶意IP地址变化非常迅速和频繁,传统的静态封锁列表难以跟上其变化速度。

上一节我们了解了全球性的流量趋势,接下来我们将视角缩小,看看这对一个具体的小型组织意味着什么。


案例研究:社区科学研究所的困境

我们合作的对象是社区科学研究所,这是一个位于纽约州中部的非营利公益组织,致力于促进科学素养、组织志愿者进行水质监测并提供经过认证的实验室分析服务。

该组织规模很小,只运行着少数几台服务器,并向公众免费提供所有数据。然而,他们发现其中一台服务器在20天内收到了超过15万次页面点击,平均每天超过7000次。

如此巨大的流量严重降低了服务器的性能,影响了已知用户和客户的正常访问。通过初步查看服务器日志,我们发现问题根源在于:尽管该数据库只包含纽约州中部的数据,但访问流量却来自全世界各地。这清楚地表明,有成千上万的机器在尝试抓取数据,很可能是用于训练AI模型的网络爬虫。


传统防护工具的局限性

在寻找解决方案时,我们评估了多种常见工具,但发现它们对于应对当前的AI爬虫浪潮效果有限。以下是我们的发现:

  • 速率限制:效果不佳。我们发现大多数爬虫会主动遵守服务器设置的速率限制(例如,每分钟不超过20页),以避免被传统限流机制封锁。
  • 公开封锁列表:如前所述,覆盖率很低,高达87%的恶意IP未被收录。
  • grep命令搜索:过于底层和繁琐,效率低下。
  • GoAccess等日志分析工具:它们提供的是摘要统计信息,无法区分人类和机器流量。例如,其报告明确注明“包含蜘蛛爬虫”。
  • 实时监控:通常不分析历史日志模式,难以识别持续性的机械访问规律。
  • 基于AI的检测:这类新技术通常需要大量优质的、已标注好“人类/机器”类别的训练数据,这对于许多组织来说是一个挑战。

因此,我们决定采用一种非AI的方法来解决这个由AI引发的问题。核心问题是:我们能否从访问模式上区分人类和机器?


核心理念:像声纳员一样“聆听”流量

想象一下潜艇里的声纳员,他通过聆听声音模式来区分敌方潜艇(有规律的机械声)和鲸鱼(自然、随机的声音)。我们借鉴了这个思路。

我们的方法是:分析访问日志,寻找那些听起来像“机器”的、机械的、重复的模式,并将其与更像人类的、随机且不可预测的访问模式区分开来。

为了“看到”这些模式,我们受到一篇2018年论文《Web服务器日志可视化》的启发,采用了时间 vs. 主机IP 的可视化方法。


可视化分析:一眼识别机器模式

我们将社区科学研究所20天的日志数据绘制成图:横轴是时间,纵轴是主机IP地址。

这种可视化方法有两个关键优势:

  1. 一览无余:在一张图中呈现所有日志数据,没有任何统计摘要造成的信息隐藏。
  2. 人类直觉:人类非常擅长从图像中识别模式。

观察生成的图像,那些形成笔直横线、虚线或极其规律点阵的IP,就是典型的机器访问模式——它们以固定的频率持续访问。而图像中那些分散、随机、无规律的点,则更可能来自人类用户。

我们还发现了更复杂的机械模式:它们虽然不像直线那样持续全天,但依然呈现出明显的规律性“声学特征”。我们的目标是识别所有机械访问模式,无论其意图是善意还是恶意。


引入人类行为指标进行评分

既然速率限制(“你有多快?”)效果有限,我们引入了来自人机交互领域的理念,从行为层面进行区分。

我们设计了一套评分算法,基于以下人类行为指标对IP地址进行每日评估:

  • 访问频率:人类不会连续多天、每天长时间地访问同一个服务器。
  • 每日活跃时长:大多数人每天工作不超过一定小时数,长时间持续访问很可疑。
  • 每日点击量:对单个服务器而言,一天内浏览超过数百个页面极不寻常。

算法将这些指标加权组合,为每个IP计算一个“非人类”评分。公式的核心思想是:
评分 = f(访问频率权重, 每日时长权重, 点击量权重)

以下是应用不同过滤规则后的效果对比:

  • 应用“连续多日访问”过滤:有效清除了那些在连续多天内长时间访问的IP。
  • 结合“每日时长”与“频率”过滤:即“智能限流”,能捕捉那些在一天中特定时段规律访问的IP。
  • 应用“每日最大点击量”过滤:清除那些试图在短时间内获取海量页面的IP。
  • 综合过滤结果:将以上所有规则组合应用后,图像中的机械模式大部分被清除,流量图看起来更接近人类访问。

应对数据中心攻击:子网哈希聚合

然而,综合过滤后图像底部仍残留一些“虚线”模式。放大观察发现,这并非单个IP,而是来自一个C类子网(如192.168.1.xxx)内的多个IP,它们以一致的频率发起访问。这就是典型的数据中心攻击——利用整个IP段来分散请求,规避针对单个IP的检测。

为了自动化识别此类攻击,我们引入了分层子网哈希聚合算法:

  1. 首先,对单个IP进行评分和过滤。
  2. 然后,将IP地址屏蔽掉最后一段,聚合到C类子网级别,并对该子网的整体行为进行评分。
  3. 进一步,屏蔽掉最后两段,聚合到B类子网级别并进行评分。
  4. 最终,汇总所有级别的过滤结果,生成最终的封锁列表。
# 算法概念性伪代码
def hierarchical_subnet_hashing_and_scoring(log_entries):
    # 1. IP级别评分
    ip_scores = score_individual_ips(log_entries)
    block_list_ip = filter_based_on_score(ip_scores)

    # 2. 聚合到C类子网并评分 (掩码 255.255.255.0)
    c_subnet_aggregates = aggregate_by_subnet(log_entries, mask=24)
    c_subnet_scores = score_subnets(c_subnet_aggregates)
    block_list_c = filter_based_on_score(c_subnet_scores)

    # 3. 聚合到B类子网并评分 (掩码 255.255.0.0)
    b_subnet_aggregates = aggregate_by_subnet(log_entries, mask=16)
    b_subnet_scores = score_subnets(b_subnet_aggregates)
    block_list_b = filter_based_on_score(b_subnet_scores)

    # 4. 合并去重,生成最小化封锁列表
    final_block_list = merge_and_minimize(block_list_ip, block_list_c, block_list_b)
    return final_block_list

应用子网封锁后,我们得到了最终结果。对比原始流量图(左)和过滤后流量图(右),机械访问模式被极大清除。


效果评估与政策考量

通过行为评分结合子网哈希,我们实现了94%的流量削减,远超单纯速率限制33%的效果。各阶段贡献如下:

  • 速率限制:-33%
  • 连续访问过滤:-9%
  • 每日时长过滤:-9%
  • 每日最大点击量过滤:-3%
  • C类子网封锁:-14%
  • B类子网封锁:-26%
  • 总削减:94%

这对于小型组织至关重要。我们发现,即使行为良好、遵守限速的AI爬虫,其绝对数量也足以压垮小型服务器。我们的方法不分析具体请求内容(如SQL注入),而是解决流量规模这一根本问题。

从政策角度看,社区科学研究所的目标不是保护数据(数据本身免费公开),而是确保服务器对人类用户保持响应,并鼓励“人在回路”的数据使用方式。此外,准确的、剔除机器流量的访问统计,对于依赖“用户量”数据来申请资助的非营利组织也至关重要。


解决方案:LogGrip工具介绍

基于以上研究,我们开发了 LogGrip——一个轻量级开源工具,用于基于访问日志生成封锁列表和策略可视化。

工具特点:

  • 输入简单:仅需服务器访问日志和一个定义日志格式及封锁策略的配置文件。
  • 处理快速:处理15万条日志仅需不到一分钟。
  • 输出丰富:一次性生成多种结果,包括:
    • 原始/过滤后流量可视化PNG图
    • 按IP和子网统计的指标CSV文件
    • 页面点击详情
    • 可直接使用的分层封锁列表(可用于iptables等)
  • 开源易用:基于Apache 2.0许可证,命令行操作,无需图形界面。

工具局限性:

  1. 无法防御DDoS攻击:图中出现的贯穿整个IP范围的垂直短线,代表分布式拒绝服务攻击。这种使用海量随机IP短时轰炸的方式,无法用封锁列表有效应对。
  2. 存在漏网的“温和”爬虫:一些爬虫设计得非常像人类(低频、随机、在合理时间访问),可能无法被过滤。但从策略上讲,只要它们不影响服务器性能,允许其访问也可能是可接受的。


未来方向

  • 实际效果监测:在客户生产环境中部署,测量封锁后的实际影响。
  • 获取基准数据:构建“人类”和“机器”流量的基准数据集用于更精确的验证和优化,这目前很有挑战性。
  • 策略参数优化:研究12个策略参数的敏感性,并探索(在基准数据支持下)使用机器学习进行自动优化。
  • 增强功能:集成地理围栏信息、更深入分析请求内容等,以提供更精细的过滤能力。

总结

本节课中,我们一起学习了如何在AI机器人主导流量的时代保护小型组织。我们认识到,即使“行为良好”的AI爬虫,其庞大数量也会对资源有限的小型服务器构成威胁。通过结合人类行为指标评分分层子网哈希聚合的方法,我们可以有效区分并过滤机械访问模式,显著降低非人类流量(本案例中达94%),从而保障服务器对人类用户的可用性和响应性。最后,我们介绍了实现这一理念的LogGrip工具,它提供了一种低成本、易用且开源的实践方案。


(注:文中的视频演示、问答环节及具体命令行操作细节已根据要求整合或简化到上述教程正文中,未单独列出。)

QUACK:通过静态鸭子类型防御反序列化攻击 🦆

概述

在本节课中,我们将学习一种名为QUACK的防御系统,它旨在通过静态程序分析技术来缓解PHP应用程序中的反序列化攻击。我们将首先了解反序列化攻击的工作原理,然后深入探讨QUACK如何利用“静态鸭子类型”来自动推断开发者的意图,并限制反序列化时可实例化的类,从而阻止攻击链。


反序列化攻击原理 🔓

上一节我们介绍了课程目标,本节中我们来看看反序列化攻击是如何工作的。

PHP提供了一个名为unserialize()的函数,它接收一个表示序列化对象的字符串,并将其重建为运行时的对象。如果攻击者能够控制输入给unserialize()的字符串,他们就可以操纵反序列化出的对象类型和属性。

示例代码:

// 开发者期望反序列化一个 App 类的对象
$data = unserialize($user_input);
$data->run();

攻击者可以构造一个字符串,使得unserialize()返回一个完全不同的类(例如CommandExecutor)的实例。如果这个类恰好有与预期对象同名的方法(如run()),或者包含特殊的“魔术方法”(如__wakeup, __destruct),攻击者就可能执行恶意代码。

属性导向编程(POP Chains)

为了在真实、复杂的应用中利用漏洞,攻击者使用一种称为“属性导向编程”(Property-Oriented Programming, POP)的技术。

以下是POP链的基本步骤:

  1. 攻击者选择一个包含有用魔术方法(如__destruct)的类作为入口点。
  2. 通过设置该对象的属性,将其他类的对象嵌套进去。
  3. 这些嵌套对象的类包含其他方法,当入口点的魔术方法被自动调用时,会触发一系列方法调用链。
  4. 这条调用链最终会到达一个能执行危险操作(如system())的函数。

核心概念: 攻击之所以能够成功,是因为攻击者能够创建和利用比开发者预期更多的类。


现有缓解措施及其局限性 🛡️

了解了攻击原理后,我们来看看现有的防御方法及其不足。

目前主要有三种推荐方案:

  1. 避免使用unserialize():改用JSON等格式存储简单数据。但对于需要存储复杂PHP对象的场景不适用。
  2. 使用加密签名确保数据完整性:这要求应用程序自身生成序列化数据,并非总是可行。
  3. 使用unserialize()allowed_classes参数:这是PHP内置的最有效防御。开发者可以提供一个允许反序列化的类名列表。如果遇到列表之外的类,PHP会将其替换为一个无方法无属性的“虚对象”,从而阻断攻击。

示例代码:

// 只允许反序列化 App 类
$data = unserialize($user_input, ['allowed_classes' => ['App']]);

然而,allowed_classes参数使用率极低(约0.1%),主要原因有两个:

  • 开发者不了解反序列化的风险。
  • 对于已存在的庞大代码库,手动找出每个unserialize()调用所期望的类非常繁琐。

本节要点: 现有缓解措施要么不通用,要么未被充分利用。我们需要一种能自动推断开发者意图的工具。


QUACK系统设计 🛠️

上一节我们指出了手动防御的困难,本节中我们将介绍QUACK的解决方案。

QUACK的设计目标是:自动推断在特定unserialize()调用点,开发者预期允许反序列化的类集合,并利用allowed_classes参数实施限制。

QUACK的工作流程分为三步:

  1. 确定可用类集合:分析程序,找出在特定unserialize()调用点可能被加载的所有类。
  2. 推断预期类集合:通过静态分析,观察反序列化后的对象在代码中是如何被使用的,以此推断其可能的类型。
  3. 计算交集并应用:取“可用类集合”和“预期类集合”的交集,作为allowed_classes的参数值。

系统公式:
allowed_classes = AvailableClasses(at deserialization point) ∩ InferredExpectedClasses(usage of object)


QUACK核心技术:静态鸭子类型 🦆🔍

QUACK推断类型的关键技术是“静态鸭子类型”。鸭子类型是动态语言中的概念:“如果一个对象走起来像鸭子,叫起来像鸭子,那么它就可以被当作鸭子。” 即,对象类型由其拥有的方法和属性决定。

QUACK将这一概念应用于静态分析。它遍历代码,收集关于反序列化对象使用的“证据”,并应用类型推断规则。

以下是几个核心推断规则示例:

规则1:方法调用
如果对象被调用了swim()fly()方法,QUACK会寻找同时定义了这两个方法的类。

规则2:属性访问
如果对象访问了featherColor属性,QUACK会寻找定义了该属性的类。

规则3:函数参数类型提示
如果对象被传递给一个具有类型提示(如function feed(Duck $animal))的函数,QUACK会直接采用该类型。

规则4:类型检查操作符
如果对象用于instanceof操作符(如$obj instanceof Duck),QUACK会采用操作符指定的类型。

QUACK还会分析嵌套对象的属性访问,以确保整个对象图中所有可能被实例化的类都受到限制。


实战演示:QUACK防御漏洞 🛡️✅

让我们通过一个真实案例(Moodle学习平台的CVE)来看QUACK的防御效果。

  1. 攻击阶段:攻击者上传一个包含恶意序列化字符串的XML文件,触发POP链,成功执行了system(‘echo HACKED’)命令。
  2. 分析阶段:对Moodle代码运行QUACK。QUACK分析到漏洞点处的unserialize()调用,发现反序列化对象仅被访问了两个特定属性。根据鸭子类型规则,它推断出只有一个类同时拥有这两个属性,并且该类在可用类集合中。
  3. 防御阶段:根据QUACK的输出,手动(或通过后处理脚本)修改漏洞代码,添加allowed_classes参数,仅允许那个特定的类。
  4. 验证阶段:再次上传相同的恶意XML文件。此时,由于攻击链中的其他类不被允许,反序列化失败,恶意命令未能执行,而正常的课程导入功能不受影响。

效果评估与未来展望 📊🚀

我们对QUACK在多个真实漏洞上的表现进行了评估。

  • 有效性:在15个易受攻击的unserialize()调用中,QUACK成功阻断了其中12个调用点的所有攻击方法。总体而言,它阻止了攻击者97%的可用方法。自动化漏洞利用工具在QUACK防护下无法再生成有效的攻击载荷。
  • 改进方向
    • 正确性:PHP语言特性复杂,QUACK作为研究原型,可能存在未覆盖的边角情况。我们希望社区能提供反馈,帮助完善。
    • 可用性:理想情况下,QUACK可以集成到IDE中,在开发者编写代码时实时提供allowed_classes建议,实现“左移”安全。
  • 适用范围与局限
    • QUACK能有效限制攻击者可用的类数量,从而阻断POP链攻击。
    • QUACK无法防御“纯数据攻击”,即攻击者使用合法类但篡改其属性值(如将User->isAdmin改为true)的攻击。这需要其他机制(如输入验证)来防御。
    • QUACK的理念可以扩展到具有类似反序列化API的语言(如Java、C#),但对于Python pickle这类表达能力极强的模块则难以适用。

总结 🎯

本节课中我们一起学习了以下内容:

  1. 反序列化攻击的本质:攻击者通过注入非预期的类对象,利用魔术方法和POP链劫持程序控制流。
  2. 现有防御的不足:最有效的allowed_classes参数因难以确定预期类而很少被使用。
  3. QUACK的解决方案:通过静态程序分析,结合“可用类分析”和“静态鸭子类型推断”,自动计算出应被允许的类集合。
  4. QUACK的效果与意义:它能显著降低应用受反序列化攻击的风险,作为一种深度防御工具,与开发者谨慎的编码实践和其他安全机制相辅相成。

最后,给开发者的核心建议是:审慎使用unserialize(),如果必须使用,请务必考虑使用allowed_classes参数,而QUACK可以帮助你确定该参数的取值。


(注:本教程根据技术演讲内容整理,聚焦于核心原理与流程,省略了部分演示细节和问答环节。)

安全港湾还是危险水域?揭示 PyTorch 中 TorchScript 引擎的隐藏风险 🚨

在本节课中,我们将学习 PyTorch 框架中一个重要的安全特性 with_onnx,并深入探讨其背后的 TorchScript 引擎如何被绕过,从而引发严重的安全漏洞。我们将从背景知识开始,逐步分析漏洞的成因、利用方式及其对整个 AI 生态系统的影响。


背景知识介绍

PyTorch 是一个基于 Torch 机器学习库的框架,由 Facebook 开发,现已开源。它易于使用,功能强大,广泛应用于深度学习研究、自然语言处理和计算机视觉领域。

在机器学习领域,存在许多流行的框架,如 TensorFlow 和 Keras。然而,根据官方数据,PyTorch 无疑是最受欢迎的机器学习框架之一。因此,在这样一个著名的框架中发现漏洞将是一件非常引人注目的事情。


故事的开始:从 Pickle 到 with_onnx

早期,PyTorch 为了方便,使用 Python 的 pickle 模块来加载和保存模型。然而,pickle 是 Python 中最著名的安全问题之一。事实上,官方 Python 文档警告称,加载不受信任的数据时使用 pickle 是不安全的。

2021年,有人在 GitHub 上提出了这个问题,并呼吁寻找解决方案。最终,在 2022年,PyTorch 发布了一个重要更新,引入了 with_onnx 参数。

让我们简要了解一下 with_onnx 的实现。当 with_onnx 未启用时(这是默认设置),PyTorch 会使用 pickle 来保存和加载模块,这会引入安全风险。然而,当我们设置 with_onnx=True 参数时,它将使用一种称为 with_onnx_pickle 的受限 pickle 来加载模型。

以下是一个示例,展示了默认情况下如何利用 pickle 执行命令:

import torch
import pickle

class EvilPickle:
    def __reduce__(self):
        import os
        return (os.system, ('whoami', ))

evil_model = EvilPickle()
torch.save(evil_model, 'evil_model.pt')
loaded_model = torch.load('evil_model.pt', with_onnx=False)  # 这将执行 `whoami` 命令

然而,当使用 with_onnx=True 时,会引发异常,似乎有效地缓解了漏洞。在官方 PyTorch 文档中,他们也认为 with_onnx=True 是安全的,同时警告永远不要使用 with_onnx=False 加载不受信任的检查点。

此外,当在其他基于 PyTorch 的组件中发现类似的安全问题时,他们通常通过使用 with_onnx=True 来修复。例如,最初 VOM 使用 torch.load 时没有设置 with_onnx=True,从而引入了安全风险,然后他们通过添加 with_onnx=True 参数来修补这个漏洞。

不仅限于 VOM,每当发现软件使用 torch.load 而没有设置 with_onnx=True 时,修复方法总是相同的:只是添加这个参数。但这里出现了一个问题:我们能盲目信任 with_onnx 的安全性吗?


深入分析:with_onnx 如何工作?

之前我们指出,with_onnx 类似于一个受限的 pickle。在分析 with_onnx 的实现之前,我们需要了解 pickle 是如何工作的。

pickle 就像一个解释器,它按顺序读取并解释每段代码,执行相应的操作。例如,我们首先遇到 GLOBAL 操作码,它将执行 load_global 函数,加载目标函数(如 os.system)并将其推入栈中。

然后,我们需要构造参数。首先,执行 UNICODE 操作码,它将推入一个字符串(例如 'whoami')。由于命令必须是元组格式,我们需要用 TUPLE1 操作码包装这个字符串,执行 load_tuple 函数。最后,使用 REDUCE 操作码,从栈中获取函数和参数,并执行该函数。

那么,with_onnx 如何解决这个问题?通过上面的例子,我们可以大致感觉到,pickle 反序列化中最危险的部分是 load_globalload_reducewith_onnx_pickle 只是对这些危险的操作码添加了一些限制。

查看代码,可以看到 load_global 函数添加了白名单和黑名单检查以防止安全问题。同样,load_reduce 函数也以类似的方式受到限制,它也有一个白名单。

总的来说,with_onnx 是使用白名单和黑名单机制实现的。那么,我们如何绕过它呢?

一个常见的方法是检查白名单,看看是否有任何潜在的危险代码。我做了同样的尝试,但最终没有找到任何有用的东西。

我们常常受限于固定的思维方式。例如,大多数人可能只看到明显的白名单和黑名单机制,然后就停在那里。然而,实际上,使用 with_onnx=True 的加载过程相当复杂。那么,在这个加载过程的其他地方是否可能存在一些问题呢?

我尝试对整个工作流程进行复杂分析,以确保没有遗漏任何东西。我开始逐步调试代码,一行一行地执行。在一次练习中,我发现了奇怪的东西:torch.jit.load。这是什么?我对此一无所知,于是在谷歌上搜索了一下,发现 torch.jit.load 用于加载 TorchScript 格式的模块。

现在你可以理解为什么我们命名这个主题为“揭示 TorchScript 引擎的隐藏风险”了。接下来,我们将分析和利用 TorchScript 引擎。


TorchScript 基础

TorchScript 用于在没有 Python 解释器的环境中部署模型,例如 C++ 和移动设备。它可以通过脚本或追踪从 Python 代码编译而来,并保存为 .pt 文件,该文件可以在 C++ 和移动设备中加载和运行。保存和加载过程涉及序列化。我将解释 Python 代码如何编译为 TorchScript、序列化和反序列化过程、.pt 文件的结构,以及最终如何执行。

首先,我们可以使用 @torch.jit.script 装饰器将一个 Python 函数编译为 TorchScript。

编译步骤如下:

  1. 将 Python 源代码解析为抽象语法树。
  2. 将 Python AST 转换为 JIT AST。
  3. 将 JIT AST 转换为中间表示图。

IR 图最初包含许多不必要的节点,通过优化使其更加简洁。

让我们深入了解编译过程。在开始之前,我需要展示在这个上下文中什么是函数和模型。你可以看到一个是函数,另一个是类。这两者的脚本化过程有些不同,因此我们将分别介绍。

首先看函数的情况。编译过程在 script_impl 函数中处理。有两个主要函数:get_jit_defjit_script_compileget_jit_def 函数执行两个主要任务:首先,它使用 AST 库将 Python 代码转换为 Python AST;其次,它调用 build_def 将该 Python AST 转换为 JIT AST。jit_script_compile 是一个从 C++ 绑定到 Python 的函数,它在 C++ 层进一步将 JIT AST 转换为 IR。它最终调用 to_ir 函数,完成从 JIT AST 到 IR 的转换。此外,to_ir 还会调用一些优化函数来简化 IR 图。

现在,函数的编译过程就完成了。对这个过程有一个高层次的了解就足够了。如果你对完整的源代码细节感兴趣,可以使用我提供的调用栈来浏览源代码。

然后,让我们看看模型的情况。整体过程与函数类似,只是在开始时多了一个步骤:从模型中检索所有函数。它需要检索函数并逐个编译它们。stubs_fn 函数负责处理这个。stubs_fninit_methods_to_compile 在这个上下文中的别名。让我们看看 init_methods_to_compile 函数做了什么。

init_methods_to_compile 函数中,首先使用 dir() 获取模型的所有属性和方法,经过过滤后,保存需要导出的方法,从而收集模型中所有需要编译的函数。make_stubs_from_methods 使用 get_jit_def 函数将收集到的函数转换为 JIT AST,这与函数编译过程中使用的函数相同。回到 create_script_modelmethod_stubs 变量存储我们刚刚转换的 JIT AST。create_methods_and_properties_from_stubs 函数以 method_stubs 作为输入,负责将其转换为 IR。我们可以看到,这个调用栈与函数编译的调用栈相似,两者最终都完成了向 IR 的转换。现在,模型的编译过程就完成了。

总的来说,函数和模型的一些关键步骤是相同的。两者都使用 get_jit_def 将 Python 转换为 JIT AST,然后通过 to_ir 转换为 IR。

序列化功能可以保存模型并将其部署到其他环境。使用 torch.save 将模型保存为 .pt 文件,使用 torch.load.pt 文件加载为模型。

这里的 Python 代码是从 IR 转换而来的。你会注意到它与原始代码略有不同。

让我们看看脚本函数和脚本模型是如何序列化的。与脚本模型相比,脚本函数多了一个步骤:它需要先转换为脚本模型。之后,两者都调用 save 进行序列化。

在序列化过程中,一些信息以 pickle 格式存储在 data.pklconstant.pkl 中。此外,它还将从 IR 转换的 Python 代码和调试信息保存到 code 目录中。

总结保存过程:torch.jit.script 函数首先转换为 Torch 模型。剩余的过程是相同的:首先,与模型对应的 IR 以 pickle 格式序列化为 data.pkl;其次,通过 pretty_print 获取代码和调试信息,并写入 code 目录;第三,将张量常量保存到 constant.pkl。现在,序列化完成。

让我们看看 .pt 文件的细节。.pt 文件是使用 zip 压缩的压缩文件。解压缩后的文件树如上所示。我们可以使用 pickletools 反汇编它,上面是 data.pkl 的反汇编输出。这段 pickle 代码的含义是创建一个名为 torch.jit._pickle.Pickleable 的对象,并将其 training 属性设置为 True。而 torch.jit._pickle.Pickleable 对象就是脚本模型。因此,在解释 data.pkl 时,模型对象被创建。constant.pkl 包含可以创建带有张量的 IR 对象的 pickle 代码。torch.py 文件包含 Python 代码字符串,它与脚本模型中 code 属性的内容相同,因为它们是以相同的方式获取的。

好的,现在我们理解了序列化文件中保存的三个最重要部分:data.pklconstant.pklcode 目录中的源代码。让我们看看这些部分如何恢复为脚本模型。

在反序列化函数中,序列化文件的三个主要部分被转换为脚本模型。让我们看看函数实现。deserialize 会调用 read_zip 来读取 constant.pkldata.pkl,然后得到一个 C++ 中的模型,也就是 Python 中的模型。

在反序列化过程中,首先,unpickle_constants 小心地获取张量常量,然后保存在常量表中。其次,在反序列化 data.pkl 的过程中,从 code 目录读取相关源代码,并根据需要进行解析。同时,相关常量也从常量表中读取。代码解析过程包括将 Python 代码转换为自定义令牌,然后将令牌转换为 JIT AST,最后转换为 IR。这个过程与之前 Python 到 TorchScript 的编译过程有显著不同。

总结加载过程:首先,通过 deserialize 运行主要逻辑;其次,调用 read_zip 读取 constant.pkl,通过 unpickle 将常量转换为 IR 值,并将它们保存到常量表中;第三,调用 read_zip 读取 data.pkl,在反序列化 data.pkl 期间,源导入器读取 code 文件和常量表,通过 parse_typefind_name_typeimport_name_type 恢复 IR 图。现在,反序列化完成。

让我们看看 TorchScript 是如何运行的。IR 图由许多节点组成,每个节点包含输入、输出和操作码三部分。操作码是执行的关键。执行 TorchScript 的过程是遍历 IR 并将其转换为指令,然后解释这些指令。每个指令都有一个操作码,这里有一个查找表,通过操作码找到对应的处理逻辑,然后执行它。

现在,我们对 TorchScript 的工作流程有了基本的了解。在阅读代码时,我发现了一些有趣的东西。有一个操作码名为 OP,它可以在操作符表上进行调用。操作符表包含许多函数,对应于操作符。我好奇它们是什么操作符。

一些内置函数将自己注册为操作符,需要操作指令来调用相应的函数。RegisterOperators 类管理这些操作符,并通过 register_operator 函数注册它们。我修改了 Python 代码,添加了一个函数来输出所有操作符。你可以看到这里有超过 2000 个操作符。所有这些操作符都安全吗?

在对这些操作符进行代码审计时,我们发现了两个有趣的操作符:savefrom_file。这里我们可以看到这两个函数的相应实现。save 函数会将指定值作为模型保存到指定文件,这可能导致任意文件写入。但保存的文件包含许多脏数据,即模型信息。from_file 函数将读取指定的文件,并将文件内容转换为张量,然后返回该张量。我们可以从张量中获取文件内容。现在,我们知道这两个操作符存在漏洞。

但仍然有一个问题:如何从 TorchScript 中调用它们?要得到答案,我们需要进一步理解操作符的注册过程。

_get_builtin_table 函数将一些对象成员函数注册到内置操作符中。在这个过程中,它还会为成员函数添加前缀以进行重命名。最后,这些函数的地址及其修改后的名称将被放入内置表中。

在 TorchScript 编译过程中,当检查 Python 对象是否存在于内置表中时,会触发糖化操作。如果存在,则返回一个内置函数。最终,这个内置函数将通过 emit_builtin_call 插入到 IR 图中。

回到内置注册过程,我们现在理解 save 可能来自包含内置函数的对象之一。通过逐个测试每个对象的 save 函数过程,我们会发现 save 函数存在于 torch 对象中。itemfrom_file 也可以以相同的方式获得。

因此,我们只需要调用 torch.savetorch.from_file 就可以在 TorchScript 中获得任意文件读写能力。

现在,我们可以尝试写入一个文件来获得 RCE,但由于存在一些脏字符,只有特定的特殊文件才会起作用。/etc/passwd 文件因为权限不匹配而失败。我们的脚本使用 torch.save,它用 0o600 权限写入文件。但当前守护进程需要 0o600 权限。

这是一个漏洞验证视频。你可以看到我们获得了 RCE。

到目前为止,我们讨论的漏洞可能更类似于逻辑漏洞。另一方面,一些黑客可能更喜欢内存相关的漏洞。我们还发现了一些溢出问题。在这里,你可以看到当我们加载这个模型文件时,它触发了一个堆溢出。因此,我们可以观察到堆地址和库的加载地址被泄露。这是一个漏洞验证视频。但由于时间限制,我们不会在这里详细讨论它们。我们希望将来能分享它们。

好的,这就是这个 CVE 的全部细节。修复也相对简单:当启用 with_onnx 时,它阻止了 TorchScript 的使用。


漏洞影响与案例研究

那么这个漏洞对整个 AI 生态系统有什么影响呢?整个 AI 生态系统就像这座房子,而 PyTorch 是基础组件之一。如果 PyTorch 出现问题,就像我们移除了底层组件之一,整个结构的安全性就会受到损害。

我们在 GitHub 上对使用 with_onnx=True 的项目进行了简单搜索,可以看到很多项目都以这种方式使用它。这里我们选择两个知名项目作为例子来说明漏洞的影响:一个是 VOM,另一个是 Transformers。

VOM 是一个用于大语言模型推理的高性能库,针对速度和内存使用进行了优化。我选择它是因为它恰好有一个 CVE,该 CVE 指出它使用了没有设置 with_onnx=Truetorch.load 函数,从而存在安全问题。他们通过添加 with_onnx 参数修补了这个漏洞,这似乎解决了问题。但由于 PyTorch 的问题,所有的缓解措施最终都无效了。因此,我们曾经认为的安全港湾实际上是危险水域。

同时,我注意到了一个非常有趣的现象。在 requirements-cpu.txt 中,你可以看到它硬编码了一个 PyTorch 版本,在 GPU 版本中也是如此。这意味着即使 PyTorch 发布了新的修补版本,VOM 的用户也无法及时更新,因为 VOM 已经硬编码了这个版本。因此,他们将长期暴露于这个漏洞之下。

首先,让我们设置我们的环境。由于 VOM 的最新版本已经修复了这个问题,我们需要安装一个旧版本,确切地说是 0.7.3。你可以看到,当我们安装 VOM 时,它会安装旧版本的 PyTorch。

这里我们将使用这个函数作为例子来演示漏洞的存在。起初,我没有想太多,只是想直接使用之前的漏洞利用代码,希望一次成功。你可以看到这里,当我们进入我们想要的逻辑时,它肯定会加载我们的模型。所以我们成功了。但事实上,失败了。为什么?让我们看看之前的漏洞利用代码,你可以看到在加载模型之后,我们需要调用这个模型才能触发前向逻辑,但在这里加载模型之后,你可以看到它没有调用模型,它只是获取 at 属性,然后删除这个模型。

这真的结束了吗?然而,在那个时候,我注意到了异常信息,它只是说模型对象没有名为 at 的属性。这个错误信息给了我一些启发。at 本质上是 Python 中的一个关键字,通常用于字典类型对象。你可以看到这里,实际上,at 是一个函数。那么,我们能推测出函数名吗?

于是我进行了第一次尝试。然而,当我们以这种方式编写代码时,我只是将函数名从 forward 改为 items,然后运行调用,但你可以看到我们仍然得到这个错误信息,为什么它仍然说我们没有 items 属性?但是,我尝试以这种方式编写,我们只是在我们的前向消息中调用 items 函数,你可以看到当我们运行代码时,我们成功地触发了逻辑。

这非常奇怪。原因是当检索模型函数时,它定义了该函数是否需要为函数导出,没有用 @export 装饰的函数,有一个延迟导出策略。这意味着只有在导出的函数内部调用它们时,

保护“人”的因素:Mimecast如何应对邮件威胁与AI风险 🛡️

在本节课中,我们将学习Mimecast如何将安全防护的重点从单纯的邮件安全,扩展到保护组织中最关键但也最脆弱的环节——“人”。我们将探讨如何识别高风险用户,以及如何应对生成式人工智能带来的新型安全挑战。


从邮件安全到“人”的安全 🔄

首先,我们非常感谢我们的客户群体。他们让我们认识到,触发风险需要两个条件。

攻击者向用户发送恶意邮件或钓鱼尝试只是其一。

用户实际采取行动并点击这些链接是其二。

因此,对我们而言,在讨论保护风险最高的载体——即传入的邮件威胁时,我们不仅需要保护传入的数据,还必须保护最终操作这些数据的“人”。

在过去的几年里,Mimecast收购了多项技术,使我们能够全面审视“人”的因素。

例如,了解他们在安全与意识培训方面的表现。

理解他们在数据丢失和内部威胁方面代表的风险。

同时,甚至能够执行我们所需的合规控制。

因此,对我们来说,将对话从“邮件安全”提升到“保护整个人”是一个合乎逻辑的演进。最重要的是,我们所有的客户都反馈,这是一个必要的演进。

这使他们能够更好地保护自己的组织。


识别高风险用户:人类风险指挥中心 🎯

在涉及人为风险时,最大的挑战之一是找出组织中的高风险用户。

根据Mimecast每天处理的数十亿封邮件数据,我们的研究表明,8%的用户导致了80%的风险

这引出了一个关键问题:组织如何收集所有这些风险信号,并将其汇总起来,以便快速识别出那些风险最高的用户?

特别是,某些用户如果同时满足以下条件,可能代表特定风险:例如,在邮件安全方面受到高度攻击,同时在模拟钓鱼攻击中表现不佳。我们知道这两个因素叠加会放大风险级别。

我们的“人类风险指挥中心”旨在让管理员和安全领导者轻松发现组织中的风险所在,并对这些风险点应用自适应控制。

以下是其主要目标:

  • 主动预防:阻止即将发生的风险。
  • 识别未来风险:预测并发现潜在威胁。
  • 控制与保护:确保所有最佳实践得到执行,全面保护用户,使其免受可能针对其业务的任何攻击。

这就是人类风险指挥中心。它是一个中央页面,能够以单一视图的方式集中展示所有风险,并将这些信息清晰地呈现给需要做出决策的管理员,以便他们应用自适应控制,防止风险进入组织。


应对生成式人工智能的双重挑战 🤖

生成式人工智能正在改变我们所有人的工作方式。

这不仅指您组织内部的用户,不幸的是,也包括黑客和攻击者试图入侵您组织的方式。

它使得一些我们以前能够轻易发现的风险,现在可以简单地通过这些AI工具进行调整和绕过。

这意味着我们必须更好地保护用户免受这些生成式AI攻击,攻击者正在利用AI发起激光般精准、针对性极强的钓鱼尝试

同时,我们需要确保您的组织从生成式AI中获得的生产力提升本身也是安全的。

在当今世界,用户尝试做很多事情,并且大多数时候他们的意图都是好的。

我们发现,用户通常不理解安全最佳实践,或者会绕过这些最佳实践,访问组织中未经批准的AI工具。

这对我们意味着,我们必须做好以下工作:

  • 了解工具:了解您在组织中实施了哪些安全工具。
  • 管理访问:了解您允许组织访问哪些生成式AI工具。
  • 引导与保护:最重要的是,确保您的员工被引导至那些经过批准的机制来使用AI。同时,在我们自己的产品中使用AI工具来发现呈现给用户的风险,并在这些威胁进入组织之前将其阻止。

我想大声地告诉所有人:生成式人工智能正在改变我们所有人的工作方式

我们鼓励组织拥抱这些技术,它们将使组织更具竞争力、更安全、让用户更高效。

但至关重要的是,我们必须为这些工具加上一层保护透镜,以确保其数据不会意外或故意泄露,从而被攻击者利用。这正是Mimecast目前正在做的事情:在保护AI使用的同时,也将其应用于我们的技术,以提供市场上最佳的威胁防护。


总结 📝

本节课中,我们一起学习了Mimecast的安全理念演进。

我们了解到,完整的安全防护需要同时关注外部威胁内部人为因素。通过“人类风险指挥中心”,可以基于数据识别出关键的少数高风险用户,并实施精准防护。

此外,面对生成式AI带来的新挑战,安全策略需要双管齐下:既要利用AI增强防护能力,也要严格管理组织内部对AI工具的使用,防止其成为新的风险入口。保护“人”的因素,是构建全面、弹性安全体系的核心。

释放UEFI恶意软件的完全隐身能力 [t17YEHymwE4] 🔓

概述

在本节课中,我们将探讨如何使UEFI恶意软件(UFMO)更加隐蔽,以及如何检测这些隐身的UEFI威胁。我们将深入分析现有UEFI恶意软件的局限性,并介绍一种名为“Shade BIOS”的新技术,它能够克服这些限制,实现更纯粹、更隐蔽的固件级攻击。


引言

我是Kasuki Mato,来自日本安全厂商FFR Security的研究员。我的主要研究方向是固件安全,特别是EFI/BIOS安全。在G5安全领域,一个普遍的观点是:感染固件是“杀鸡用牛刀”,通常感染内核层就足够了。这对于以普通公司为目标的攻击者来说确实如此,但固件安全在以下两个领域尤为重要。


固件安全的重要性

1. 国家安全相关攻击 🛡️

这类恶意软件必须尽可能隐蔽。此外,BIOS是安装后门的合理位置。与主要由单一公司制造的操作系统、虚拟机管理程序或CPU不同,BIOS由许多供应商实现,这使其成为安装后门的合适目标。操作系统和虚拟机管理程序在制造过程中并不存在,因此将后门置于BIOS中是合理的选择。从Vault 7等泄露文件可以看出,UEFI安全在国家安全背景下被认为非常重要。

2. 云安全 ☁️

原则上,BIOS比虚拟机管理程序拥有更高的权限,因为它执行得更早。因此,BIOS有潜力破坏虚拟机管理程序,并影响云服务上的所有虚拟机。现有研究表明,虚拟机管理程序与BIOS恶意软件之间存在激烈的对抗。


现有UEFI威胁的现状

UEFI威胁并非理论,现实中存在UEFI恶意软件。目前总共存在大约九个已知的引导套件,数量不算多。因此,EFI恶意软件能做的事情也未被充分评估。

这些引导套件有一个共同的重要特征:它们最终在用户态或内核态执行恶意行为。它们并非纯粹的BIOS恶意软件,只是支持用户态/内核态恶意行为的引导套件。我们认为这对UEFI恶意软件来说是一个重大挑战,因为这意味着它们最终仍然依赖于操作系统的安全机制。

除了引导套件,还有一些泄露的BIOS后门,如JetT或Vector EDK。其中一些是纯粹的BIOS恶意软件,意味着它们仅在BIOS中执行恶意活动。然而,这些后门都存在相同的问题:它们只支持非常特定的目标。研究领域的未来因素也是如此,这都是由于其设备特定的实现方式。

总结来说,现有的UEFI恶意软件普遍受到操作系统依赖性和硬件/设备依赖性的困扰。


操作系统依赖性问题

现有的UEFI引导套件可以禁用任何操作系统安全机制,它们实际上也是这么做的。例如,ES Specter Boot禁用驱动程序签名强制,Cosmic Strand Boot禁用补丁防护。

然而,它们仍然依赖于地球全局安全,因为如果不知道目标上运行的是什么杀毒软件,它们会被杀毒软件的内核驱动程序检测到。此外,除非它们禁用所有操作系统安全机制,否则它们会被其他操作系统安全机制检测到。而且,现有的引导套件在内核镜像和引导加载程序镜像的钩子中大量使用模式匹配,因此每次操作系统更新时,后门都必须更新。

因此,现有的UEFI引导套件仍然存在被上层安全机制检测到的风险。

从攻击者的角度来看,既然我们已经控制了更底层的BIOS,就不应该再关心操作系统。但为什么每个现有的UEFI引导套件首先都要使用用户态/内核态呢?为什么不把所有功能都实现在BIOS代码中?


硬件依赖性问题

这个问题的关键在于,攻击者想要的秘密或任何数据,只有在操作系统启动后才存在。也就是说,在引导阶段没有任何有趣的东西。然而,大多数BIOS环境在操作系统启动时就被销毁了。例如,EFI引导服务(如分配页面)不再可用,因此BIOS代码无法使用内存管理器。此外,UEFI协议(如HTTP协议或磁盘I/O协议)都被销毁,因此没有访问设备的接口。

因此,从操作系统启动后运行的BIOS代码中,很难与C2服务器通信或读取文件等。攻击者可以直接执行I/O操作,但这很困难,因为它们本质上必须实现完整的驱动程序栈。而且,即使它们设法做到了,实现也会变得非常设备特定,因此只能在非常特定的设备上工作。

这就是为什么现有的BIOS后门都是硬件依赖的,并且只支持非常特定的目标。例如,Steady Bound文档说明它只适用于Dell PowerEdge服务器。iChe引导套件只支持特定版本的HP iLO服务器。研究领域的BIOS恶意软件也是如此。

有一些纯粹在BIOS内实现的SMM后门,但如果你查看这些实现,它们必须直接访问硬件寄存器。直接访问寄存器意味着攻击者必须知道目标设备是什么,找到该设备的规格,并根据该规格读写这些寄存器。幸运的是,在这种情况下,设备是USB主机控制器,而USB有标准化规范,因此依赖性不那么严格。但这对于不使用USB的其他设备(如网络接口卡)无效。


现有BIOS恶意软件的困境总结

到目前为止,现有的BIOS恶意软件面临硬件和操作系统依赖性的困境。如果恶意软件试图在BIOS代码中执行所有操作,那么实现将变得非常设备特定,并且只能在特定的攻击目标上工作。这是由于缺乏访问设备的抽象接口。这些接口存在于操作系统或用户态运行时中,因此恶意软件可以使用它们。但这样一来,实现就会变得依赖于操作系统,并且可以被上层安全机制检测到。

因此,虽然据说攻击者控制了BIOS就可以为所欲为,但实际上这个困境限制了BIOS恶意软件能做的事情。

此外,平台安全正在迅速发展,我们也必须考虑它们。大多数现有的BIOS恶意软件是作为SMM模块实现的。但随着称为SMM隔离的最新安全机制,这些将不再有效。SMM曾被称为环-2,因为它可以在操作系统运行时访问任何物理内存或任何I/O而不被中断,因此长期被滥用。但启用SMM隔离后,以Intel平台为例,所有非Intel SMM模块都通过环分离或SMM环境内的页表隔离。因此,如果攻击者构建了自己的SMM后门并植入目标PC,它将在SMM环3运行。当它尝试访问操作系统内存区域时,由于这些页面未映射到SMM页表,将触发页错误。当它尝试访问I/O时,在SMM环0运行的安全监视器将检查策略,如果不匹配则拒绝访问。

因此,除非绕过SMM隔离,否则现有的SMM恶意软件在当前SMM和权限分离的趋势下不再有效。

顺便说一下,有两种类型的UEFI模块可以在操作系统运行时运行。一种是前面提到的SMM模块,大多数现有研究使用这种。然而,还有另一种类型的UEFI模块可以在运行时运行,称为运行时DXE驱动程序。这些模块像内核驱动程序一样映射到高虚拟地址空间。当操作系统代码调用UEFI运行时服务时,会触发这些功能。

与启用SMM隔离的SMM模块相比,运行时DXE驱动程序现在可以被视为权限更高的模块,因为它可以访问所有操作系统内存和所有I/O。然而,无论哪种模块,它们也都面临着操作系统和硬件依赖性的困境。


Shade BIOS的构想

那么,从BIOS能做的就这些了吗?从攻击者的角度来看,我们不想触及操作系统,因为操作系统可以检测到所有行为。但我们又需要操作系统在运行时的功能,如内存管理或设备驱动程序。如果没有这样的功能,最直接的想法是为攻击者实现一个独占的虚拟机。但这不现实,因为没有操作系统可以与其他操作系统并行运行,而且这很麻烦且占用大量内存。

经过思考,我们意识到UEFI BIOS实际上可以被视为一个小型操作系统,因为它有自己的内存管理和设备驱动程序。而且,它的体积很小,所以不浪费内存。于是我们想到一个主意:即使在操作系统启动后,也保留BIOS在内存中并使用它。因此,我们创造了Shade BIOS。

通过将BIOS保留在内存中,它允许BIOS代码即使在操作系统启动后也能使用UEFI功能,如UEFI引导服务、UEFI协议或UEFI驱动程序。

通过使用Shade BIOS,攻击者可以获得以下三个好处:

  1. 实现纯粹的BIOS恶意软件:Shade BIOS将使UEFI恶意软件与操作系统级安全脱钩。
  2. 使恶意软件设备独立:意味着攻击者不必知道目标使用什么设备。
  3. 使恶意软件易于开发:因为它们不需要实现完整的驱动程序栈或直接访问I/O,而是可以使用UEFI的接口。

Shade BIOS的工作原理

在接下来的部分,我将解释Shade BIOS的工作原理。简而言之,它有两个主要功能:第一是在操作系统启动后保留BIOS;第二是让保留的代码在运行时正常工作。

1. 如何将BIOS保留在内存中

在解释之前,我想概述一下UEFI如何管理内存映射。内存映射被管理为一个内存映射结构的双向链表。每个结构都有一个EFI内存类型,指示该内存区域存储什么类型的数据。例如,从内存地址0x5000到0x6000的内存区域的EFI内存类型为EFI引导服务数据。存储在这里的数据仅在引导时可用,操作系统启动后可以丢弃。

可以通过调用GetMemoryMap引导服务来获取内存映射,但我们只能获得内存映射的副本。这主要由操作系统加载程序使用,它们调用这个GetMemoryMap引导服务,并确定可以在哪里放置操作系统。它们认为EFI引导服务代码和数据不再必要,因此将使用这些内存区域。但它们会保留EFI运行时服务代码或数据等内存区域。

回到我们的目标,为了将BIOS保留在内存中,我们可以挂钩这个GetMemoryMap引导服务,并将EFI引导服务代码和数据的类型更改为EFI运行时服务代码和数据。然后,操作系统加载程序会认为这些存放EFI驱动程序或EFI协议的区域不能被销毁,这些状态将保留在内存中。你可能会想,这是否会占用太多操作系统可用的内存区域。但BIOS是一个非常小的组件,所以内存中没有很多EFI引导服务代码和数据。操作系统将转而使用EFI加载器数据或EFI常规内存,大多数内存区域都属于这种类型。

2. 解决运行时问题

现在我们已经能够将BIOS保留在内存中,但我们不能直接执行保留的代码。我们需要处理以下五个问题,才能让保留的代码在运行时正常工作。

问题一:运行时内存管理问题

内存分配器或BIOS从前面提到的双向链表中找到EFI常规内存的新页面。但这里的问题是,当前使用EFI常规内存的是操作系统。因此,BIOS分配器将从操作系统内存区域分配新的内存区域。

解决方案:我们可以再次挂钩GetMemoryMap引导服务,并为BIOS在运行时使用保存一些EFI常规内存。内存映射中有很多常规内存,我们将通过将其显示为EFI运行时服务数据,从操作系统中拿走一些黄色的常规内存。请记住,GetMemoryMap返回内存映射的副本,因此我们并没有修改实际的内存映射。这样,黄色的常规内存将不会被操作系统加载程序使用,但其他粉色的常规内存将被操作系统使用。接下来,我们希望BIOS内存分配器只使用黄色的常规内存,因此我们将粉色的常规内存从实际的内存映射中取消链接。这样,当BIOS内存分配器搜索空闲内存时,由于只有我们保存的黄色常规内存被链接,BIOS永远不会使用粉色的内存区域。

问题二:内存虚拟化问题

保留的模块认为它们在物理地址上运行,因此它们包含物理地址的全局指针,甚至可能有硬编码的物理地址。由于很难调整所有这些引用到虚拟地址,处理这个问题的最佳方法是更改页表为恒等映射。我实际上使用了部分恒等映射,这在我去年的BlackHat演讲中介绍过,因此这里跳过细节。

问题三:仅引导时资源问题

EFI系统表和EFI引导服务的一些成员指针在操作系统启动后被释放。这个问题的解决方案非常简单,你只需要在引导时复制它们,并在运行时解析它们。

另一个问题是UEFI变量。具有运行时属性的新UEFI变量仅在引导时可访问。但保留的BIOS代码会尝试访问非运行时UEFI变量,因为它们认为自己在引导时运行。这个问题的解决方案也很直接,我们可以挂钩SetVariable运行时服务,并为该变量创建一个副本,并添加运行时属性。

问题四:设备设置被操作系统设备驱动程序重新初始化

我想以USB主机控制器为例解释这意味着什么。USB主机控制器有一个CRCR寄存器,用于保存命令环的内存地址。设备驱动程序将写入这个命令环,让硬件控制器执行某些操作。当驱动程序初始化控制器时,它做的一件事是在内存中准备这个命令环,并将其地址存储到CRCR寄存器中。现在的问题是,在引导时,UEFI驱动程序在内存中准备了它们的命令环。但在操作系统启动后,操作系统设备驱动程序将准备它们自己的命令环,并覆盖CRCR寄存器以指向它们的命令环。然而,保留的UEFI驱动程序认为CRCR寄存器仍然指向它们的命令环,因此你不能直接使用保留的UEFI协议。

解决方案:重新初始化来自UEFI驱动程序的设备,并将这些设备寄存器设置为适当的值,供BIOS在运行时使用。但请记住,我们不希望Shade BIOS包含设备特定的代码,因此我们不能直接读写这些寄存器。

那么,如何在不直接访问寄存器的情况下重新初始化设备呢?解决方案是利用UEFI驱动程序遵循UEFI驱动程序模型这一事实,使用DisconnectController引导服务和ConnectController引导服务。以网络接口卡为例,NIC的硬件控制器被抽象为一个特定的控制器句柄。如果你调用ConnectController引导服务并指定这个控制器句柄,每个与此控制器句柄相关的驱动程序绑定协议中的Start函数都会被调用。在这个Start函数中,它通过设置一些寄存器来初始化设备,并安装UEFI协议。另一方面,如果你调用DisconnectController引导服务,每个Stop函数都会被调用,所有这些协议都会被卸载,设备被重置。

因此,为了从操作系统劫持设备控制:

  1. 首先,我们调用DisconnectController引导服务来重置设备,意味着清除硬件的寄存器,这样CRCR寄存器将不再指向操作系统的命令环。
  2. 然后,我们调用ConnectController引导服务来为BIOS初始化设备,这样CRCR寄存器将指向BIOS的命令环。

现在,保留的UEFI驱动程序可以使用UEFI协议访问设备。但在恶意行为完成后,我们必须将设备控制权返回给操作系统。这相当困难,因为我们不知道操作系统的命令环在哪里,或者寄存器中设置了什么值,而且我们不能仅仅保存寄存器值并恢复它,因为我们不想包含特定的代码。

幸运的是,我们意识到我们不需要显式地将设备控制权返回给操作系统,因为它们会自我修复。因此,如果Shade BIOS使用NIC并结束其恶意行为,会有几个时刻网络连接中断,但会在不到三分钟内恢复。这可能不是一个优雅的解决方案,但既然我们必须使代码设备独立,我认为这是最好的选择。我们也可以说,这个设备控制权返回问题是Shade BIOS的主要挑战。

问题五:独占控制问题

Shade BIOS会做很多有害的事情,比如更改页表,因此我们需要排除操作系统代码。这意味着我们需要禁用中断。禁用中断最流行的方法是使用CLI和STI指令。但这些不可靠,因为保留的BIOS代码中已经有很多CLI和STI指令。即使里面有一个STI指令,中断也会在之后被启用,操作系统会运行。因此,我们改用CR8寄存器或任务优先级寄存器,因为UEFI驱动程序很少使用这个。

禁用中断排除了操作系统代码,但有人可能会问,BIOS的中断呢?方便的是,UEFI BIOS除了定时器中断外不使用中断。UEFI驱动程序主要使用轮询。因此,大多数UEFI协议实际上在没有中断的情况下工作。定时器中断用于定时器事件,因此一些使用这个的UEFI协议会工作。但我们可以手动触发每个事件并模拟中断。因此,我们不会更改操作系统的IDT,而是模拟定时器中断。

定时器事件被管理为I事件结构的双向链表。例如,当你使用HTTP协议的请求函数时,一些事件结构被插入到这个列表中。每个I结构都有一个触发时间,如果系统时间大于触发时间,则执行事件的Notify函数。是定时器中断处理程序递增这个系统时间。因此,我们可以定位这个链表,并触发每个事件,而不管触发时间如何。这是一种相当粗暴的方式,但大多数事件在从调用函数返回时已经完成,所以这意外地奏效了。


Shade BIOS的优势

现在,保留的代码应该可以正常工作了。接下来,我将通过比较现有的BIOS恶意软件和纯粹的BIOS恶意软件,展示我们如何实现设备独立。

左侧的现有UEFI恶意软件在用户态或内核态执行恶意行为。例如,当它们想要创建一个文件时,会使用C的fopen Windows API或NtCreateFile内核API。该API将向操作系统设备驱动程序发送请求,最终到达硬件。在这个过程中,存在很多被检测到的风险。在操作系统API中,有内置的日志记录功能;在设备驱动程序之间,有反病毒产品的过滤驱动程序等。虽然可以禁用这些,但如前所述,很难禁用所有东西,而且攻击者必须知道目标上运行的是什么杀毒软件,以及该杀毒软件使用什么内核驱动程序。

另一方面,Shade BIOS将使用保留的UEFI驱动程序,而不是操作系统设备驱动程序。因此,它完全独立于操作系统检测和杀毒软件检测。

关于设备依赖性:中间的图片是使用Shade BIOS进行命令与控制通信的代码。这段代码首先调用ConnectController引导服务,从操作系统劫持设备控制权。然后使用HTTP协议进行配置并向C2服务器发出请求。如你所见,没有直接访问I/O,没有直接读写寄存器,它只是使用抽象的接口,如EFI引导服务或EFI协议。因此,相同的代码可以在不同的机器上工作。


演示与检测

我将展示Shade BIOS如何工作的演示。左边是感染了Shade BIOS的受害设备,右边是在端口3033上监听的C2服务器。我想使用这个内核驱动程序,它也会连接到C2服务器,将其视为从现有UEFI恶意软件丢弃的内核级代码。并将其与Shade BIOS进行比较,看它是否会被上层安全机制检测到。在这种情况下,是Windows Defender防火墙。

首先,正常执行这个内核驱动程序,C2服务器收到了这些消息。接下来,我将使用Windows Defender防火墙阻止端口3333,然后再次加载并执行它。这次我们没有收到任何消息。如果我们查看调试消息,它收到了访问被拒绝的状态。

最后,我将使用Shade BIOS窃取这个进程数据。我将使用这个触发程序来触发Shade BIOS。Shade BIOS不需要客户端程序,但这只是为了在正确的时机触发它进行演示。现在执行这个,我收到了秘密数据,它与这个数据匹配。

因此,我们可以说操作系统级安全不影响Shade BIOS。


检测与缓解

Shade BIOS实际上需要一个内核功能,那就是MmGetVirtualForPhysical API。由于时间关系,我跳过原因,但这不会成为检测向量,因为即使检测逻辑被构建到API中,BIOS也可以将整个函数复制到其他地方,禁用安全逻辑,然后使用它。而且这不是一个很大的函数,所以很容易

智能充电,更智能的黑客:ISO 15118 的潜在风险 🔌⚡

在本节课中,我们将要学习 ISO 15118 标准。这是一个旨在提升电动汽车充电效率、便利性和安全性的通信协议。我们将探讨该标准如何改变威胁格局,它解决了哪些问题,以及更重要的是,它可能遗留或引入了哪些新的安全风险。

第一部分:什么是 ISO 15118 标准?🤔

上一节我们概述了课程内容,本节中我们来看看 ISO 15118 标准本身及其引入的背景。

全球电动汽车数量正在急剧增长。有预测表明,到 2040 年,电动汽车数量可能达到 6 亿辆,占全球汽车总量的 30% 至 40%。这对脱碳来说是极好的消息。

但与此同时,电动汽车数量的激增也带来了挑战。这是因为我们的电网并非设计用来在同一地点同时为大量电动汽车充电。当这种情况发生时,电网会面临一种称为“电网压力”的挑战性局面。我们可能会开始经历电压下降。本地电力变压器可能开始损坏,这甚至可能导致局部电网完全断开,即全面停电。

我们还需要理解讨论电网时的第二个问题。这个问题并非由电动汽车引起,而是我们生产和消费电力方式的副产品。如今,我们越来越依赖太阳能和风能等可再生能源。这当然是极好的消息。但与此同时,这也带来了挑战。

因为我们的电网依赖于电力生产量和消耗量之间的脆弱平衡。可再生能源存在风险,因为通过风能和太阳能产生的电量会随天气快速变化。这意味着可再生能源可能在电网中产生电力过剩,我们必须找到使用或储存它的方法。如果我们无法做到,可能会面临严重后果,因为这种情况会使电网频率(即电网的“心跳”)超出安全运行限值。

那么,如果我说电动汽车可以成为解决这两个问题的方法呢?因为我们估计,如今私家车平均有 95% 的时间停在路上。因此,我们实际上可以将停在路上的电动汽车用作分散式存储电池。这将避免西班牙发生的情况。

以下是实现这一目标的两项主要技术:

  • 智能充电:这是一种创新的充电方式,允许充电站改变充电模式。充电站将确保电动汽车仅在电网允许时从电网获取电力,从而解决第一个问题。
  • 车辆到电网通信:这解决了第二个问题。因此,停在我们街上的汽车可以在电力过剩时从电网获取电力。这些车辆将来也可能在电网需要时将电力输送回电网。

ISO 15118 标准的引入实际上是为了让电网更高效,因为该标准支持智能充电和车辆到电网通信这两项技术。这是我们今天的起点。提高电网效率只是该标准的主要目标之一,因为该标准同时也用于通过一项新功能——即插即充——使用户的充电过程更加便利。同时,该标准的引入也是为了改善电动汽车充电生态系统的安全性。

以下是关于标准版本的一些细节:

  • ISO 15118-2 (2014):支持屏幕上显示的所有功能,但车辆到电网通信除外。
  • ISO 15118-20 (2022):完全支持车辆到电网通信。

第二部分:标准如何改变威胁格局?🛡️➡️🔓

上一节我们介绍了 ISO 15118 标准的目标和功能,本节中我们来看看该标准如何影响安全威胁格局。

该标准实际上改善了电动汽车充电生态系统的安全性。它专注于电动汽车和充电站之间的通信链路,并保护一项新功能——即插即充——的通信。如今,如果一辆电动汽车支持 ISO 标准,车辆会存储一个数字证书。该数字证书通过 PKI(公钥基础设施)颁发,并与用户账户绑定。这意味着,当我们将支持该标准的电动汽车插入支持该标准的充电站时,充电站会自动识别电动汽车。如果你拥有电动汽车,你不再需要使用信用卡或实体令牌来验证充电会话,这将通过即插即充自动完成。即插即充还允许充电站从数字证书中提取支付和计费所需的所有信息。同样,我们不再需要使用信用卡。电动汽车和充电站之间流动的所有信息都通过 TLS 加密。

这在威胁方面意味着什么?在标准引入之前,困扰电动汽车充电生态系统的最重大威胁之一是未经授权的充电会话。这是因为充电站严重依赖像 RFID 卡和信用卡这样的实体令牌,这些组件可能被窃取、侧录或克隆。如今这不再可能,因为所有信息都来自数字证书。

只要电动汽车和充电站之间通信链路上的加密保持有效,恶意用户的选项就非常有限。他们需要篡改电动汽车的物理硬件以提取与数字证书关联的私钥,或者他们需要攻破证书颁发机构本身以开始签发欺诈性证书。这非常难以实现。

但该标准也以一种更间接的方式改善了电动汽车充电生态系统的安全性。因为所有支付信息都来自数字证书,这意味着如今有了 ISO 标准,不再是充电站负责管理支付。我们将此责任转移到了后端一个新的集中实体,称为电动出行服务提供商

这在威胁格局方面意味着什么?这一点尤其重要,因为在标准引入之前,我们将管理数据的责任留给了充电站,这导致了一个非常分散的生态系统。一些充电站确实使用了强大的安全措施,但有些则没有。如今,我们将此责任转移到了一个集中实体——电动出行服务提供商,它可以在大规模上强制执行网络安全策略。然而,这种责任转移伴随着一种权衡。在标准引入之前,充电站层面的泄露可能暴露数百或数千辆电动汽车的用户数据。如今,电动出行服务提供商层面的泄露可能同时暴露数百万条数据。但尽管如此,安全性的提升仍然是显著的,因为我们正从一个分散的生态系统转向一个更强大、更紧密的架构。

第三部分:标准遗留与引入的风险 🚨

上一节我们探讨了标准如何改善安全性,本节中我们将视角放大,审视标准范围之外以及因其创新而可能产生的风险。

如果我们只关注标准所做的事情,改进是显著的。这意味着我们会认为电动汽车充电生态系统因为该标准而实际上是安全的。但事实并非如此。我们必须放大视角,尝试理解由于标准的存在,生态系统其余部分发生了什么。

我们要看的第一个部分是充电站,因为充电站是标准范围之外的组件之一。这里我们必须小心,因为这不是标准设计上的缺陷,而是一个深思熟虑的选择,因为标准只关注车辆和充电站之间的通信链路。但标准做了一个假设,这是一个非常危险的假设。标准假设充电站是一个可信实体,充电站是安全的。这个假设可能会适得其反。

事实上,最近的一些审计表明,一些充电站仍然依赖现成的组件(如树莓派),它们仍然有开放的维护接口、开放的后台端口、不安全的远程路径访问。这意味着充电站仍然非常容易受到持续性的入侵。我们不要忘记充电站是公开可访问的,这意味着恶意用户可以去那里进行物理篡改,可以上传修改版的操作系统,可以提升权限以获得完全的 root 访问权限,并通过此实施各种攻击。

如果恶意用户控制了充电站,他可以轻易实施拒绝服务攻击,因为如果我们控制了充电会话,我们可以直接禁用功能。你可以开始意识到标准的第一个矛盾:标准保护了电动汽车和充电站之间的通信链路,但同时,充电站可能完全无法使用。

现在我们可以转向第二个威胁:不安全电力输送。更糟糕的是,我们不要忘记充电站是网络物理系统。这意味着对充电站的攻击将对现实生活或我们自身的现实产生后果。这一点现在尤其危险。ISO 15118 标准实际上有一个协商机制,电动汽车和充电站必须共同协商一个可接受的功率水平。但标准缺乏的是一个强制执行合规性的机制。这意味着在此协商之后,如果充电站被入侵,充电会话可以简单地覆盖设置,并开始输送对电动汽车危险的功率水平,这可能对用户造成安全隐患。

还有第三个威胁:未经授权的充电会话。我们曾认为这种威胁通过标准的引入已完全缓解,但事实并非如此。我们引入了即插即充和数字证书,但标准留下了一个漏洞,因为标准缺乏让充电站与可信时间源同步时钟的机制。这意味着恶意用户可以简单地控制充电站,修改本地时钟,这将诱使充电站接受已吊销或过期的证书。因此,如果我们从更大的视角来看,一些我们认为已解决的问题实际上仍然存在。

现在还有第四类也是最后一类需要分析的风险:新风险。这意味着这些风险在标准引入之前并不存在。这些风险是标准创新(智能充电和车辆到电网通信)的意外后果。为什么我们将这些功能视为攻击向量?再次是因为充电站容易受到入侵。

让我们考虑第一个风险:充电操纵。充电操纵意味着恶意用户试图让他人为他的车辆充电付费。这在智能充电引入后成为可能。如果我们有一个被入侵的充电站,恶意用户可以简单地模拟电网拥堵,这将人为抬高充电站的价格,并迫使许多电动汽车停止充电。你可以想象电动汽车车主返回车辆时发现电池完全没电时的沮丧。

但也有恶意行为者可以实施的更复杂的攻击,其中之一例如是电网攻击。这是一种由车辆到电网通信实现的攻击。让我们想象一个恶意用户同时控制多个充电站。显然,这特别难以实现,但这并不会排除此类攻击,只是将攻击者类型缩小到那些拥有预算、技能和手段的人。如果我们有多个被入侵的充电站,并且它们都连接到同一个本地电力变压器,这些充电会话可以同步进行持续的充电和放电。

这对我们的现实尤其危险,因为这种攻击有可能使电网频率超出安全运行限值。因此,我们将能够人为诱发类似今年早些时候西班牙发生的停电,显然,拥有技能和预算的攻击者能够断开部分或整个国家电网。

总结与关键要点 📝

本节课中,我们一起学习了 ISO 15118 标准及其对电动汽车充电生态系统安全格局的双重影响。

我想要留给大家的主要信息是:首先,我们必须小心。我们必须理解 ISO 15118 标准确实显著改善了电动汽车充电生态系统的安全性,这一点不可否认。但如果我们放大视角,我们也会意识到标准遗留了一些风险,其中一些风险特别危险,并且标准也可能因其创新而引入新的风险作为意外后果。

当我们有一个系统或像电动汽车充电这样的生态系统被标记为符合某个标准时,我们可能会感到安全,但这可能是一种虚假的安全感。你可能感到安全,即使生态系统并不安全。因此,我们必须认识到,真正的安全不仅仅是遵守一个标准。真正的安全需要思维方式的转变。因此,我们不应该只问自己“标准解决了什么?”,而应该问自己“标准改变了什么?”。我们必须放大视角,理解由于标准的存在,整个生态系统中正在发生什么。我们还应该问自己“标准遗留了什么?”,因为新的风险或漏洞常常出现在无人关注的空白地带。

我希望大家离开时记住的三个关键信息如下:

  1. 标准可以改善安全,但也会制造漏洞和安全盲点
  2. 整个生态系统通常基于一系列不同的标准网络。ISO 15118 标准只是我们讨论的生态系统中的一个环节。但今天我们意识到,即使生态系统中有一个组件被某个标准排除在外,整个生态系统的安全性也会面临风险,无论各个组件本身的安全性有多好。
  3. 我们需要超越合规的行动。制定标准是好的,因为它们为我们提供了行动的指导方针。但我们也必须理解,通常一个标准是不够的。我的建议是,所有在电动汽车充电生态系统中工作的利益相关者,如电动汽车制造商、充电站制造商、电动出行服务提供商、电网运营商,都需要团结起来。他们必须理解,我们需要实施超越标准所提供的安全措施。这是我们保证真正安全的唯一途径,也是我们避免因仅仅遵守标准而产生的虚假安全感的唯一途径。

第11届黑帽美国大会网络运营中心(NOC)报告解读教程 🛡️💻

在本课程中,我们将学习如何解读一份大型网络安全会议的NOC(网络运营中心)报告。我们将跟随报告内容,了解一个为两万人提供服务的临时网络是如何搭建、运营,并从中发现有趣的安全趋势和事件的。课程将涵盖网络架构、合作伙伴协作、数据分析以及实际遇到的安全故事。

网络运营团队与合作伙伴 🤝

上一节我们介绍了课程概述,本节中我们来看看负责运营这个庞大网络的团队是如何组成的。

报告指出,舞台上的主讲人并非独自工作。实际上,运营黑帽大会NOC的是一个庞大的团队,由15到20名核心成员及其合作伙伴组成。这个传统始于23年前,当时团队只有三个人,如今已发展到约70人的规模。

仅仅依靠团队自身的力量是不够的。在大约10到11年前,随着大会规模从1500人、15个培训班级扩展到如今的2万人和超过90个班级,原有的开源脚本和商用设备方案已无法满足需求。团队决定寻求厂商合作伙伴的支持。

以下是合作伙伴模式的运作方式:

  • 严格筛选:合作伙伴无法通过赞助进入NOC。团队会像真实客户一样对厂商产品进行演示和评估,选择在特定领域表现最佳的产品。
  • 资源投入:选中的合作伙伴会提供最好的设备、软件,并派遣最优秀的技术人员现场支持。
  • 品牌合作:团队以黑帽大会的品牌影响力作为交换,为合作伙伴提供品牌曝光机会。

这种深度合作带来了显著的效益,各竞争厂商(如Palo Alto和Cisco)的技术人员在现场紧密协作,进行产品集成测试,甚至共同开发新功能。

网络架构与核心组件 🏗️

了解了团队构成后,本节我们来看看这个临时网络的具体架构和使用的核心组件。

整个网络的设计遵循“保持简单”的原则,因为搭建时间只有大约四天,而拆除仅需几小时。目标是确保网络的可靠性和所有数据的安全性。

以下是网络的核心组件与布局:

  • 核心防火墙与路由:由 Palo Alto 设备提供,同时其 Cortex XSIAM 平台负责日志记录、工单管理和自动化。
  • 交换与无线接入:由 Arista 设备提供所有交换机和接入点(AP)。
  • 移动设备管理与DNS:由 Cisco 提供MDM(移动设备管理)、Umbrella DNS等服务。
  • 互联网接入:由 Lumen 提供10Gbps电路。报告提到,即使在高流量时段,网络带宽也远未达到上限。
  • 主动监控传感器:在会场各处部署了多台树莓派(Raspberry Pi)或香橙派(Orange Pi),运行 Cisco ThousandEyes 探针,用于主动发现网络问题。

此外,团队还部署了 Cortex XDR 在所有的传感器端点上,以监控和控制这些设备本身的行为。

网络数据与安全趋势分析 📊

网络搭建完成后,会产生海量数据。本节我们将分析从这些数据中观察到的安全趋势和统计数据。

NOC团队通过各种仪表板实时监控网络状态,并将其作为教育展示。数据显示,在一个本应更懂安全的群体中,网络活动依然充满“混乱”。

以下是一些关键统计数据:

  • 加密流量:今年加密流量比例首次突破 90%,达到91%。过去几年这一比例通常在75%-80%之间徘徊。
  • 数据抓包:捕获了超过 630亿 个数据包,总数据量达 62TB
  • 明文凭证:发现了 62台 主机发送了明文密码,涉及 2800个 唯一的明文凭证。
  • 唯一主机:网络上出现了近 59000个 唯一主机。团队估计只有约50%的参会者连接了大会Wi-Fi,并鼓励更多人连接,以便利用NOC的高级安全设备帮助发现潜在威胁。

尽管黑帽大会网络常被称为“全球最危险的网络”,但这是因为网络上充满了培训实验、工具演示等合法攻击流量。NOC的原则是不轻易阻断流量,以免影响会议活动。他们的目标是在“针堆里找针”,只阻断那些直接攻击核心系统(如注册服务器)或影响网络稳定的真正恶意行为。例如,在监测到的 119万 个威胁告警中,实际只阻断了 7个

技术创新与主动监控工具 🚀

在分析了整体趋势后,本节我们聚焦于NOC团队今年引入的几项技术创新和主动监控工具。

团队持续演进网络能力,今年重点推出了几个新项目以提升主动性和可视化能力。

以下是三项主要创新:

  1. “暗物质”项目:该项目代号“先知”,旨在问题发生前就感知到。通过在会场各处的香橙派上部署无线网卡,模拟客户端持续监测无线网络质量,从而能在用户投诉前就调整信道、优化配置。
  2. VIBES可视化工具:这是一个实时网络流量可视化工具,能将流量分析“游戏化”。例如,当有人在网络上进行nmap扫描时,工具会以动态视觉效果展示。该工具运行在连接100G端口的设备上,能处理完整的流量捕获数据。项目已在GitHub开源。
  3. AI增强型SOC运营:团队利用AI和机器学习来加速事件响应。例如,自动分类网络中的信标流量以识别合法工具;通过分析HTTP POST数据包的熵值来发现可疑内容;对于来自同一教室、攻击目标符合课程内容的告警,系统会自动标记为“黑帽正向”并关闭,让分析师专注于真正的威胁。

此外,团队还集成了模型上下文协议服务器,允许分析师通过自然语言(如在Slack中或XSIAM聊天框内)查询IP地址、MAC地址等信息,快速获取上下文,极大提升了威胁狩猎效率。

真实世界中的安全故事与教训 🕵️♂️

最后,我们通过NOC团队在本次大会上遇到的几个真实安全事件,来总结一些普遍且重要的安全教训。

尽管技术不断进步,但许多安全问题根源在于“信任但未验证”。以下是从实际案例中提炼的教训:

以下是几个典型案例:

  • AI应用的数据泄露:一个韩国搜索引擎的语音搜索功能,前端通信加密,但后端处理查询的令牌却以明文传输。这反映了新兴技术(如AI)若实现不当,反而会引入新的安全漏洞
  • CTF挑战的反向利用:展台上一项针对AI的CTF挑战,旨在诱导AI泄露秘密。讽刺的是,挑战平台本身存在漏洞,导致答案可被窃取。这说明了安全测试环境自身也必须安全
  • 翻译功能泄露:一款群聊应用支持多语言实时翻译,所有消息在翻译环节均以明文传输。这提醒我们,即使核心通信加密,集成的第三方功能也可能成为突破口
  • 地理位置泄露:一款天气应用在向服务器查询时,明文发送用户的经纬度坐标。这已是反复出现的问题,强调用户需谨慎对待应用的位置权限
  • VoIP通话明文传输:一个免费SIP电话服务,所有语音通话内容均为明文,可被轻易还原。这证明了对语音通信的加密验证同样重要
  • 钓鱼不分对象:最令人警醒的故事来自一位黑帽大会演讲者。他的电脑因恶意Chrome扩展程序而被入侵。这表明,无论专业知识多丰富,任何人都可能成为钓鱼攻击的受害者,因此需要对普通用户抱有同理心。

报告最后建议,个人应使用如Wireshark等工具检查家中网络设备及自建服务的通信,确保没有敏感数据在明文传输。

总结 🎯

在本课程中,我们一起学习了如何解读一份复杂的NOC报告。我们从团队与合作伙伴的协作模式开始,了解了支撑大型活动的临时网络如何通过紧密的厂商合作构建。接着,我们剖析了网络的核心架构,看到了从防火墙、交换机到主动探测传感器的完整布局。通过对网络数据的分析,我们观察到了加密流量持续增长等重要趋势,也理解了在特殊环境下“不阻断”策略背后的逻辑。课程还重点介绍了NOC采用的技术创新,如主动监控、AI增强运营和流量可视化工具。最后,通过一系列真实的安全故事,我们得到了“永远要验证”、“任何环节都可能出错”以及“对用户保持同理心”等宝贵的安全实践教训。这份报告生动地展示了,即使在一个高手云集的环境里,基础的安全原则和持续验证依然至关重要。

Black Hat USA 2025 初创企业焦点竞赛全记录 🏆

在本节课中,我们将回顾 Black Hat USA 2025 大会上的“初创企业焦点竞赛”。这是一场汇集了网络安全领域最具创新精神的初创公司的盛会。我们将了解竞赛的背景、评委阵容、四家入围决赛公司的精彩路演,以及最终获胜者的诞生过程。


竞赛开幕与评委介绍 🎤

欢迎来到 Black Hat USA 2025 的“初创企业焦点竞赛”。本次竞赛旨在展示网络安全领域最具突破性的创新解决方案。

本次竞赛的评委团代表了网络安全行业的最前沿。他们拥有多元化的背景,包括首席安全官、风险投资人、行业分析师和资深技术专家,将从产品、市场、投资和技术等多个维度对参赛公司进行综合评估。

以下是评委团成员名单:

  • Colleen Coulett:前 Twilio 和 Segment 首席安全官,擅长构建持久的安全文化。
  • Trarey Fort:前 Black Hat 总经理,前 Salesforce 安全负责人,现任 Bugcrowd 首席安全官,深谙攻防双方。
  • Holly Heesy:Odia 首席分析师,追踪物联网威胁,理解大规模市场模式和趋势。
  • Matthew Martin:拥有25年经验的安全领导者,现任 Two Candlesticks 首席执行官,专注于人工智能驱动的风险咨询。
  • Mata X:前 Rapid7 和 Bugcrowd 高管,现任某公司首席执行官,也是往届 Black Hat 焦点竞赛的获胜者。
  • Lucas Nelson:风险投资合伙人,黑客出身的投资者,精通技术并深谙行业。
  • Robert Stratton:Ma 37 早期基金普通合伙人,入侵检测系统先驱,长期担任初创企业导师。
  • Sid Treveti:Foundation Capital 合伙人,主持“Inside the Network”播客,研究初创企业规模化。
  • Mcalla Vdell:Lineage 增长主管,精通网络安全公司当今最重要的环节——市场进入策略。

在介绍决赛选手之前,我们还要向一些获得“荣誉提名”的优秀公司致意,它们是:Air MDR、Legion、Mind、Mi Tab 和 SquareX。


决赛选手路演:Firetail 🔥

上一节我们介绍了竞赛的评委和背景,本节中我们来看看第一位决赛选手——Firetail。

Firetail 的创始人兼首席执行官 Jeremy Snyder 上台进行路演。他开篇指出,人工智能是自互联网以来最具颠覆性的技术,但企业在采用AI时正在重复过去的安全错误。大多数AI使用处于无监管状态,导致安全事件逐年翻倍。

Firetail 提供端到端的AI安全与治理软件,旨在帮助企业安全团队对AI应用说“是”。其核心功能包括:

  • 持续发现与可视化:通过与云平台和代码环境集成,无需在用户端安装代理或端点软件,即可构建统一的AI资产清单。
  • LLM测试:自动化测试已采用的LLM,识别特定的内容操纵风险。
  • 统一安全态势视图:汇总所有LLM的发现结果,进行优先级排序,并与 OWASP、MITRE 等框架对齐。
  • 治理策略:定义组织内可接受的AI使用策略,并实时监控违规行为。

Jeremy 通过演示展示了产品如何发现AI使用、测试风险并执行策略。他强调,Firetail 独特地结合了AI安全和API安全能力,因为所有的AI交互都通过API进行。

在问答环节,评委们询问了竞争格局、目标用户角色、定价模型(基于系统提示词和日志处理量)以及产品内部各模块如何协同工作。


决赛选手路演:Keepware 🛡️

接下来登场的是第二位决赛选手——Keepware。

创始人兼首席执行官 Ryan Bner 指出,当今绝大多数工作活动都在浏览器中进行,但传统安全堆栈(如CASB、SWG、EDR)中没有哪个工具真正“拥有”浏览器。攻击者深知浏览器存储着关键信息,且是身份的载体。

Keepware 的解决方案是一个轻量级浏览器扩展,它通过嵌入到文档对象模型(DOM)树中,在“点击发生点”提供安全。其核心价值在于:

  • 提供前所未有的浏览器可见性:记录用户在浏览器中的点击、分页行为。
  • 浏览器检测与响应:能够阻止重构的恶意软件、钓鱼攻击等。
  • 与企业安全栈集成:提供浏览器专属的数据模型,可与邮件、网络、端点数据关联,将调查时间从数小时缩短到数分钟。

Ryan 演示了产品如何阻止一次通过“Clear Fake”技术发起的攻击,以及如何阻止一个AI代理落入钓鱼陷阱。他强调 Keepware 的扩展基于API,无需代理或隧道,兼容所有主流浏览器(包括移动端)。

评委们的问题集中在与其它企业浏览器的区别、移动端支持、概念验证流程、定价(按用户/月)、销售对象(安全团队而非CIO)以及目前最具潜力的客户行业(医疗、金融和专业服务)。


决赛选手路演:Prime Security ⚙️

第三位登场的是 Prime Security 的联合创始人兼首席产品官 Dmitri Schwartzman。

Dmitri 以《星球大战》中死星的设计缺陷为例,引出了安全设计审查的重要性。他指出,在AI普及的今天,任何部门都可以快速构建产品,安全设计已成为主要的风险前沿,而传统的人工审查流程不可持续且成本高昂。

Prime Security 旨在成为企业的“AI安全架构师”,在设计阶段识别和缓解风险。其工作原理是:

  1. 集成与上下文获取:连接任务管理系统和云存储以获取业务上下文。
  2. 蓝图与风险发现:提供环境关键组件的高级概览,帮助安全人员发现盲点。
  3. 自动化安全评审:快速对特定项目进行详细评审,生成数据流图、攻击树和具体建议。
  4. 集成到开发流程:将风险和建议直接写入开发者的工作流(如代码助手Cursor)中。

Dmitri 演示了产品如何帮助安全运营人员发现未知项目、快速完成紧急安全评审。他提到,Prime 已经帮助客户实现了近100%的设计阶段可见性,并将安全评审速度提升了10倍。

评委们询问了与企业架构平台的集成、风险建议如何传递给开发人员、如何确保AI生成内容的准确性和一致性,以及如何防止输出“漂移”。Dmitri 强调他们构建了透明的本体论,并像使用工具一样使用AI,核心是“将手动安全经验转化为机器执行”。


决赛选手路演:Twine 🤖

最后一位路演者是 Twine 的创始人 Benny。

Benny 描绘了网络安全防御的未来图景:从静态工具和孤立的专家,转向由AI数字员工组成的动态、协作的智能系统。他指出,身份安全是风险的沉默驱动因素,问题不在于缺乏工具或可见性,而在于认知过载和复杂性。

Twine 推出了首个AI数字员工——Alex。Alex 是一个身份专家,可以像人类分析师一样加入团队,自主调查、探索和解决问题。其核心特点是:

  • 多智能体系统:由多个专用智能体组成,分别负责理解风险、构建工作流、调查环境等。
  • 自主执行:从收集上下文、识别利益相关者,到协作制定缓解计划并最终执行行动。
  • 控制与治理:通过“控制膜”确保AI行为符合预设策略,所有行动均有审计日志和推理过程记录。

Benny 演示了 Alex 如何自主处理一起身份事件。他强调,Twine 的目标不是取代现有IAM工具,而是让这些工具更好地协同工作,让人成为“超级人类”,指挥智能系统。

评委们的问题涉及定价模型(基于身份数量)、AI智能体的治理与控制、如何防止不良分析师“教坏”AI、产品定位(增强而非替换IAM),以及客户的投资回报来源。


往届冠军分享与观众互动 🎉

在评委退场评议期间,2024年的竞赛冠军——来自 Ggnostic 的 Sunil 上台分享了获胜一年的心得。他坦言,赢得竞赛本身并不能保证市场成功,它只是“1%的灵感”,剩下的“99%的汗水”在于团队、执行计划和持续交付价值。他鼓励所有参赛者,即使没有获胜,也要充分利用入围带来的关注度。

随后,主持人邀请四位创始人回到台上,接受现场观众的提问。观众通过扫码进行实时投票,问题涵盖了初创公司在AI浪潮中的定位、数据隐私、品牌建设以及各自的获胜信心等。现场投票显示,Prime Security 和 Twine 暂时领先。


最终结果揭晓 🏅

评委团经过审议,最终将冠军奖杯授予了 Prime Security!评委们认为,Prime Security 精准地切入了一个长期存在且日益严峻的痛点——安全设计评审的自动化和规模化,其解决方案务实且具有清晰的商业价值。


课程总结 📚

本节课中,我们一起深入了解了 Black Hat USA 2025 初创企业焦点竞赛的全过程。我们认识了多元化的专家评委团,并详细学习了四家顶尖网络安全初创公司的创新解决方案:

  1. Firetail:专注于AI安全与治理,提供从发现、测试到策略执行的端到端平台。
  2. Keepware:通过轻量级浏览器扩展,在点击点提供安全,实现前所未有的浏览器活动可见性与防护。
  3. Prime Security:作为“AI安全架构师”,在设计阶段自动化安全评审,将安全左移并融入开发流程。
  4. Twine:开创性地推出AI数字员工,旨在通过多智能体协作改变未来网络安全防御的运作模式。

最终,Prime Security 凭借其解决核心痛点、清晰的执行路径和团队执行力赢得了本届竞赛的冠军。这场竞赛不仅展示了网络安全领域最前沿的创新方向,也体现了从创意到成功需要团队、执行和市场策略的完美结合。

追踪拖拉机:分析与利用智能农业自动化系统 [OxnY_25suS8] 🚜

在本节课中,我们将学习如何分析一个流行的智能农业自动化系统。我们将从市场背景开始,逐步深入到系统的网络通信、硬件交互和安全漏洞,最终展示如何远程控制拖拉机转向系统。本教程旨在让初学者理解物联网设备安全研究的基本思路和方法。

概述与背景 🌾

上一节我们介绍了课程主题。本节中,我们来看看智能农业自动化兴起的背景。

农业数字化是当前的热门话题。现代农场的各个方面如今都可以通过数字化技术进行增强。例如,目前最常见的增强技术是GPS辅助耕作。

GPS辅助耕作的范围很广,从仅仅获取田地的GPS信息,到实现拖拉机在田地里自动行驶的全自动化。

除了自动化,该领域也有积极的研究。因为这些组件的技术表面正变得越来越互联。该领域完成的大多数汽车研究也是经典的汽车研究,例如针对CAN总线或ECU的攻击。

但也有更专门和具体的研究。例如,在某个会议上,有研究者展示了他能够入侵一台拖拉机并在上面运行《毁灭战士》游戏。

除了主动研究,也有实际的攻击案例。例如,瑞士的一位农民遭遇了勒索软件攻击。但中招的不是他的普通电脑,而是他的挤奶机器人。

系统如何工作?🔧

上一节我们了解了农业自动化的背景。本节中,我们来看看这类自动化系统具体是如何工作的。

一个典型的自动化系统如下图所示。在屏幕右侧,你可以看到一个转向系统。这是一个售后解决方案,可以帮助你实现拖拉机自动化。

整个装置由一个方向盘、一个作为人机界面(HMI)的平板电脑和一个GPS天线组成。它的价格并不昂贵,大约在5千到1万美元之间。这与一台起价往往高达百万美元的新拖拉机相比非常便宜。

为了让你更好地理解系统如何集成,下图展示了其布线方式。你安装一个平板电脑,替换掉某个部件,再安装一些传感器,然后就可以出发了。这样基本上就把任何主要品牌的拖拉机变“智能”了。

它适用于各种跟随式农机。你还可以集成像犁或其他附加硬件到拖拉机上。

剩下唯一要做的就是定义你的田地,决定你想在田地里以何种模式行驶。下次你开着拖拉机去田地时,只需点击播放,就可以自动耕作你的田地。

市场与目标系统 📊

在真正开始研究这些主题和设备之前,我们做了一些市场调查,看看哪些系统更常见。因为我们住在中欧,我们关注了在中欧销售的系统,有两个主导品牌。

一个是AgroDynamics,另一个是Alice Vi/Viacmo。如果你再往东看,例如在俄罗斯,你会看到Navomo。这是一个不同的供应商,但系统类似。

我们设法弄到了一台F.G.T.和一台React系统。结果发现,它们是同一个系统。因为F.G.T.是系统的制造商,而例如Svak只是同一系统的贴牌产品。

这对我们来说实际上是个好消息,因为我们知道现在问题不仅影响一两个设备,而是影响了自动化市场的很大一部分,因为这是两个主导品牌。

系统架构与通信协议 📡

上一节我们确定了研究对象。本节中,我们来剖析目标系统的架构和通信方式。

我们对目标系统(82系统)有一个粗略的概述。我们有三个组件:

  1. 82 HMI 平板电脑,基本上是农民从驾驶舱操作的界面。
  2. 我们的电机和方向盘。
  3. 拖拉机顶部的GPS天线,它从卫星获取GPS坐标。

系统通过HTTPSMQTT协议与位于中国的Aerodynamic云服务器通信。你还可以使用一个蓝牙遥控器来远程控制你的82平板电脑。

MQTT是一种轻量级的发布/订阅消息传输协议,常用于物联网产品中,用于在不同MQTT客户端之间交换消息。我们有一个中央代理服务器。

我们最初的焦点是监控外发流量。我们有一个加密的MQTT协议连接。通信是加密的。

我们遇到的问题是,我们想查看流量中发生了什么。但由于设备是租用的,我们不能修改它,必须归还。所以我们面临需要解密流量的问题。

我们做了常见的尝试,比如重定向流量,并验证是否存在某种TLS利用问题,因为这是在不修改系统本身的情况下最简单的方法。

结果发现,TLS验证根本不存在。系统不验证任何类型的TLS证书。

这对我们来说是个好消息,因为这样我们就获得了客户端设备连接到代理服务器的凭证。

凭证提取与云访问 🔓

上一节我们发现系统不验证TLS证书。本节中,我们来看看如何利用这一点获取访问凭证。

我们只是打开了一个原始网络套接字,并将MQTT流量重定向到那里。这是一个原始十六进制转储的MQTT数据包。

在绿色字段中,你可以看到客户端ID。这类似于HTTP中的用户代理,是一个任意文本字段。在底部的蓝色字段中,你可以看到产品名称和密码。

但真正奇怪的是,设备没有使用其序列号,而是使用了产品名称“82”。所有设备都使用相同的用户名和相同的密码。这已经有点可疑了。

然后我们想,好吧,我们只用MQTT Explorer(一个常用的客户端)来使用这个协议,输入密码和用户名,应该就能行了。结果发现不行。

因为他们也使用了客户端TLS证书。这是我见过的最奇怪的TLS组合之一,因为一方面他们没有TLS验证,但另一方面他们在使用用户名和密码之前却使用了客户端TLS证书。

所以我们的下一个任务基本上是提取证书以进行身份验证。

我们有两个选择:要么实际逆向整个应用程序,或者至少是处理证书的部分,但它被混淆了;要么使用Frida。Frida是一个用于各种动态二进制插桩的非常酷的工具。所以我们使用该工具的自定义脚本来从应用程序中转储各种TLS密钥。

这样,我们就得到了TLS客户端证书。现在我们能够访问代理服务器了。我们现在能够访问云基础设施,并查看发送到代理的是哪种消息。

例如,在下图的红色区域,你可以看到系统将其GPS坐标发送到代理,并通知“我已移动”,然后更新系统的地图。

在这个代理上,有各种不同的主题。例如,我们有位置更新的主题。例如,如果车辆参数发生变化,比如农民在拖拉机上安装了不同的系统或硬件。

还有“函数调用”功能。这有点意思,因为它暴露了许多不同的函数。

安全漏洞与影响 ⚠️

上一节我们获得了云系统的访问权限。本节中,我们来探索其中存在的安全漏洞及其潜在影响。

但现在的问题是,我们进行这项研究已经超过一年了。在这一年里,基础设施发生了变化。最初的情况要弱得多,因为最初只是所有设备使用相同的用户名和静态密码。

密码只有两个字符和数字2020。后来他们改成了销售注册服务。所以现在所有设备都使用自定义密码和自定义用户名向代理注册。

然而,这对我们来说是个好消息,因为最初我们只能访问欧洲的代理,因为我们只有欧洲的设备。但现在,我们突然可以访问他们在不同地区的所有代理了。所以我们现在能够访问美国、中国和俄罗斯等地的数据。

然后我们想,我们现在能做什么?我们测试了不同的测试用例。例如,我们测试了如果使用一个不存在的设备序列号会发生什么。系统直接接受了。你可以用一个根本不存在的序列号、密码和用户名登录。所以它只依赖于你提供的密码。然后你就可以说“嘿,在这个设备上”,系统会说“没问题”。

我们还可以尝试冒充不同的拖拉机。例如,我们从朋友那里知道不同拖拉机有不同的序列号。我们有一些这样的序列号。我们尝试了,结果成功了。你可以登录并冒充另一台拖拉机。

但事实上,如果你能冒充一台拖拉机,为什么不冒充所有拖拉机呢?

结果发现,两个字符就搞定了。这是一个MQTT多级通配符,它基本上告诉代理:“嘿,代理,我现在想要所有主题和所有消息。”

代理回答说:“好的。”

于是我们突然获得了大量数据,并访问了连接到这个代理的数千台设备。

例如,在红色区域,有600台拖拉机连接,产生了80000条消息。这只是打开50秒的数据量。

数据量如此之大,以至于我们遇到了真正的问题,因为突然之间,我们的系统开始崩溃,因为内存耗尽,因为我们收到了如此多的MQTT流量。

所以我们不得不为此构建一个自定义工具。我们称之为“Tractor Hackney”。它基本上就是接收所有这些MQTT数据并摄取它们。我们必须处理每秒大约10万条消息。

下图展示了架构。我们有连接到其本地云代理的所有拖拉机,然后我们使用我们的工具连接到这个代理并获取所有数据。

由于他们有自助注册服务,我们现在可以访问所有这些代理。

数据分析与隐私泄露 📍

既然我们获取了数据,我们现在可以进行一些分析了。在几个月的时间里,我们看到了大约44,000个系统。

大多数系统在亚洲运行,因为这是中国供应商的产品。但排在第二位的是欧盟,那里有大约5,000个这样的系统。在美国,目前只售出了大约300个系统。

我们看到的数据包括各种不同的GPS数据。所以我们知道农民在他的日常操作中在做什么。我们知道他住在哪里,他耕种哪些田地,他使用什么对等地址,有时还知道他使用什么电子邮件地址(例如,当他们彼此共享田地时)。

所以这里面有各种隐私数据。

但我们也进行了可视化。例如,在美国,你可以看到它们在全国各地行驶。也在不同的州。在左边,你可以看到一个放大的例子,例如,他们也在公共道路上使用该系统。所以并不是他们用系统主动驾驶,而是他们没有正确关闭它。所以它也在公共道路上使用。

在欧盟国家,如果你在公共道路上行驶,必须关闭这个系统。但根据我们掌握的GPS状态,我们知道农民们没有这样做。所以他们不是主动驾驶,只是没有正确关闭电源。

然后我们开始查看拖拉机的位置。我们看到这些拖拉机出现在一些疯狂的地方。例如,其中一台距离乌克兰前线20公里,时间大约是凌晨3点。

所以你可以看到,这带来了各种影响,我们现在突然可以追踪世界各地的拖拉机。我们还看到一台拖拉机靠近朝鲜,在韩国行驶。

主动攻击:锁定与通知 🚫

上一节我们看到了被动读取数据的风险。本节中,我们来看看如果主动向拖拉机发送数据会怎样。

问题是,你能发送给拖拉机的命令相当有限。你只有一些命令可以发送。但这些命令是“锁定”和“发送通知”。

“锁定”基本上会锁定设备,你无法再操作它。拖拉机仍然可以正常操作,但自动化功能完全消失。你可以发送通知,所以你可以骚扰他们,例如发送一些消息。

问题是,代理服务器没有适当的授权机制,所以每台拖拉机都可以向其他任何拖拉机发送通知。

我们有一个简短的演示视频。你可以看到系统处于正常操作状态,驾驶员处于自动模式,正在正常的田地里操作。

突然,你看到一个弹出消息“拖拉机现在被锁定”。你可以指定任何你想写的内容。然后自动化功能就消失了。

这对于所有连接到系统的拖拉机都是可能的。所以突然之间,所有系统都可能瘫痪。只有供应商可以恢复系统,所以每个农民都必须打电话给供应商来解锁。但攻击者可以再次发送这个命令,然后你又会被锁定。

所以代理服务器有一些非常严重的漏洞。

深入硬件:转向系统接管 🎮

上一节我们展示了云端的攻击。本节中,我们更进一步,看看如何攻击转向系统本身。

我们也想到,系统在公共道路上使用。如果我们能入侵方向盘呢?如果我们能接管方向盘,例如把拖拉机开进沟里,或者突然让它偏离道路。

所以我们开始更多地研究转向系统本身的工作原理。

转向系统由HMI、方向盘和一些GPS传感器组成。HMI本身只是一个安卓平板电脑。然而,供应商对其进行了锁定。所以你不能只启动任何应用程序,它只启动供应商的默认应用程序。

但它没有正确实现锁定。所以你可以启用ADB访问来获取系统设置,然后你至少拥有了一些shell访问权限。

在普通的安卓设备上,你现在需要利用一些漏洞来获取完整的root权限。但是,这不是一个普通的安卓设备,因为事实证明,设备基本上是root了的。

因为我们只用了大约五分钟就root了设备。我们把它放在桌子上,启动,点击用户界面,连接USB-C,然后我们就有了root权限。因为供应商需要root权限来运行他自己的代码。

我们查看了代码,想知道为什么他们无论如何都需要root权限。结果发现,在安全功能方面他们有点懒,因为他们没有为访问安卓系统内的其他设备实现适当的授权机制。

所以他们在里面有子系统。在安卓中,这些只是原始串行设备。要访问它们,你需要一个适当的权限系统来进行适当的授权。但他们没有,他们只是放了SU二进制文件,然后执行他们自己的代码。

但这对我们来说是个好消息。所以我们拥有了安卓系统的root权限。

但我们想远程实现这一点。

远程Root与OTA漏洞 📲

我们遇到了很多死胡同。我们尝试了很多方法。例如,我们尝试通过代理发送恶意消息来获得某种代码执行。然而,你可以从代理发送的命令相当有限,而且它也只落在安全的Java代码中,这些代码不容易受到任何内存损坏或其他问题的影响。

我们还尝试通过网络。例如,它是否暴露了任何服务?没有,它没有暴露任何服务。

这给我们留下了以下三种攻击途径:

  1. 通过物理访问,我们可以直接root,但这不能构成一个技术攻击向量,因为我们需要物理接触设备。
  2. 通过蓝牙进行RCE。系统本身已经过时,容易受到一些众所周知的安卓蓝牙漏洞的影响。而且有公开的漏洞利用程序。然而,你需要蓝牙配对,而且漏洞利用程序导致系统崩溃的次数比给你shell的次数要多。
  3. 我们开始研究一些我们可以进行中间人攻击并替换服务器响应的方法,从而触发HMI本身的代码执行。

这就是OTA(空中下载)更新的用武之地。出于某种原因,供应商在这方面真的搞砸了,因为他们没有为此进行传输加密,也没有任何形式的验证或签名。

通常,当你有某种固件更新或OTA更新时,你会有某种强非对称签名来防止篡改镜像。在这种情况下,他们只使用MD5校验和。我想我们可以计算那个值。

在屏幕右侧,你可以看到一个典型的请求。它说:“嘿,是时候更新了。我们正在更新到版本25。这是你需要下载的URL。”

这就像教科书般的“路过式下载”例子。所以如果你在中间,你可以用任何你想要的二进制文件替换它。因为设备是预root的,这导致了完整的root代码执行。

但是中间人攻击总是很难实现。你必须处于相邻位置,而且扩展性不好。这对我们来说扩展性不好,但众所周知,例如国家行为体或高级威胁组织能够对互联网连接执行中间人攻击。

所以虽然我们不能大规模利用这个漏洞,但他们很可能可以。

攻击本身非常简单。你成为中间人,替换响应。例如,在这种情况下,你只需将其替换为自定义URL。你必须计算MD5校验和,替换底部的代码。这很重要,否则客户端不会接受。

你还可以添加自定义消息,比如“这是一个病毒,相信我,我是海豚”。如果你这样做,用户会看到这个有趣的对话框。如果农民说“哦,状态实例是合法的”并接受它,我们就获得了完整的root权限。

这是一个有趣的例子,但真正的攻击者可以使用更恶意的内容,或者结合社会工程学来让农民安装系统或更新。

作为概念验证,例如,我们使用Metasploit作为一个简单的PoC。你可以看到APK正在从网络下载,然后Metasploit会话启动。所以远程root这个设备也相当容易。

因为它已经root了,我们已经拥有了root访问权限。

转向协议逆向与最终控制 🛠️

在这一点上,我们通过网络拥有了完整的root权限。但问题是,距离转向系统还有很长的路要走,因为转向系统本身由多个组件组成。

你有这个安卓平板电脑,然后你有一个ECU,这是一个嵌入式设备,它接收来自安卓平板和IMU(惯性测量单元)的多个输入。IMU是方向传感器,用于了解拖拉机的水平程度。

ECU结合其输入,然后做出转向决策,该决策随后被发送到电机控制单元(MCU)。然后MCU是实际转动方向盘的设备。

所以我们的下一个任务是技术问题。然而,这是一个租赁设备。通常,我们会打开它,连接JTAG,或者获取某种闪存转储来进行分析。但这对我们来说不是一个选项。

所以我们唯一的选项要么是直接刷新安卓平板电脑,要么是逆向用于转向的协议。

所以我们选择了安全的方式,逆向工程了协议。但这花了我们一些时间,因为二进制文件只是200KB的原始ARM汇编,没有符号,没有字符串,什么也没有。我们不知道它采用的确切指令集,也不知道里面使用了什么操作系统。

我们的策略基本上是寻找一些具有高密度条件语句和高密度魔数(magic bytes)的函数,因为这通常是数据包处理程序的样子。在某个时刻,我们找到了一个基本上指定了协议外观的函数。

我们逆向了这个子函数,清理了代码,并得出了以下协议规范。

在这里,你可以看到可能用于转向系统的各种命令。至少我们认为这些是正确的命令。在右侧,你可以看到不同的数据包或数据包结构。

数据包总是以0xEC91开头,有一些头部。最重要的字节是第16个字节,因为第16个字节是命令字节,它基本上告诉转向系统你发送的是哪种命令。

例如,这是一个航点配置命令,它指定你从A点行驶到B点。所以在命令字节之后,你有命令负载,在这种情况下是四个浮点值,代表两次的纬度和经度。

重要的是,仅仅发送像左转或右转这样的命令是不够的,因为那是不可能的。你必须指定一条特定的路线,说“嘿,我们从A点行驶到B点再到C点”。然后ECU决定如何到达那个点。所以系统本身对方向盘没有直接控制。

所以如果你想创建一个劫持方向盘并只是左转或右转的PoC,我们必须计算一个相对于当前位置的90度角来实现,例如,一个急转弯。

整合攻击:演示与影响 🎥

有了协议规范,我们离接管方向盘很近了,因为我们还需要一样东西:正确的通信流程。

因为事实证明,你需要多个数据包来控制方向盘,因为你需要向ECU发送心跳包。如果你停止心跳,ECU会关闭。你需要指定航点,例如,告诉转向系统从A点行驶到B点的配置,指定一些配置参数,然后是执行命令。

但在你发送这些类型的命令之后,方向盘开始转动。如果你想要一个完整的攻击者控制,你还需要注意必须停止原始应用程序,否则它会干扰转向。

我们把所有这些整合到了这个演示中。

在这里,例如,系统处于操作状态。它处于被动模式。例如,有些人在公共道路上使用它。你可以正常使用拖拉机,但它是预root的,只需轻按开关,转向就被接管了。

问题是,转向电机相当强大。所以你现在有两个选择:要么开始与方向盘争夺控制权,要么你足够快地关闭系统。但这基本上只需要一瞬间就能把拖拉机开进沟里或导致翻车。

意外发现:割草机与机器人 🤖

但在开始,我们说过我们最终到达了某个不同的地方。事实证明,供应商还有很多其他设备连接到同一个代理。

在某个时刻,我们看到一个函数调用叫做“拍照”。我们想,这是怎么回事?为什么,谁在拍照,为什么拖拉机会拍照?结果发现那不是拖拉机,而是更多东西。

同一个供应商也在制造连接到同一个云基础设施的割草机。割草机如何操作?它们基本上只是用摄像头拍一张照片,上传到云存储,然后通过代理发送云存储URL。因为我们正在监听代理,我们看到了这些云存储图片的URL。

通常,当你有云存储时,会有某种签名或令牌来保护你,这样你就不能直接从那里下载图片。供应商在这方面也搞砸了。

所以突然之间,我们拥有了来自世界各地、不同大陆的多个割草机的完整摄像头访问权限。我们突然有了来自不同割草机的一系列视频流

揭露与应对 TJ Actions 供应链攻击 🛡️

在本节课中,我们将学习一起真实的 GitHub Actions 供应链攻击事件。我们将了解攻击是如何被发现的、攻击者的具体手法、事件的影响范围,并从中总结出关键的防御经验。


GitHub Actions 与 TJ Actions 简介 🚀

上一节我们概述了本次课程的主题,本节中我们来看看事件的核心组件:GitHub Actions 以及被攻击的 TJ Actions “change-files” Action。

GitHub Actions 是 GitHub 于 2019 年 11 月推出的 CI/CD 平台。它迅速成为托管大量开源和企业 CI/CD 管道的默认选择。

以下是一个示例的 GitHub Actions 工作流:

name: Sample Workflow
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: tj-actions/changed-files@v44
      - run: echo "Deployment steps..."

这个工作流运行在 GitHub 提供的 Ubuntu 虚拟机上。它包含多个步骤,其中前几个步骤使用了来自 GitHub Actions 市场的现有 Action。GitHub Actions 市场拥有超过 25000 个可复用的 Action。

GitHub Actions 工作流可以消费机密信息,例如云凭证、发布密钥等。当工作流需要机密信息时,GitHub 会将其提供给运行在虚拟机上的 runner.worker 进程,然后该进程再将其提供给工作流中的相应步骤。关键在于,所有第三方 Action 都运行在同一台虚拟机上,因此它们本质上共享主机内存空间。

请注意,工作流通过发布标签(如 v44)来引用这些 Action。GitHub 标签默认是可变的,这意味着攻击者可以在创建后将 v44 这样的标签重新指向另一个提交。


被攻击的 Action:TJ Actions Changed Files 🔍

现在,让我们聚焦于本次事件的核心——TJ Actions “changed-files” Action,并理解它为何如此流行。

该 Action 的功能是:找出在给定提交或拉取请求中被修改的文件列表。在我们的示例工作流中,如果 PR 修改了 infrastructureterraform 目录中的文件,它就会执行 Terraform 部署步骤,否则跳过这些步骤。这本质上节省了计算时间和资源,因此该 Action 被广泛用于从内部工具到生产管道的各种场景。


攻击是如何被发现的 🕵️♂️

上一节我们介绍了被攻击的 Action,本节中我们来看看这次攻击是如何被安全产品检测到的。

如果你反复运行那个工作流,并从 CI/CD Runner 监控其出站网络调用,你会看到类似下图的基线。这张截图来自我们的产品 Step Security Harden Runner,但重点在于方法论而非工具本身。

在正常情况下,工作流会调用 github.com(由 actions/checkout 发起)以及 aws.amazon.comhashicorp.com(部署步骤)。然而,在 3 月 14 日,同一个任务发起了一个对 jsdkgithubusercontent.com 的新调用。由于该任务从未向此目的地发起过出站调用,这触发了检测。

调查发现,这个调用来自 TJ Actions Changed Files Action,并且是通过 curl 下载一个名为 mem_dump.py 的文件,这非常可疑。


攻击手法:冒名顶替提交与标签劫持 ⚔️

既然这个 Action 开始进行新的出站调用,那么其内部必然发生了改变。调查发现,就在几小时前,该 Action 的所有发布标签都被修改,指向了一个恶意的提交。

当我们首次在 GitHub 上打开这个恶意提交时,提交信息看起来是无害的。但我们注意到一个黄色文本框中的提示:“此提交不属于此仓库的任何分支,可能属于仓库外部的 Fork。” 这是如何发生的?一个仓库的发布标签怎么能指向一个甚至不在该仓库中的提交?

答案就是“冒名顶替提交”。这种提交不存在于原始仓库中,而是存在于仓库的一个 Fork 里。但由于 GitHub API 的工作方式,这些提交可以从原始仓库访问。在这个案例中,恶意提交存在于 TJ Actions Changed Files 仓库的一个 Fork 中,但仓库的发布标签可以指向它。

以下是攻击者创建冒名顶替提交并更新现有发布标签的步骤:

  1. 攻击者 Fork 目标仓库。
  2. 他们在自己的 Fork 中创建一个包含后门代码的恶意提交。
  3. 他们将现有的发布标签(如 v35)更新,指向他们的恶意提交。

一旦完成,所有使用该标签的 GitHub Actions 工作流将自动开始执行恶意代码。


恶意载荷分析:窃取 CI/CD 凭证 🧨

现在让我们看看 TJ Actions 攻击中使用的冒名顶替提交具体做了什么。

提交中包含一个 Base64 编码的字符串,它被解码并作为 Shell 脚本执行。解码后,我们发现这是一个仅在 Linux Runner 上有效的攻击脚本。

该脚本从知名的公共 GitHub Gist 下载 mem_dump.py 文件并执行它。mem_dump.py 会遍历主机上的运行进程列表,寻找名为 runner.worker 的进程。找到后,它会打开该进程并转储其全部内存。

这正是窃取秘密的关键。之前提到,当工作流需要机密信息时,GitHub 会将其提供给 runner.worker 进程。mem_dump.py 转储其内存后,会在其中搜索 CI/CD 秘密。

攻击者还使用了一个巧妙的技巧:双重 Base64 编码。GitHub 会自动屏蔽 Base64 编码格式的秘密,因此单次编码的秘密会被隐藏。然而,如果使用双重 Base64 编码,GitHub 就不再将其识别为秘密,这些编码后的秘密会以明文形式出现在构建日志中。

总结一下,TJ Actions 冒名顶替提交的执行链如下:

  1. 从公共 Gist 下载 mem_dump.py
  2. 执行脚本,转储 runner.worker 进程内存。
  3. 在内存转储中搜索 CI/CD 秘密。
  4. 将窃取的秘密以双重 Base64 编码格式输出到构建日志。

在事件发生后的几个小时内,攻击者已经从数千次工作流运行中窃取了秘密,包括云凭证、访问密钥、数据库密码等。


攻击链溯源:从 ReviewDog 到 TJ Actions 🔗

我们已经看到了被攻击的 Action 做了什么,现在让我们尝试理解这个 Action 最初是如何被攻破的。

TJ Actions Changed Files 仓库本身有一个工作流,使用了 tj-actions/eslint-changed-files Action。这是一个复合 Action,由多个 Action 组成,其中之一是 reviewdog/action-setup Action。正是这个 reviewdog/action-setup Action 首先被攻破,进而导致了 TJ Actions Changed Files 的沦陷。

reviewdog/action-setup 被攻破的方式与 TJ Actions 类似:攻击者创建了一个冒名顶替提交,并将其 v1 标签指向它。当 TJ Actions 的运行工作流使用 reviewdog 时,一个持久的个人访问令牌被泄露在构建日志中。攻击者随后利用这个令牌,更改了 TJ Actions Changed Files 的标签。

那么 reviewdog Action 又是如何被发现的呢?这源于独立安全研究员 @nthncanhan 在 X 上的帖子。他通过检查构建日志发现,在某个时间段内,reviewdog/action-setupv1 标签指向了一个不在其仓库中的提交(即冒名顶替提交),从而确定了其被攻破的事实。

reviewdog 组织存在一个设计缺陷:如果任何人在其组织下的仓库创建拉取请求并被合并,该人会自动获得对 reviewdog GitHub 组织的写入权限。reviewdog/action-setup 正是通过窃取其中一位维护者的个人访问令牌而被攻破的,而该令牌又是从 spotbugs/spotbugs 仓库泄露的,这本身又是一次由拉取请求漏洞引发的连锁供应链攻击。


事件时间线与攻击者策略 📅

这是整个调查的时间线:

  • 3月14日:我们识别出 TJ Actions Changed Files Action 被攻破。
  • 接下来3小时:我们通知社区和维护者,并告知一些泄露凭证的公共仓库。
  • 次日 14:00 UTC:GitHub 移除了 TJ Actions Changed Files 仓库,导致所有使用它的工作流停止运行(近24小时内,相关构建日志仍在泄露凭证)。
  • 同日 22:00 UTC:GitHub 恢复了已清理的仓库,所有标签不再恶意。
  • 3月18日:确认 reviewdog Action 是最初的突破口。

攻击者非常狡猾:

  1. 隐藏网络痕迹:TJ Actions 的载荷从高信誉域名 jsdkgithubusercontent.com 下载,许多安全解决方案会盲目信任此类域名。reviewdog 的载荷则直接嵌入在提交中,无需网络调用。
  2. 使用冒名顶替提交:使得仓库活动看起来正常,在分支和提交历史中找不到恶意代码。
  3. 冒充合法用户:例如在 TJ Actions 的冒名顶替提交中,攻击者试图冒充 renovate-bot


经验教训与防护建议 🛡️

在本次演讲的最后一部分,让我们看看从这些事件中可以汲取的具体建议和经验教训。

以下是具体的防护建议:

  1. 对 CI/CD Runner 实施安全监控
    许多组织监控了桌面和生产环境,但 CI/CD Runner 或构建服务器通常缺乏监控。你可以使用开源工具(如 WazuhFalcoTetragon)收集出站网络流量、进程和文件写入事件信息,将其与 CI/CD 管道关联,建立基线并构建异常检测。

  2. 为 GitHub Actions 使用允许列表
    GitHub Actions 市场有超过 25000 个 Action。通过允许列表,你可以建立一个流程,规定组织中允许使用哪些 Action。

  3. 将第三方 Action 固定到不可变的提交 SHA
    在此次事件中,那些已将 TJ Actions Changed Files 固定到某个提交 SHA(而非主要或语义化标签)的组织基本未受影响。

  4. 制定针对 Action 泄露的事件响应计划
    事件发生后,手动响应非常繁琐:需要查找所有使用被攻击 Action 的工作流文件,检查攻击窗口期内所有工作流运行的构建日志,识别并轮换泄露的持久化凭证。因此,提前制定自动化或半自动化的响应计划至关重要。

攻击者的计划是:攻破一个流行的 GitHub Action,更改其标签指向恶意提交,然后坐等数千次工作流运行在构建日志中泄露凭证并加以收割。但他们没想到的是,基于 CI/CD Runner 的基线安全监控能够快速识别此类异常。


总结 📝

本节课中,我们一起深入分析了一起复杂的 GitHub Actions 供应链攻击事件。我们学习了攻击的发现过程、利用“冒名顶替提交”和标签可变性的攻击手法、以及从 reviewdogTJ Actions 的连锁攻击链。最重要的是,我们总结了四条关键防护建议:监控 Runner、使用允许列表、固定提交 SHA 以及制定事件响应计划。供应链攻击已从理论变为现实,我们必须提高警惕,加固自身的 CI/CD 管道安全。

通用且上下文无关的触发器,用于精确控制大语言模型输出 [W8zzpTGVHRE] 🔐

在本节课中,我们将学习一种新型的提示注入攻击方法——通用对抗触发器。我们将了解其背景、原理、攻击演示以及如何生成这种触发器。这是一种能够跨不同上下文精确控制大语言模型输出的强大攻击手段。

背景:提示注入威胁的演变 🚨

上一节我们介绍了课程主题,本节中我们来看看提示注入攻击的背景及其演变过程。

大语言模型及其应用近年来发展迅速。与此同时,提示注入已成为一个日益关键的攻击向量。

早期,大语言模型主要是独立的聊天或内容生成工具。提示注入依赖于直接的用户输入或网页内容脚本,以诱骗模型产生有害内容甚至错误答案。其影响相对有限。

随后,大语言模型被集成到更复杂的工作流中,例如检索增强生成系统。通过污染这些工作流动态检索的数据源,攻击者可以将恶意提示注入工作流,从而破坏整个流程。

如今,我们正进入AI智能体时代。这些智能体可以通过代码编辑器、浏览器等多种工具直接与现实世界交互。这极大地提高了风险。提示注入不再仅仅导致错误信息,还可能造成代码后门、数据泄露甚至整个系统被攻陷。

传统提示注入的局限性 ⚠️

上一节我们回顾了提示注入的演变,本节中我们来看看传统方法的局限性。

传统上,提示注入通常涉及两个步骤。

首先,攻击者试图逃离原始提示的上下文。这通常需要理解提示结构。因此,攻击者常尝试用“描述你的任务和角色”、“有哪些可用工具”等短语来泄露上下文。然后,他们尝试使用各种技巧进行越狱,例如要求模型忽略之前的指令或扮演一个不受限制的角色。

第二步是重定向模型的注意力到被劫持的任务上,即控制模型的响应。

以下是常见的被劫持任务:

  • 生成不道德内容,例如教人制造炸弹。
  • 产生错误答案,例如将狗分类为猫。

然而,这种传统方法有显著的局限性。越狱步骤需要对每种场景进行手动分析和精心设计。这些手工制作的注入高度依赖于上下文,无法在不同应用间复用。对于劫持步骤,攻击者通常需要更精确的输出控制,例如生成一个每个字符都至关重要的Shell脚本,或创建格式正确的JSON以传递给下游工具。此外,攻击者也希望造成比仅仅一个不道德响应更严重的安全后果。

这些局限性促使我们寻找更好的方法。

理想的攻击与通用对抗触发器 💡

上一节我们探讨了传统方法的不足,本节中我们来看看理想攻击应具备的特性以及我们提出的新范式。

我们认为理想的提示注入应具备四个关键属性:

  • 通用有效性:我们希望将攻击解耦为可复用的触发器加上可定制的有效载荷,使同一触发器能在不同应用中生效。
  • 高可访问性:无需复杂的注入技术,即使经验不足的黑客也能实现高成功率。
  • 精确控制:攻击者能可靠地指定希望模型响应的确切内容。
  • 安全后果:例如系统接管。

这似乎是一个不可能的组合,直到现在。

这里我们介绍通用对抗触发器,我们认为它代表了一种新的提示注入攻击范式。受对抗触发器学术研究的启发,我们将这一理论概念发展成了实际的现实世界威胁。

让我通过例子来说明这个想法。

左侧是针对文本生成任务的攻击。对话以定义模型角色的系统提示开始,它应该分析政策的利弊。原始用户消息本应讨论提供免费大学教育,但它被注入了恶意内容。注入由三部分组成:一个触发器前缀、一个有效载荷和一个触发器后缀。有效载荷是黑客希望模型输出的确切文本。它被一对触发器包围,触发器是一系列对人类来说大多不可读的标记。但当它们被大语言模型处理时,会迫使模型忽略其他指令,仅用有效载荷进行响应。你可以看到模型响应:“哈哈,我被黑了。我会做任何你想做的事。”

右侧是针对文本转SQL任务的类似攻击。系统提示描述了以JSON格式构建SQL查询,正常的用户消息请求从表中读取一些客户数据。但攻击者注入了要求模型生成恶意SQL命令的内容,该命令将从表中删除客户数据。

两个例子都使用了模型 Llama-2-7B-Instruct,这是一个流行的开源模型。屏幕上显示的触发器字符串是专门为此模型训练的。因此,无论原始任务、注入位置或有效载荷内容如何,只要使用相同的目标模型,这些触发器就保持有效。

请注意,我们已屏蔽了触发器中的一些标记。这是为了防止攻击者直接复制我们的触发器造成实际损害。

我们认为这是一种新的任务范式,因为它具有以下优势。最重要的是,触发器无需修改即可应用于许多攻击场景。根据我们的实验,它在不同的提示上下文和有效载荷中实现了约70%的成功率。一旦人们获得这些触发器,他们可以简单地将任何有效载荷插入模板中。它可以是JSON、XML或任何他们希望模型输出的内容,这可以大大降低提示注入的成本。我们很快将演示,这种范式甚至可以轻松地在AI智能体上导致远程代码执行。

攻击演示:远程代码执行 🎬

上一节我们介绍了通用对抗触发器的概念,本节中我们通过两个演示来看看它的实际攻击效果。

第一个演示将展示我们如何使用触发器攻击Open Interpreter。Open Interpreter是一个智能体,允许用户通过自然语言界面操作他们的计算机系统。

在播放视频之前,我将描述技术流程。当用户要求Open Interpreter检查他的邮箱时,智能体会编写一段Python代码来访问电子邮件。攻击者之前已经制作并发送了一封恶意电子邮件给用户。当智能体读取包含被触发器包围的Shell命令的电子邮件时,就会发生提示注入。这将迫使模型以特定格式输出Shell命令,以便被Open Interpreter传递并执行,从而为我们提供一个远程Shell。

第二个演示展示了在Cursor上实现远程代码执行。Cursor是一个广泛使用的Web编码助手,作为VSCode扩展运行。代码智能体用户通常会安装MCP服务器来扩展智能体功能。攻击者可以发布一个看似良性的MCP服务器,等待其获得一定流行度后,更新MCP描述以包含触发器和有效载荷。开发者通常会为安全命令启用自动批准功能,如果模型确定命令安全,这将允许Cursor无需用户确认即可执行命令。在我们的有效载荷中,我们将Shell命令嵌入XML格式,并将requires_approval标志设置为false。因此,当模型输出此XML有效载荷时,Cursor将在无需进一步用户确认的情况下执行命令。为了防止MCP工具进行恶意活动,一些开发者会将MCP服务器隔离在沙箱中。然而,这在我们这种情况下没有帮助,因为MCP描述仍然会被注入到提示中,并且Shell命令是在用户的VSCode终端上直接执行的,而不是在隔离环境中。

技术细节:如何发现触发器 🔬

上一节我们看到了触发器的强大威力,本节中我们来深入了解如何发现它们的技术细节。

以下是大语言模型处理包含触发器的输入的过程。首先,大语言模型使用提示模板将聊天消息转换为输入字符串。该字符串包含攻击者控制的注入输入,加上由应用程序决定的周围文本。然后,分词器将输入字符串转换为标记ID。我们将使用不同颜色表示提示上下文标记、触发器标记和有效载荷标记。模型中的嵌入层将每个标记映射到一个高维向量,称为标记嵌入。这些嵌入被输入到一个复杂的神经网络中,该网络将计算词汇表中每个标记的概率分布。然后,模型通过随机采样决定下一个输出标记。生成的标记被追加到输入序列中,该过程为后续输出标记重复进行。

为了获得对抗触发器,这里的核心思想是通过找到好的触发器标记,来最大化输出所需有效载荷标记的概率。因此,这可以公式化为一个数学优化问题。

输入包括前部的提示上下文、触发器前缀、有效载荷、触发器后缀以及其后的提示文本。我们希望最大化模型在给定输入标记的情况下输出有效载荷标记的概率。由于我们有多个有效载荷标记,这可以表示为各个标记概率的乘积。然后我们通过对概率取对数,并在我们的训练数据集上对有效载荷长度取平均,将其写为损失函数。前面还有一个负号,因为损失应该被最小化。

为了确保生成的触发器具有通用性,训练数据集应包含多样化的提示上下文和目标输出。除此之外,我们还需要一个好的优化算法来搜索触发器标记。

我们构建了一个数据处理流水线,通过将正常对话转换为对抗训练数据来生成训练数据。基础训练数据来自公共指令数据集,其中包含多样化的指令遵循示例。我们还添加了一些包含智能体对话模式(如Web编码对话)的领域特定数据。转换流水线会随机选择注入位置,并生成一些恶意有效载荷,例如错误答案、偏离主题的响应和恶意命令。这些有效载荷被包装在不同的格式中,包括纯文本、JSON和XML。

对于优化算法,我们不能直接将梯度下降应用于触发器标记,因为标记是离散值。这是一个根本性的挑战,因为梯度下降算法需要通过计算损失函数对输入变量的偏导数来获得方向性指导。

为了解决这个问题,HotFlip方法在2018年被提出。它使用标记嵌入空间的梯度来估计当我们用一个标记替换另一个标记时,损失函数如何变化。假设L(A)是使用输入标记A时的损失,L(B)是将标记A替换为标记B后的损失。我们可以使用这个方程来估计L(B),这是标记嵌入空间中的一阶泰勒展开。为了找到最小化估计损失的标记,我们只需要选择其嵌入向量产生最小点积的标记B,如黄色背景所示。

虽然HotFlip告诉我们使用什么替换标记B,但贪婪坐标梯度算法告诉我们替换哪个原始标记A。该算法将每个标记位置视为一个可以操作的坐标。它随机采样几个标记位置,并为每个位置找到最小化估计损失的前K个替换候选。然后它测试这些候选的实际损失,并仅保留最佳位置及相应的替换。这个过程将迭代重复,直到损失收敛。

由于算法相当数学化,如果您想了解更多细节,可以参考我们的论文。我们将在最后提供一个链接。

实验结果与局限性 📊

上一节我们深入探讨了触发器的生成原理,本节中我们来看看实验结果以及当前方法的局限性。

我们在三个开源模型上测试了上述方法:Qwen、Llama和Devtro Small。结果表明,在经过约1000次迭代步骤,在一个包含超过10000个对话的数据集上训练后,发现的触发器在不同任务中实现了约70%的成功率。

我们测试了触发器的可迁移性。我们发现,在同一模型家族内存在一定的可迁移性,例如从Llama-3-8B迁移到拥有700亿参数的更大Llama模型,或从Qwen2-7B迁移到较新的Qwen2.5-7B,成功率保持在60%左右。然而,在我们的实验中,触发器无法跨模型家族迁移。

我们的方法有几个局限性。它需要白盒访问,因为我们需要模型权重和梯度信息来训练触发器。生成的触发器字符串通常对人类没有意义,可以通过一些基于困惑度的过滤器检测到。训练触发器需要大量的计算资源,我们总共需要大约10万次大语言模型调用来找到一个好的触发器。此外,如前所述,触发器无法跨模型家族迁移,这意味着攻击者无法在开源模型上训练,然后直接在专有模型上使用它们。

总结与问答环节 🏁

在本节课中,我们一起学习了通用对抗触发器这一新的大语言模型攻击范式。它降低了成功进行提示注入攻击的门槛。这些触发器的存在威胁着AI智能体的安全设计。我们通过将梯度引导优化应用于开源模型,证明了此类触发器的存在。

请记住,大语言模型默认是不可信的。我们应始终在沙箱中运行智能体,并实施适当的安全控制。

感谢聆听。如果您有兴趣了解更多关于我们的研究,可以通过下面的电子邮件地址联系我们。您可以在列表上阅读我们的论文和一些相关文章。


问答环节

:关于你展示的计算概率和损失的方程,概率是用触发器、有效载荷和后缀计算的。那么触发器是否依赖于有效载荷本身?换句话说,你能替换有效载荷并仍然得到相同的损失吗?如果你生成了那些触发器,之后能否将其用于未在触发器计算中使用过的其他有效载荷?

:问题是,触发器是否依赖于有效载荷?是的,我们希望触发器独立于有效载荷,以便同一触发器适用于所有类型的有效载荷。在数据集中,唯一的变量是有效载荷本身和上下文。触发器是我们在训练过程中要发现的东西。所以,你可以基于任意有效载荷生成触发器,然后使用相同的触发器搭配不同的有效载荷。

:目前由于需要访问权重来创建触发器,所以不可能(攻击专有模型)。你认为未来有可能泛化触发器吗?例如,通过搜索多个触发器,然后尝试找到能在多个模型上工作的那些。

:我们还没有测试过,但有可能,比如同时在不同模型上训练触发器,或者独立使用它们然后组合起来,那样也许能在专有模型上奏效。

Unix Underworld:探索z/OS的黑暗面 [课程编号:3wQHhGxVTuo] 🔍

概述

在本节课中,我们将学习IBM大型机操作系统z/OS中一个关键但常被忽视的组成部分——Unix子系统。我们将探讨其安全模型、常见的攻击路径,以及如何利用已有的Unix知识来理解和测试这个平台的安全性。你会发现,你对于“入侵”大型机所了解的知识,可能比你想象的要多得多。


演讲者介绍

我是Chad Rikansrud,一名软件安全研究员,就职于Broadcom。我的工作是发现大型机软件中的漏洞。我成长于90年代的“黑客小子”文化,热衷于逆向工程和突破限制。

我是Philip Young,Netsby公司的大型机渗透测试总监。很多人也叫我“Fortran战士”。同样,我也是一名90年代的“黑客小子”,并且是大型机网络安全的狂热爱好者。

我们两人在这个领域合作已有十年。此外,我们还要感谢Mark Wilson,他在我们之前就开始了这方面的工作,是我们进入这个领域的引路人。


什么是大型机?

早期的“大型机”指的是装满CPU的“主框架”,其余部分只是输入输出设备。如今,整个系统可以集成在一个机柜中。这样的系统每天都在处理价值数十亿甚至数万亿的交易。

金融、政府、大型零售商、医疗保健、航空和航运等行业都依赖这个平台。它的高可靠性和稳定性使其默默无闻地支撑着现代社会。


关键术语

在深入之前,我们先了解几个核心术语:

  • RACF: 外部安全管理器。你可以将其类比为Active Directory,负责控制身份验证和授权。它是IBM的产品,本课程主要讨论它,但原理也适用于其他ESM(如ACF2、Top Secret)。
  • APF授权: 授权程序设施。这是一个操作系统控制机制,决定你的进程是否能在CPU层面获得超级用户权限。
  • 特殊属性: 用户在RACF中可能拥有的特殊权限。拥有这些属性,你在RACF中的权力几乎是无限的。
  • Key 0: 大型机上所有内存都有一个关联的存储键。进程也有一个键。通常,进程只能读写相同键的内存。Key 0是一个特殊的键,允许读写任何内存。

了解这些术语有助于我们理解后续的攻击路径。


破除神话

十年前,当我想开始测试这个平台时,经常听到这样的说法:“大型机不可能被入侵”、“它有神奇的防护”。如今,这种观念正在改变,但仍有部分人认为这个平台固若金汤。

本课程的目标之一就是打破这个神话。


攻击路径概览

如果你在其他平台(如x86、ARM)上进行过安全测试,那么大型机的攻击路径对你来说会非常熟悉:

  1. 网络攻击: 使用TCP/IP、Web应用等,与其他平台完全相同。
  2. 文件系统攻击: 针对MVS数据集和Unix文件,原理相同。
  3. 外部安全管理器配置错误: 安全设置不当,与其他平台无异。
  4. z/OS Unix子系统: 这是我们本节课的重点。

z/OS Unix(也称为Unix System Services、OMVS或z/OS UNIX)是z/OS的一个Unix-like接口。它不是一个容器,也不是独立的操作系统,而是一个接口。对许多人来说,这是了解大型机的“入门途径”,因为它非常熟悉。


探索Unix子系统

在z/OS Unix中,你会发现熟悉的元素:

  • Shell: 例如 sh
  • 分层文件系统: 从根目录 / 开始。
  • 文件系统权限: 采用三组八进制位(读、写、执行),与Linux/Unix相同。

你可以通过TSO的 oshell 命令或直接使用 ssh 访问它。运行一些命令,你会发现操作方式与你熟知的Unix环境几乎一致。


枚举工具

在渗透测试中,第一步通常是信息枚举。以下是一些可用于z/OS Unix的开源工具:

  • enum.rex: 一个REXX脚本,从内存中提取信息(如安全配置),有时能访问到通常无法直接获取的数据。
  • OMVSEnum.sh: 基于LinEnum,用Shell编写,进行大量检查,包括在RACF中的访问权限,帮助从Unix内部分析系统。
  • ZShog: 类似于TruffleHog,用于在Unix文件系统中搜索密码、令牌等敏感信息。

所有这些工具都是开源的。我们通常会将所有脚本打包成一个JCL文件上传,以解决文件传输和编码(EBCDIC/ASCII转换)的问题。

枚举时,我们还会尝试进行“出站测试”,扫描外部网络。令人惊讶的是,许多大型机拥有直达互联网的开放连接。


枚举结果分析

通过枚举脚本,我们可能会发现以下问题:

  1. RACF数据库信息: 例如,密码是否仍在使用较弱的DES-based算法加密,而非更强的AES-based算法(KDFAES)。
  2. 无需密码切换为rootsu 到root用户时不需要密码。
  3. 危险的文件权限: 例如,在 /bin 目录下发现全局可读、写、执行(777)的shell脚本或配置文件。
  4. 特权挂载能力: 拥有进行特权文件系统挂载的权限。
  5. APF授权能力: 能够成功执行 extattr +a 命令,为程序添加APF授权位。

ZShog 工具可能会在文件中发现明文存储的凭证,例如 .properties 文件中的用户名和密码。


演示攻击影响

发现漏洞后,我们需要证明其影响。

攻击1:利用存储的凭证
最常见的问题是凭证以明文形式存储在权限设置不当的文件中。例如,一个被设置为777权限的脚本中包含数据库凭证。攻击者可以直接读取并使用这些凭证。

攻击2:SSH密钥注入
如果我们能 su 到root(即使无需密码),我们可以在root的 .ssh/authorized_keys 文件中添加我们自己的公钥,从而获得持久的root shell访问权限。这在Unix层面是“游戏结束”。

攻击3:利用APF授权实现权限提升
这是更高级的攻击。首先,我们需要理解APF授权。

  • CPU状态: z/Architecture CPU有两种状态:问题状态(普通)和管理状态(特权)。特权指令(如切换内存键)只能在管理状态下执行。
  • APF控制: 操作系统通过APF授权控制哪些程序可以切换到管理状态。在Unix中,程序通过 extattr +a 命令获得一个APF授权位。
  • 攻击流程
    1. 通过枚举发现拥有运行 extattr +a 命令的权限(需要访问 BPX.FILEATTR.APF 配置文件)。
    2. 编写一个汇编程序,其核心是执行 PC(程序调用)指令切换到管理状态和Key 0。
    3. 在Unix中汇编、链接该程序。
    4. 使用 extattr +a 命令为该程序添加APF授权位。
    5. 运行该程序。成功后,进程便拥有了Key 0权限。
  • 绕过RACF: 仅拥有Key 0还不够,因为RACF仍在检查你的权限。RACF将用户权限缓存在一个称为ACEE的控制块中。我们的攻击程序可以利用特权,在内存中为另一个高权限用户(例如Phil)伪造一个新的ACEE,然后修改我们进程的指针指向这个伪造的ACEE。这样,当RACF检查权限时,就会认为我们是Phil。

攻击4:特权挂载攻击
z/OS Unix的文件系统挂载点背后是MVS数据集。APF授权位存储在这些数据集内部。

  • 如果我们拥有特权挂载的能力(通过特定RACF权限或root身份),就可以进行以下操作:
    1. 在测试环境中创建一个ZFS文件系统。
    2. 在其中放置我们编写的攻击程序,并为其设置APF授权位和setuid位。
    3. 卸载该文件系统,并将其打包。
    4. 在目标系统上上传、恢复并特权挂载这个文件系统。
    5. 运行其中的程序,系统会认可我们在其他系统上设置的APF授权,从而实现权限提升。

缓冲区溢出

许多Unix程序是用C语言编写的。长期以来,人们认为大型机上无法进行缓冲区溢出攻击,直到有人证明了其可能性。

如果存在缓冲区溢出漏洞的程序同时是APF授权的,那么利用该溢出就可以直接获得我们之前讨论过的管理状态和Key 0权限。你可以使用 find / -type f -ext a 命令轻松查找所有APF授权的程序。

关于大型机缓冲区溢出的深入技术细节,可以参考Jake Laperruque和Chad Rikansrud在Defcon上的演讲,以及他们提供的Github workshop材料。


其他攻击面

  • ESM权限覆盖文件系统权限: 如果配置了RACF来管理Unix文件系统安全,它可能会覆盖文件本身的权限位。这可能导致两种情况:1) 文件显示为777但你无法访问(更严格);2) 文件权限正确但RACF给了你访问权(更宽松)。这可能会造成混淆。
  • 全局可写的关键文件: 例如,在 /bin 中发现全局可写的shell脚本,该脚本在用户登录时执行。攻击者可以直接编辑它以获得持久化访问。
  • Web应用漏洞: 大型机上也运行Web应用。我们曾发现存在本地文件包含漏洞的Web应用,通过它可以访问原本无法读取的Unix文件。

防护与检测建议

防护措施:

  1. 检查文件权限: 定期审计,避免全局可读/写/执行的文件。
  2. 限制高危权限: 以下RACF权限应严格控制,最好仅用于“应急”账户,而非日常账户:
    • BPX.SUPERUSER
    • BPX.FILEATTR.APF
    • BPX.DAEMON
  3. 启用Unix文件系统审计: 使用 ls -E 查看文件的审计属性。管理员可以配置系统,对关键文件的所有访问尝试(成功和失败)生成日志。将审计属性从默认的 f(仅失败)改为 a(全部)。

检测措施:

  1. 分析系统日志(SMF): 关注成功和失败事件。
    • 频繁的 su 到root成功记录。
    • 频繁的APF授权操作。
    • 对文件的大量未授权访问尝试(表明有人在扫描)。
    • 大量的出站TCP连接(表明可能存在扫描或数据外泄)。
  2. 实施出口过滤: 严格限制大型机直接访问互联网,避免开放SMTP中继等风险。

社区与致谢

大型机安全社区正在不断成长。我们要感谢所有为此做出贡献的研究人员和社区,如Moshax的YouTube频道和Discord、Share上的大型机网络安全社区等。同时,也要感谢IBM等公司与我们进行的建设性合作,共同提升平台安全性。


总结

本节课我们一起探索了z/OS Unix子系统的安全世界。我们了解到:

  • 大型机并非无法入侵,它面临着与其他平台相似的安全挑战。
  • 你的Unix知识是理解和测试这个平台的强大基础。
  • 常见的攻击路径包括配置错误、权限滥用、APF授权漏洞和缓冲区溢出。
  • 通过使用现有的工具和方法论,并理解平台特有的概念(如RACF、APF、Key 0),你可以有效地对大型机进行安全评估。

记住,安全是一个持续的过程,在这个古老而关键的平台上也不例外。

个人信息的利用与滥用 —— 政治版 📊

在本节课中,我们将学习一个为期五年的研究项目,该项目通过创建虚假身份订阅2024年美国大选周期的政治新闻简报,来追踪和分析政治实体如何收集、使用及分享个人信息。我们将探讨其研究方法、核心发现以及对个人隐私的启示。


概述与背景

我们通常以创造性方式探讨如何衡量个人信息及其在互联网上的传播。这个名为“个人信息的利用与滥用”的项目已进行了约五年。

今天讨论的重点是,我们决定注册约1400个虚假身份参与2024年美国大选周期,旨在理解政客们如何使用我们的信息、他们发送了什么内容,以及我们能从中得出哪些结论。

在开始之前,需要感谢弗吉尼亚理工大学的团队。过去五年中,多位教员参与了该项目。此外,还有来自21个不同专业的130名本科生为此工作,这使得该课题成为一个涉及多学科的、普遍令人感兴趣的话题。

该项目始于大约五年前。2021年,我们在一次仅使用175个虚假身份的简单实验后进行了汇报,当时更侧重于企业实体及其信息共享行为。

在那次实验中我们学到了很多教训,或许比实际收获更多。但在共享行为方面,我们观察到一些非常有趣的现象:排名第一的是,企业实体不会共享信息,因为我们是他们的盈利对象。而我们确实看到共享行为的地方,实际上来自政治实体。这引发了我们的兴趣:如何大规模地量化这种现象?

这促使我们在2022年期间致力于实现自动化,使其不再是一项繁重的手工操作,而是能够大规模进行。我将提供更多相关信息。这只是使用相同框架的多个实验之一,但今天我们聚焦于政治讨论。


动机与定义

有人可能会问我们为什么这样做。从根本上说,这甚至超出了个人隐私的影响范围。当我审视选举时,160亿美元是一大笔钱。作为一个更偏向数学家思维的人,我自然会想:我们花的钱值吗?我不知道。这相当于烧掉了32头由百元美钞堆成的大象。我们得到了相当于多少套中等价位房屋的价值?客观地看,过去20年美国民众对政客的整体满意度一直在下降。

因此,即使在进行这项研究时,我们也会尽力保持中立,对双方都进行一些善意的调侃。总的来说,我们试图理解他们的行为模式。

首先给出几个定义。当我们说OSN(开源情报)时,大多数人想到的是被动OSINT,这几乎像是吸收互联网或其他公开来源上所有可用信息。重要的是要记住,当你在互联网上进行交互时,你自然在进行信息交换,因为你必须请求对方发送特定数据。

主动OSINT与此的区别在于,我可能会发送更多信息,这可能实际上帮助对方弄清我的身份或关于我的某些事情。但这仍然是一种交换,只是往往更深入,甚至可能随着时间的推移建立完整的对话。因此,就定义而言,被动和主动之间的区别比教科书上所说的更为模糊。


实验设计:核心概念

当我们审视整个实验,让你感受一下我们所谓的“利用与滥用”时,基本流程是:我们生成尽可能逼真的虚假身份,可以想象成一个非常优秀的伪随机数生成器,或者基于人口统计平均数据。我们尽最大努力使其看起来真实,或者在地址等情况下故意造假——我们实际上会去美国邮政服务核实,确保创建的地址不是真实的,不会有人因此收到垃圾邮件。

然后,我们使用这个虚假身份进行一次性的在线交易。在这个实验中,就是注册新闻简报账户。我们试图表达的是:“嘿,政客们,请发送所有你们用于竞选宣传的信息。”

一个重要的后续结果是:我们只使用那条信息一次。因此,如果我们从第三方收到任何类型的信息或内容,我就知道我没有与他们分享过。所以,我提供信息的那个候选人,我知道他们参与了分享那个虚假身份的行为,尽管他们并不知道那是假的。他们已将个人身份信息分享给了其他人。因此,我们收到的每一点内容,都可以追溯到最初的那次交易。

你将看到的整个实验,基本上是我们在大约18个月期间(从初选到选举后六个月)收集的电子邮件和语音邮件。

必须说明的是,背后有很多复杂工作。我很乐意在讲座后提供更多细节。但当你看到我们如何生成虚假身份,以及如何结合开源工具来创建一个非常简化的注册流程时,我确实对团队帮助我们整合的内容印象深刻。

用最简单的术语来说,当我审视一次注册时,我们已将其缩短到每个账户大约2到3分钟。想象一个坐满本科生的房间,很多披萨飞来飞去,这是一支非常廉价但大脑神经网络优秀的劳动力。我们基本上为他们提供:左边显示的是虚假身份及其所有属性。他们只需要点击按钮、复制,然后粘贴到需要的地方。我们记录他们使用了哪些个人身份信息,这样我们就有了未来追踪使用了哪些实际信息的记录。

通常每个流程需要2到3分钟。当我们遇到验证码或其他双重验证时,我们有一个网络钩子和其他工具来实时简化他们获取信息的过程。


政治实验的具体设置

回到这个具体的政治实验:我们在初选前尝试注册了总共1400个账户。在这种情况下,我们只是说:“嘿,给我们你新闻简报上的所有信息。”我们涵盖了不同的政党、不同的竞选等。我们生成了许多额外的身份,在某些情况下,我们为同一个候选人注册了多个身份,但有意改变身份的某些方面来进行或多或少的A/B测试。

我们认为,围绕人口统计或身份政治的政治因素会是一个大问题,考虑到所有的新闻报道。但结果完全不是这样。你在个人身份信息图表中可以看到,根本没人问过这些。对他们来说,我们几乎只是一个电子邮件地址,可能还有一个名字。


电话与语音邮件分析

接下来,我们将把话筒交给Ja,让他开始谈谈我们在数据中实际看到的情况。

就像Alan提到的,我们注册了电子邮件和电话线路。我们先看看电话线路,因为结果不太令人兴奋。我们收到了超过34,000通电话和超过7,000条语音邮件。如果你看向右边,可以看到我们接到电话或语音邮件的时间线,高峰出现在2024年6月。

我们可以进一步将其分解为一天中的时间和一周中的星期几。如果你看向左边,那是一周中的星期几,大部分通话发生在周一至周五。至于一天中的时间,则是在上午8点到下午6点之间。这些时间 conveniently 遵循呼叫中心和诈骗者的模式。我们之所以这么说,是因为我们实际上聆听了每一条语音邮件,并将其归类到更广泛的类别中,以帮助解释其内容。

我们发现,只有203条语音邮件实际上是政治相关的。其中,民主党人留下的语音邮件最多。但非常令人惊讶的是,超过一半的语音邮件实际上是某种诈骗,这强烈表明诈骗者在随机模拟我们的号码。

我很好奇,有没有人设置过类似的电话交换或网络语音?我们可能花了18个月,相当于10个人兼职投入了这项巨大的努力。我必须说,看到一旦你预留了号码,它们或多或少就被前用户污染了,这令人失望。

我想向在座可能更熟悉这一领域的人发出呼吁:如果我们能想出一个简单的验证方法,哪怕只是说“哦,那条电话线实际上正在电信公司或交换机中使用,然后让通话通过”,我们就能消除99%的垃圾电话,从我们看到的电话情况来看是这样。


电子邮件数据分析

由于语音邮件和电话的结果有些平淡,我们现在将转向电子邮件,因为从中我们能够发现更多信息。

我们注册了大致相同数量的民主党人和共和党候选人,但我们从民主党人那里收到的电子邮件几乎是共和党人的两倍。如果我们看向右边,你还可以看到不同分支(众议院、参议院和总统)的细分。民主党显然是其中两个分支的最大发送者,他们只在总统选举中输给了独立党派。

与语音邮件类似,我们可以展示收到这些电子邮件的时间线。你可以看到某些事件导致了峰值,例如,当特朗普赢得密歇根州初选时,民主党和共和党发送的电子邮件都大幅增加。在拜登与特朗普辩论之后,你可以看到民主党第二天发送的电子邮件显著增加。

关于选举,你可以看到在此之前,共和党人在单日发送了最高数量的邮件,但选举之后,所有政党的邮件数量都显著下降。

再往右看,你实际上可以看到从初选到选举期间我们收到的电子邮件总量。这进一步强调了我们从民主党那里收到的电子邮件数量之多,因为他们每天的邮件量再次接近翻倍。在顶部你还可以看到乔·拜登的照片,因为他是我们所有账户中发送量最高的,平均每天10.2封邮件。

同样,我们可以将其分解为一天中实际收到邮件的时间。你可以看到,民主党人遵循典型的朝九晚五工作制,但共和党人则更有趣,他们倾向于在清晨和夜间发送,而在中午时分显著放缓。

考虑到我们收到的所有电子邮件,我们想知道:时间承诺是多少?如果你要阅读某个候选人的每一封电子邮件,你需要花费多少时间?我们发现,你需要阅读来自不同分支的候选人约10到100小时的电子邮件。底部显示的是共和党总统候选人,这表明我们相信他们实际上更多地使用其他形式的媒体来进行竞选宣传。而在顶部,参议院民主党人需要93小时的纯阅读时间。

我认为这里真正的启示是:实际上没人在阅读这些内容。所以在某种程度上,我不知道他们为什么发送这么多次。


内容分析:关键词与主题

接下来,我们决定看看不同的总统候选人使用了哪些词语。这些是词云图,显示了不同政党使用词语的频率。词语越大,使用频率越高。我们移除了捐赠相关的关键词(稍后会谈到),但一旦移除这些词,你可以看到每个候选人基本上都喜欢谈论自己。

你可以看到我们使用了典型的民主党标志、典型的共和党标志在中间。但在右边,由于RFK是发送量最高的独立候选人,根据新闻报道,我们用一只熊作为他的标志。在下方,你还可以看到不同候选人及其每天发送的电子邮件数量的细分。再次强调,拜登是发送量最高的,哈里斯紧随其后。共和党人数量显著下降,而独立人士则有许多候选人至少每天发送一封邮件。

正如Jared提到的,开始审视内容,看看他们实际发送了什么。词云图仅基于频率给你一个概览。我们试图更聪明地思考,在理想情况下,他们应该试图传达什么信息,比如“我喜欢我”。起初我们认为,也许是他们在不同政治纲领中声明的问题。结果根本不是。

然后我们变得更愤世嫉俗,认为也许这与那些向他们捐赠大笔资金的人更相关,谈论与某些大捐赠者相关的问题。再次令人惊讶的是,也不是。

为了快速解释你在这里看到的内容:这是两个不同政党的比例,显示他们有多少次在电子邮件中提及某个词。内圈显示包含该词的电子邮件数量,外圈显示该关键词被提及的次数。所以一个词可以在一封邮件中出现一次,但可以被提及多次。

由此你可以看到,像“生殖”是被提及和使用最多的词,它出现在总共2115封电子邮件中,但被提及了总共3203次。这些是差异较大的关键词,它们遵循我们熟知的各政党的典型趋势。你知道,三个是他们党内的关键问题,另一个是用来抨击对方候选人的。

这些是差异较大的关键词。但让我们惊讶的是那些实际上非常相似的词语。就是这些词。我只想强调一个词:被提及最多的词是“北约”,它出现在4367封电子邮件中,但被提及了总共7184次。我将在几页幻灯片后解释为什么强调这些点。

但既然我们在黑帽大会,我们认为可能也应该看看安全相关的词语。我来黑帽大会大概有十年了,这是第三次在这里演讲。我想,哦,我会查查“Cil”,查查“网络”。他们关心我们所做的任何事情吗?简短的回答是:他们对所有网络问题的总和关心程度,还不如对UFO的关心。


核心动机:捐赠与投票

所以,这些才是真正重要的关键词。主要是让你捐款或获取你的选票。如果你还记得两页幻灯片前,我提到“北约”被提及了7000多次。而“捐赠”这个词出现在17000封电子邮件中,被提及了52000次。所以很明显,所有候选人发送这些电子邮件的真正目的,要么是获取你的选票,要么是让你捐款。

唯一被提及次数接近的话题,实际上是“特朗普”。为了更好地展示这一点,我们制作了这些方形饼图,显示一个候选人被提及的次数,但不是由他们自己提及的。如果你看左边,那是民主党人。他们在电子邮件中提及唐纳德·特朗普超过11000次。同样,右边的共和党人,你可以看到他们也最常谈论特朗普,但他们提及乔·拜登大约9000次。

然而,相当令人惊讶的是,卡玛拉·哈里斯被两党提及的次数都比乔·拜登少。这可能是因为,你知道,当她被确立为总统候选人时的情况。所以我们不是说这有明确的原因。但对于民主党方面,他们实际上提及RFK的次数超过了卡玛拉·哈里斯,这进一步证明,除了捐款和让你投票之外,这才是主要问题。这是一种个人崇拜,无论你是支持还是反对你所在政党的总统候选人。


捐赠行为的影响

然后我们想,他们一直在说捐钱、捐钱、捐钱。这似乎是他们关心的。我们决定试一试。遵循所有FEC法律,我现在开始向广泛的范围捐赠5美元,这可能一开始就让人困惑。我们想看看,如果我们有一个虚假身份捐了微不足道的5美元,而另一个根本没捐,他们对待这两方的方式有何不同?简短的回答是:他们确实区别对待。我们发现,电子邮件数量增加了大约2.5倍,他们现在请求更多捐款的紧迫性实际上增加了约20%。

所以请注意,如果你曾经给他们你的电子邮件并且捐了款,你现在就在名单上了。


可读性与情感分析

从关键词退一步,我们将看看更一般的统计数据,特别是可读性。这里使用的是Gunning Fog指数,它查看特定电子邮件的句子长度以及该邮件中每个单词的复杂性,并给出0到20的分数,这代表预期能够阅读该电子邮件所需的年级水平。

我们发现两党非常相似,他们撰写电子邮件的阅读水平大约在九到十年级。令人惊讶的是,我们发现受教育程度较高的政客实际上撰写了更简单的电子邮件,而受教育程度较低的选区收到的电子邮件更难阅读。这相当令人惊讶,因为你可能会预期情况相反,因为受教育程度较低的人可读性分数会更低。

可读性不考虑电子邮件的语气,而情感分析就是用于此的。情感分析是确定消息的情感基调,无论是积极、消极还是中性。我们上次在这里时,讨论了不同的网站并对其进行了分析。我们发现IMDB和Eharmony(试图推销爱情)在他们的信息中积极得多,得分更接近1。然而,另一方面,“停止枪支暴力联盟”试图使用恐惧策略,让你对枪支感到害怕,因此他们的情感得分更接近0。

观察共和党和民主党,我们发现平均情感实际上非常相似,共和党约为0.57,民主党约为0.59。所以非常中性,略带积极。

我们发现的唯一区别是,在拜登与特朗普辩论之后,民主党人有点精神分裂,这真的取决于当天他们是积极还是消极。


表情符号使用与邮件作者

所有这些都是关于词语的,但我们发现相当多的电子邮件中包含表情符号。你现在看到的是,候选人的平均年龄在这里是74岁。RFK是他所有电子邮件中表情符号使用最多的用户。他在所有电子邮件中发送了超过1200个表情符号。

如果你看向右边,你可以看到该候选人最常用的表情符号是什么。所以RFK使用了一个灯泡。乔·拜登使用了祈祷的手,而She Pingre使用了龙虾。我知道她来自缅因州,但在政治电子邮件中使用龙虾,至少可以说很有趣。

这就引出了一个问题:到底是谁在写这些电子邮件?是候选人自己,还是他们让ChatGPT、竞选经理或实习生来写?因为我24岁,我这辈子用过的表情符号还没超过1000个。


追踪像素与信息共享

自然地,我们追踪他们发送给我们的信息,期望他们也这样做才公平。深入研究每一封电子邮件,我们查看了其中有多少包含追踪像素。我们发现追踪像素是常态,但引起好奇的是,为什么有些情况下99%的邮件都有,那1%是怎么回事?

当我们深入研究实际的元数据时,电子邮件看起来像是从同一个服务器上的不同账户发送的。所以,你知道,这真的归结为发送邮箱的IT配置,这是我们通常发现的情况。

然后,我将带大家回到一个早期的问题。你知道,这个关于共享的想法。事实上,我知道我只进行了一次交易。如果我收到任何来自第三方的信息,我就确切地知道它必须经过我提供信息的那个候选人。

我们发现,在这种情况下,前三位共享者是乔·拜登、亚当·希夫和金·克莱克。就拜登而言,由于我们注册参加选举的时间,我们从未注册过卡拉的简报。然而,我们从她的竞选活动收到了超过一千封电子邮件,而且你今天实际上可以回去看看,乔·拜登的网站会自动重定向到她的网站。所以,你知道,这有点令人惊讶。我实际上印象深刻,但这种无缝过渡也有点可怕。

在第二种情况下,亚当·希夫,他与加利福尼亚州的其他三位民主党政治家、一个堕胎倡导团体,然后有点令人惊讶地,还与他在马里兰州的第二个家乡的另一位民主党人共享了信息。

然后是金·克莱克,我们很快发现她不是特朗普那边的人,因为我们开始收到来自肯尼迪竞选总统的电子邮件。我们还收到了来自马里兰州(她的家乡)一位当地立法者的几封邮件,但后来我们发现她暴露了她的整个电子邮件列表。我们开始收到回复所有人的电子邮件,包括一封来自巴尔的摩柔道馆的邮件。

所以,你知道,这是一种奇怪的行为,因为你可以深入挖掘,看看谁与谁共享了信息,以及可能存在“敌人的敌人就是朋友”的想法。我们确实发现了跨党派共享,只有五个案例。但我们看到了足够多的实例,表明幕后有一些事情发生,现在这个列表正在与他人共享。大约5%的账户实际上这样做了。

我铭记于心的是:85%共享信息的候选人都输掉了竞选。现在,我不想赘述,但如果你在讲座后对你最喜欢的政客感到好奇,这里是两页民主党人,一页半共和党人,还有几个第三党派。所以,我的意思是,这基本上是一种常态。你知道,5%,这足以说明,真的不能指望他们会保护你的信息。

当我们进一步深入研究跨党派共享时,有一个案例非常突出。你知道,我们看到几个案例,民主党人或共和党人或独立人士。你知道,其中一些,我可以说,也许RFK是红对绿。但是,你知道,我们是按他们注册的党派来划分的。

真正让我们印象深刻的是亚利桑那州的一个案例。马克·拉姆是亚利桑那州的一名警长,我们发现我们收到了一些非常奇怪的内容。显然,我们收到了不少看起来确实是他竞选团队工作人员发来的电子邮件。但我们收到的唯一一封来自外国域名的电子邮件是发给他的,内容是宣传日本色情内容。

再深入挖掘,还有六个其他地址。来自,你知道,随机地点,看起来没有政治关联的人给我们发送了额外内容。其中三个被注册为恶意软件。其中一个实际上声称是俄勒冈州的一名法官。

所以,你知道,我们的结论是:可能他的账户或系统被黑了。


其他发现与趣闻

另外几个有趣的轶事。我在讲座早些时候提到了主动OSINT的想法,即你稍微透露更多关于自己的信息、身份、名字或某种内容,存在被追溯回你的风险。我们被抓住了。在这个案例中,约翰·利西奥尼,在我们注册他的账户一天后,他将我们的IP地址追踪回布莱克斯堡,自己做了一点OSINT,找到了我,并给我发了一封电子邮件说:“嘿,这很奇怪,是你吗?”

所以,我的意思是,我必须说,嘿,约翰,黑帽奖,你赢了。我做了一点调查,我想他以前是一名S承包商。所以就像,好吧,这说得通

基于蜂窝物联网技术的武器化——利用智能设备建立立足点 📡

在本课程中,我们将学习如何利用物联网设备的蜂窝通信模块,通过物理硬件交互和AT命令控制,将其转变为攻击跳板,从而访问其信任的网络资源。


项目介绍

我和Carlotta大约在两年前开始这个项目。项目最初源于我们的观察。多年来,我们都从事物联网评估和渗透测试工作,注意到蜂窝技术在物联网中的应用日益增长,但我们严重缺乏有效的知识和测试方法。

我们的目标是深入研究,理解蜂窝物联网的含义,构建测试方法,并解答相关的安全问题。

我们的研究主要聚焦于两种技术:

  • NB-IoT:半双工,高延迟。
  • LTE-M:速度更快,低延迟,全双工,常用于传输语音、图像、视频等数据量更大的设备。

当我们深入研究时,考虑到蜂窝通信通常是加密的且受FCC监管,为了有效测试,我们将重点转向了芯片间通信,即设备主CPU与蜂窝模块之间的通信。这部分通信在大多数设备上通常不加密,使我们能够更深入地与设备交互。

随着研究的推进,我们开始关注这些物联网硬件的信任关系。这些设备能访问什么?它们能获得什么访问权限?它们可以访问云服务、互联网,甚至通过私有APN访问私有网络。

我们接下来的目标,也是今天要讨论的,就是瞄准这种信任关系。我们将通过控制芯片间通信,从而完全控制蜂窝模块来实现这一目标。


硬件通信基础

上一节我们介绍了项目的宏观背景,本节中我们来看看如何与蜂窝模块进行硬件层面的通信。

在硬件层面,主CPU与蜂窝模块之间主要有两种通信路径:

  1. USB:通常指实现USB基本功能的USB 2.0高速接口。
  2. UART:通用异步收发传输器。蜂窝模块上通常有两个UART接口,一个是用于登录或查看启动日志的调试接口,另一个主UART则连接到主CPU。

当CPU与蜂窝模块通信时,它们使用AT命令。AT是“Attention”的缩写,最初于1981年为智能调制解调器设计,至今仍用于蜂窝模块。这是因为它们是一种简洁的文本字符串命令接口。

AT命令用于配置设备连接到蜂窝网络、进行管理更改、诊断以及更新设备固件。请注意右侧的AT命令手册截图,我们稍后会提到它。

AT命令大致可分为四类:测试、读取、写入和执行。有些命令可能同时具备测试、读取和写入功能,或者仅用于特定配置。执行类命令则用于让蜂窝模块执行特定操作。

虽然AT命令有四种类型,但3GPP(制定电信标准的组织)只要求制造商在设备上实现某些基本的AT命令,主要用于连接蜂窝网络和拨打电话。然而,物联网设备使用多种协议,因此制造商开发了各自特定的命令来实现更高级的功能,例如执行HTTP命令、打开套接字等。

右侧列出了部分制造商及其自定义命令前缀,例如Quectel使用AT+Q,ublox使用AT+U。这只是其中一部分,还有更多制造商有自己的自定义命令。

正如之前提到的AT命令手册,你可以在其中找到特定蜂窝模块的几乎所有信息。制造商通常会为特定模块型号发布AT命令手册,其中包含参数、命令说明,甚至命令运行后的响应示例。


物理交互与硬件破解

现在我们知道了与设备通信的协议(AT命令),接下来让我们看看如何在实际设备上进行物理交互。

为了能与设备上的蜂窝模块交互,我们需要能够接入设备。我经常使用的一种方法是透视图分析。具体做法是拍摄电路板正反两面的图像,然后将它们叠加在一起。这样可以同时看到电路板的两面,有助于识别芯片、表面走线、过孔等。

接着,我们获取实际的数据手册,并将芯片的焊球阵列图覆盖到实际设备图像上。这样就能更容易地识别出UART、USB等接口的位置,从而知道在电路板的哪个位置尝试接入通信。

但事情并非总是如此简单。我们经常会遇到无法直接访问的情况。这时该怎么办?看看幻灯片,你可能会想:“用针灸针?”答案是:没错。

以下是一个例子:如果能把模块侧立起来,看到焊球阵列的边缘,就可以使用针灸针插入芯片或蜂窝模块主体下方,从而访问USB和串行通信。

如果这种方法行不通,情况会变得更复杂。我们可以将设备拆开,使用热风枪进行IR回流焊,将模块从电路板上取下,然后绘制我们自己的电路。这是一个概念验证的测试样本,难度如何?实际上相当简单。使用焊盘修复套件,我能够在模块下方布线,并使用UV固化掩膜覆盖以防止短路。然后重新焊接芯片或模块,这样我们就能够接入那些关键的通信电路,从而使用AT命令与模块通信并控制它。

下一步是,如果这些方法都不奏效呢?这时就需要深入电路板内部。我成功过几次。关键在于确定你认为走线所在的位置,切割电路板,找到实际的电路走线,并在电路板的子层上接入它们。这要复杂得多,但如果你耐心细致,是能够成功接入这些关键通信电路的。


通过UART进行武器化

现在我们已经知道如何与调制解调器对话,也了解了如何进行硬件破解,接下来我们将结合这两者,看看如何通过UART进行武器化。

这张图展示了一个连接UART并能够向蜂窝模块发送命令的简单设置。我们实际上切断了主CPU和蜂窝模块之间在UART上的连接,并用我们的FTDI设备取而代之。在中间截图中,我们在TX和RX线上找到了两个位置并焊接了导线,然后切断了它们之间的走线。

接着,你可以将导线连接到一个分线板上。注意分线板中间有开关,这允许我们控制主CPU和蜂窝模块之间的全部通信。当开关打开时,设备可以继续按预期运行;当我们关闭开关时,就可以接管控制并开始发送AT命令。

我之前提到制造商为HTTP和打开套接字提供了大量命令。因此,我们实际上创建了一系列脚本,利用AT命令来重现我们在渗透测试中通常使用的工具,包括端口扫描器、HTTP代理等。接下来我将演示一个使用AT命令实现的S3存储桶扫描器。

现在我在一个串行终端中,等待模块启动并响应。它显示“Ready”,我发送了一个AT命令,它回复了OK

这个脚本可以接受存储桶名称(单个名称或文件列表)、要查找的文件扩展名、目标S3端点以及你笔记本电脑上连接的串口。我还加入了--assume-on选项,这样如果设备已经启动,它就不会一直等待。

通过使用AT命令创建这些工具,我们可以复制功能,并攻击设备所连接网络内的内部资源或互联网上的主机。如你所见,它正在遍历目标S3存储桶(这是一个专门为此演示设置的存储桶)。所有信息都被保存到一个文件中。最后,我们在那个S3存储桶中找到了flag.txt文件,结果被保存到一个JSON文件中,之后可以用jq进行解析。

虽然用AT命令重现工具很棒,但由于AT命令的简单性,也存在一些限制。更复杂的身份验证和负载交换有时会变得困难。因此,我们转向了通过UART的PPP

这允许我们通过蜂窝模块建立网络访问。蜂窝模块作为PPP服务器,我们运行PPP守护进程作为客户端。你会被分配一个IP地址,实际上是通过蜂窝模块上网。ATD*99#就是我在演讲前面提到的那个执行命令。

为了让设置更容易(因为在实际系统上设置PPP有时会很麻烦,且有很多不同的参数),我创建了一个简单的Python脚本,并在这里进行演示。

在演示中,我展示了当前没有ppp0接口,我连接着家里的无线网络并有一个IP地址。我还对Google运行了ping命令,稍后你会明白为什么——ping命令的往返时间大约是43到46秒。

这是cell_ppp.py脚本,它接受你连接的FTDI接口、波特率以及为蜂窝模块配置的APN。现在它正在确保模块就绪,ATE0命令是为了确保所有命令都打印出来以便查看。它正在建立ppp0接口连接。我们被分配了一个IP地址,甚至还有DNS。脚本随后会将其更改为我们的默认路由。我禁用了Wi-Fi,所以不再有家庭网络连接,但我有一条通过ppp0的路由。

让我们再次运行那个ping命令。一开始出现了大约67%的数据包丢失。不幸的是,情况确实如此,但随着持续运行,情况会有所改善。现在我通过PPP over UART运行一个不那么安全的AWS枚举脚本(来自某个枚举仓库)。这个演示被加速了,因为我实际运行这个工具的时间大约是40到45分钟,而在我的家庭网络上运行可能只需要3分钟。但它确实有效。如果你有足够的耐心,愿意在它运行时去喝杯咖啡,你实际上可以通过PPP over UART对云主机进行枚举或运行任何其他工具。

那么,使用UART和AT命令的优缺点是什么?

  • 优点:所需努力程度较低;PPP over UART在某些情况下可用。
  • 缺点:速度慢,数据吞吐量有限;有些蜂窝运营商已停止对PPP的支持。

还有一种替代方案是使用USB。接下来我将把演讲交回给Darll,让他谈谈如何通过USB进行武器化。


通过USB进行武器化

正如演示中提到的,有两种通信通道:串行和USB。通常在这些设备上,即使模块都支持,大多数产品也不会同时实现两者,产品要么使用一种,要么使用另一种进行控制和通信。在我们研究的案例中,设备是一个摄像头系统,它使用的是USB。

当我开始思考如何以任何真正可用的方式与之交互时,我会遇到什么样的技术问题?我们甚至从哪里开始?我上网查阅了大量资料,试图理解这意味着什么。我们需要处理一些问题。

在USB通信中,电路中可能存在终端或阻抗匹配电阻。因此,如果你要开始修改USB电路,需要考虑这些因素。你还需要处理差分线对(D+和D-)之间的走线长度偏差,不能一条线比另一条长太多。对于USB 2.0协议,其容错性很强,所以你可以轻松做到这一点而不会有大问题。但如果是USB 3.0设备,要保持在偏差距离内就复杂得多。

我们还有走线分支的问题。如果要修改电路,必须考虑不要在板上留下任何不从一点到另一点的走线,这会导致信号反射。因此,你必须处理信号衰减、阻抗匹配、串扰噪声和信号反射等问题。

我开始研究如何实现交互。我找到了一个德州仪器的设备,它是一个多路复用器,具体是1对2的(在我们的案例中是2对1)。这个芯片有很好的手册,我可以开发自己的板子。进一步研究后,我发现中国有一款预组装的板子。这块板子大约有一角硬币大小(在电子世界里这实际上非常巨大),试图将其接入设备可能会带来问题,但它确实解决了我的一些电气或电子要求。

然后我开始思考如何有效地将其接入实际电路。从电气原理上看,我们有蜂窝模块、设备的主CPU,我们想把多路复用器放进去。我们想要实现的是切换主机的能力——从CPU切换到我们的笔记本电脑。作为这种针对性攻击的一部分,目标是利用硬件的信任关系。这个硬件在启动时,会经历完整的身份验证过程,通过其APN,可能通过VPN功能进行外部验证,也可能验证各种云服务或功能。我们希望能够利用这一点。所以目标是:我们保持连接CPU,让蜂窝模块和CPU为我们完成所有身份验证和协商。一旦我们认为这些已完成,我们就希望通过多路复用器将设备切换到笔记本电脑,控制电路并实际用它来路由我们的数据。

这是实际的电路板。我们需要小心设备上的悬空走线。你看到那里的USB走线,我们切断了这些线路,将它们完全从电路中移除。然后我们在这里焊接导线,需要保持连接到我们设备的导线长度合适,以避免因长度偏差导致电路错误。

完成后,我们将设备接入。我们有一个开关S,用于在线路1和线路2之间切换。OE接地以确保设备上电。当OE接地时,多路复用器设备将上线并工作。目标是将整个东西接入,我们在设备上安装了一个高的夹层接头,使其更远离主板,因为所有东西都需要放在蜂窝设备和实际设备的主电路板之间。

从这里,我们将导线连接到多路复用器,接通电源,并连接下方的导线。在这个过程中,我的初步目标是先别管USB的线路2,先让这个多路复用器在电路中工作起来。所以我这样连接,给设备上电,让CPU保持连接,通过多路复用器路由所有流量。设备启动运行,验证其服务,开始发送图像和图片,此时功能完全正常。

下一个目标是尝试接入这个多路复用器,看看能否利用它。我做的第一件事是使用一个预制的USB插头单元。我将其接入电路,将D+连接到D+,D-连接到D-,然后启动,但什么也没发生。只有噪音。于是我接上一个USB在线嗅探器检查,发现它不断尝试协商到更低的速度,但全是错误。经过研究,这种错误的常见原因是D-和D+接反了。我不确定这些线是否标记正确,所以我放弃了,把它扔进了垃圾桶。我直接焊接了一个插头到设备上,我知道插头上的接线标准和颜色编码。我将其接入实际电路。我们能够插上它,我通过USB线连接到我的笔记本电脑。当你用这种线连接时,长度有限。通常USB标准允许很长的线缆,但如果你直接将长线缆连接到蜂窝设备模块上,如果不保持短线,电路负载会很快增加。所以我们在中间接入了USB在线嗅探器。

现在让我们进行演示,看看我们能用它做什么。当我们启动时,那是我的串行控制台,我可以看到它是否就绪。那是我的多路复用器和USB捕获设备。你可以看到,当我切换到我的笔记本电脑时,通信发生了。此时,我没有连接到任何网络服务,所以我们得到“网络不可达”。我还在我的Mac上运行了一个特定命令,可以看到没有任何迹象表明存在蜂窝设备。

现在让我们开始操作。我们给设备上电,它进入就绪模式。我发送一个AT命令给它,确认正常。让我们拨动开关看看会发生什么。我们拨动开关切换到线路2,瞬间我们得到了数据,它给了我们一个网络接口卡。现在,我们正在通过这个物联网设备的USB,利用电路中的多路复用器,路由整个Mac笔记本电脑。

我们可以ping通。如果我们跳过去查看设备上的USB,可以看到我们有ecm0。让我们再深入一点。我们将通过物联网设备的蜂窝功能,对一个设备发起SSH Metasploit暴力攻击。我们将进行四次尝试,最后一次是正确的密码。它为我们建立了一个Metasploit会话。我们看到会话已启用,让我们使用那个会话。现在我们连接到了设备。至此,我们整个笔记本电脑都通过这个物联网摄像头进行路由,通过利用电路中的多路复用器实现了这一点。

这个设备有能力连接出去。现在关键要考虑的是,在这个特定的测试设备上,我们是在互联网上,所以我们可以访问互联网。但如果我们处理的是一个使用公共APN或私有APN的物联网设备,并且它连接到某个内部网络的内部服务,我们将能够利用这个设备路由所有流量。

这个LTE-M设备上的USB功能恰好是ECM(以太网控制模型)。它基本上就是一个以太网端口。当你插入时,任何操作系统都会检测到它,就像你买了一个蜂窝调制解调器插到设备上一样,它会将其检测为一个实际的网络接口卡。

因此,硬件破解的复杂性在于,你必须拆开设备,切割线路,焊接元件,进行修改。有一些限制:并非所有设备都有ECM功能,一些NB-IoT设备可能不支持ECM,即使支持,也可能需要处理某些设备的高延迟问题。但无论如何,你可以看到这比通过串行端的点对点协议要快得多。

说到这里,我们需要讨论一些安全缓解策略。我将把演讲交给Carlotta,她会阐述我们的一些想法。我也想问一下,如果你们有自己的想法,请在会后与我们分享,我们对于如何修复或至少缓解这个问题持开放态度。


安全缓解策略

那么,设备制造商可以做些什么来缓解这方面的风险呢?是的,攻击者确实需要物理访问设备,但也存在供应链攻击等可能性。

我们认为,防拆保护,特别是外壳触发机制,会比环氧树脂灌封更有效。部分原因是,如果你有足够的耐心和决心,环氧树脂灌封是可以被去除的。外壳触发机制(无论是电子还是物理的)会在设备被打开时使设备失效。

禁用USB或UART。正如Darll提到的,设备通常只使用一种通信线路(无论是物理上还是通过软件)。终止另一种线路,防止其被用于通信,是另一种可能的缓解措施。

加密芯片间通信,使我们无法轻易看到通信内容。

在蜂窝运营商方面,可以进行APN监控、蜂窝带宽使用情况和行为监控。你的蜂窝摄像头或其他物联网设备不应该扫描互联网或内部网络。

对于实际的设备提供商网络,进行内部网络安全监控网络分段以及产品安全,因为即使你实现了这些措施,有时它们可能不如预期那样工作,或者有人可能找到绕过的方法。


总结与思考

最后我想做几点评论,其中一点不在幻灯片上。在我们今天的演示中,我们使用的是Quectel的EG91模块。这绝不是针对任何特定供应商或产品,这在我们研究过的几乎所有NB-IoT或LTE-M模块上都适用。

我想说的最后一点是,我们一直在讨论利用这个设备,将其武器化,用它来获得对其信任资源的立足点,无论是云服务、互联网服务,还是通过私有APN、内部网络、VPN连接进行攻击。那么,如果这些设备在供应链中被植入呢?记住有两种通道:USB和UART。设备通常只使用其中一种,我从未见过两者都使用的设备。这些设备很容易被植入小型计算机系统,从而为恶意活动打开大门,能够回连、接收命令和控制功能、进行监视、远程触发等。这是一个需要认真思考的问题。我们讨论和研究的是一个方向。但也有人向我提到,反过来也是我们需要关注的。

总结几点:

  1. 蜂窝模块的AT命令结构易于构建工具,AT命令手册广泛可用,有很多数据,很容易构建并接管这些设备。
  2. 存在信任关系问题需要关注。这些设备有权访问某些资源,这种访问是基于信任的,可能被用来攻击这种信任。
  3. 当攻击方式就是设备正常的工作方式时,你如何缓解威胁?我们实际上是在利用这些设备的正常功能。你如何保护自己免受正常功能被用于攻击?这通常需要你考虑良好的安全实践

这些设备的访问权限应该受到限制。这意味着,如果它们要连接出去,设备之间不应该共享资源。假设外面有一万台摄像头,如果每台都有自己的数据,但由于某种原因(因为是机器对机器通信),你失去了信任因素,那么一台设备可能潜在地获取其他设备的信息。或者,如果是一个私有APN,它应该只能访问它应该访问的内容——单台设备、单个端口来来回回传输数据,而不能在你的网络内部进行Nmap扫描或扫描,并进行暴力攻击。网络分段是解决之道。同样,实施分段以防止这类事情发生。

再者,监控。你可以在哪里部署监控以检测行为变化?对于你知道其流量模式的设备,你知道它应该做什么,应该与什么通信,通常也知道应该来回传输什么

利用 Apple AI 栈进行攻击操作 🍎⚔️

在本节课中,我们将学习如何利用 Apple 的原生 AI 框架(如 Core ML、Vision 和 AV Foundation)进行攻击操作。我们将探讨如何将恶意载荷嵌入到模型文件、图像和音频中,并利用这些框架的合法功能来加载和执行载荷,从而绕过安全检测。


Apple AI 栈概述

上一节我们介绍了课程主题,本节中我们来看看 Apple AI 栈的构成。Apple AI 栈包含多个组件,其中核心是 Core ML 引擎。它是一个轻量级框架,预装在 iPhone 和 Mac 上,用于日常任务,例如 iPhone 照片处理。此外,还有较新的 Apple Foundation 模型,用于大规模任务,但它是 Apple 私有的。因此,我们的重点将放在仍广泛可用且可被武器化的 Core ML 引擎上。在此之上,还有 Vision、AV Foundation 等原生框架,我们也将探讨如何利用它们。


什么是 ML 模型文件?

上一节我们介绍了 AI 栈,本节中我们来看看攻击的核心载体:ML 模型文件。Core ML 模型文件(.mlmodel 或编译后的 .mlmodelc)是轻量级文件,随应用程序分发,用于在设备上快速执行 AI 任务。这些文件通常未经过签名验证,因此 Gatekeeper 或公证服务不会检查其安全性。文件内部包含模型描述、类型、参数(权重)和元数据。攻击者可以将载荷隐藏在模型权重或元数据中。


各框架如何工作?

以下是 Apple 各 AI 相关框架的基本工作原理:

  1. Core ML 模型工作流:开发者训练模型,生成 .mlmodel 文件,编译后随应用分发。应用运行时,模型文件被加载到内存中执行。
  2. Vision 框架:用于图像处理和文本识别等视觉任务。它提供原生 API 来处理图像数据。
  3. AV Foundation 框架:用于音频和视频处理,被许多应用程序(如 Zoom、iMovie)使用。

滥用各层进行攻击

上一节我们了解了框架的工作原理,本节中我们来看看如何滥用每一层来隐藏和传输恶意载荷。

以下是各层的攻击方法:

  • 模型文件层:可以将载荷放置在模型描述、元数据或模型权重中。例如,将载荷放入权重层会显示为浮点数数据,难以直接识别。由于读取模型文件需要 Core ML 库,传统的 EDR 或杀毒引擎通常无法检测其中隐藏的内容。
  • Vision 框架层:可以将数据编码到图像的像素中。例如,设置像素的透明度为 15%,人眼仍能看到图像,但恶意载荷已嵌入像素数据中。攻击者可以在运行时使用 Vision API 读取像素并提取载荷。
  • AV Foundation 框架层:可以将载荷编码到音频文件的振幅中。例如,将载荷转换为二进制(0 和 1),用不同的振幅值代表 0 和 1。播放时,音频听起来像是正常的蜂鸣声,但使用 AV Foundation API 可以读取音频文件、提取振幅数据并解码出原始载荷。

演示:Vision 与 AV Foundation

以下是利用 Vision 和 AV Foundation 框架隐藏数据的简单演示:

  1. Vision 演示:一个 Python 脚本生成包含加密密钥的图片。另一个脚本使用 Vision 库读取该图片,并从像素中提取出密钥。

  2. AV Foundation 演示:一段 Swift 代码将字符串 “hello world” 转换为二进制,并根据比特位(0 或 1)设置音频振幅,生成一个音频文件。另一段代码使用 AV Foundation 读取该音频文件,提取振幅数据,解码后还原出 “hello world”。


MLR C2 框架

上一节我们看到了如何隐藏数据,本节中我们来看看如何利用这些技术构建一个完整的命令与控制(C2)框架。我构建了一个名为 MLR 的轻量级 C2 框架,它完全基于 Core ML,使用 FastAPI 进行通信,并使用模型文件作为载荷传输机制。

其工作流程如下:

  1. 注册:在受害者机器上运行 Dropper(Python 编写),它会向 MLR C2 服务器注册并创建一个会话。
  2. 命令下发:C2 操作员发送命令(如 whoami)。C2 将命令进行十六进制或 Base64 编码,放入一个模型文件的元数据中,在内存中创建该模型文件,并将其二进制数据发送给 Agent。
  3. 命令执行:Agent 接收二进制数据,在内存中重建模型文件,使用 Core ML 库提取并解码元数据中的命令,然后执行它。
  4. 结果回传:Agent 将命令执行结果以同样方式编码到新的模型文件元数据中,将其二进制数据发送回 C2。C2 使用 Core ML 解码并显示结果。

该框架完全依赖原生库,在测试中能够绕过最新的终端检测与响应(EDR)和杀毒(AV)引擎。


集成现有载荷:Mythic Apple

如果你不想使用新的 MLR C2,也可以将此技术应用于现有载荷,例如著名的 Mythic C2 的 Apple 载荷。

以下是集成步骤:

  1. 生成密钥并隐藏:使用 Vision 技术,生成一个加密密钥并将其隐藏在图片(如应用图标)的像素中。

  2. 加密载荷:使用该密钥对 Mythic Apple 的 JavaScript 载荷进行加密,得到一个加密的文本文件。

  3. 嵌入模型:使用 Python 脚本和 Core ML 库,将加密后的载荷嵌入到一个 Core ML 模型文件的权重中,生成 .mlmodel 文件。
  4. 加载执行:Loader 程序运行时,会执行以下操作:
    • 使用 Vision 库从图片中读取密钥。
    • 使用 Core ML 库在内存中加载模型文件,并提取出加密的载荷。
    • 使用密钥解密载荷并执行。

      执行后,Mythic C2 将收到上线通知。


防御盲点与缓解建议

上一节我们探讨了攻击方法,本节中我们从防御角度看看存在的盲点和应对策略。模型文件、图像文件和音频文件通常是静态文件,当前的 EDR 或 AV 引擎很少深入扫描这些文件格式的内容,因为它们看起来是合法的,且解析需要特定框架。

作为缓解措施,防御者应:

  • 监控模型文件加载:关注哪些应用程序加载了模型文件,以及这些文件的来源是否可疑。
  • 分析 API 调用:检查应用程序的 API 调用序列。如果一个文本编辑器调用了 Vision 库来读取图片,或者一个计算器应用加载了 Core ML 模型,这些都是异常行为。
  • 警惕供应链攻击:开发者可能从不可信的公共仓库下载并集成模型文件。应审查第三方模型文件的来源。
  • 制定自定义规则:安全团队需要编写针对性的检测规则,来识别这类滥用原生框架的恶意行为。

总结

本节课中我们一起学习了如何武器化 Apple 的原生 AI 栈(Core ML、Vision、AV Foundation)进行攻击操作。我们探讨了将恶意载荷隐藏于模型文件、图像像素和音频振幅中的技术,并介绍了基于此的 MLR C2 框架以及如何将技术应用于现有的 Mythic Apple 载荷。最后,我们从防御视角分析了当前安全检测的盲点,并提出了相应的监控和缓解建议。

Black Hat USA 2025 参会指南 🎯

大家好,欢迎来到Black Hat。我是Black Hat活动的总经理Steve Wiy。

我代表我们的团队,感谢您注册参加Black Hat USA 2025。

我们非常期待您今年的加入,并体验我们扩展后的活动,其中包括新的内容、项目和功能,以及Black Hat所熟知的所有最新网络安全研究与见解。

我们有一整天的Black Hat峰会,包括CISO峰会、AI峰会、创新者峰会和投资者峰会。

今年新增了Black Hat金融服务峰会。

我们安排了近120场安全简报,涵盖最新的网络安全研究、发展和趋势。

我们提供了超过100场深度技术实践培训课程,供您磨练技能并推动职业发展。

我们扩展了Black Hat Spotlight竞赛,为新兴初创公司提供展示平台,风投和公司可以在此寻找下一个投资或收购目标。

我们为您创造了许多新的社交和专业发展机会,让您在Black Hat的时间价值最大化。

活动即将到来,我们邀请您在出发前查看活动指南。

指南包含了重要的活动信息、现场物流、数字平台信息、日程更新、特别项目等。

没有我们的社区,我们的活动将无法举办,因此我们感谢您的支持。

我们祝您前往拉斯维加斯的旅途平安,并期待很快与大家见面。


概述

在本课程中,我们将一起了解Black Hat USA 2025大会的核心内容、新增项目以及参会前的准备工作。

大会核心内容介绍

上一节我们概述了本次大会,本节中我们来看看大会包含哪些核心活动与内容。

以下是本次大会的主要组成部分:

  • 峰会活动:包含一整天的Black Hat峰会,具体有CISO峰会、AI峰会、创新者峰会和投资者峰会。
  • 新增峰会:今年特别新增了Black Hat金融服务峰会。
  • 技术简报:提供近120场安全简报,内容涵盖最新的网络安全研究、发展和趋势。
  • 实践培训:开设超过100场深度技术实践培训课程,旨在帮助参会者提升专业技能。

新增特色与机会

了解了核心议程后,本节我们将关注本次大会新增的特色环节和为您创造的机会。

以下是今年扩展和新增的项目:

  • 初创企业竞赛:扩展了Black Hat Spotlight竞赛,为有潜力的初创公司提供展示平台。
  • 社交与发展:创造了多种新的社交和专业发展机会,以优化您的参会体验。

参会前准备工作

在介绍了大会的丰富内容后,本节将说明您在活动开始前需要完成的关键步骤。

以下是您的会前准备清单:

  • 查阅指南:在出发前,请务必查看活动指南。
  • 指南内容:指南包含重要活动信息、现场物流、数字平台使用说明、日程更新及特别项目详情。

总结

在本节课中,我们一起学习了Black Hat USA 2025大会的总体情况、核心议程、新增特色活动以及重要的会前准备事项。我们期待在拉斯维加斯与您相见。

Windows Hello for Business 深度解析 🛡️

在本节课中,我们将深入探讨 Windows Hello for Business 的工作原理、架构及其安全模型。我们将从基本概念入手,逐步分析其身份识别与认证流程,并揭示其内部数据库结构及潜在的安全考量。

概述:告别密码的时代 🔑

2015年,微软在 Windows 操作系统中引入了 Windows Hello 功能,旨在减少对密码的依赖,转而使用生物识别技术。密码容易被遗忘、丢失,且输入不便。生物识别技术则不同,它是用户固有的特征(如面部、指纹),不易丢失,并能提供更流畅的用户体验。微软正致力于将 Windows Hello 推广到更多场景,例如 Windows Recall(基于AI的屏幕活动记录与检索)和 Passkey(使用生物识别技术登录网站)。

Windows Hello for Business 建立在两个核心原则之上:身份识别(确认设备前用户的身份)和身份认证(确认该身份有权访问特定资源)。

身份识别与认证流程 🔄

上一节我们介绍了 Windows Hello 的目标,本节中我们来看看其核心的身份识别与认证流程。

注册流程

用户首次设置 Windows Hello for Business 时,系统会执行注册流程。

  1. 采集生物特征:系统通过传感器(如摄像头)采集用户的生物特征样本。
  2. 生成密钥对:系统为用户创建一对非对称加密密钥,称为 用户ID密钥
    • 公钥:被发送并存储在身份提供商(如 Active Directory)处,与用户身份绑定。
    • 私钥:存储在用户设备上。如果设备配备可信平台模块,则私钥存储在 TPM 中;否则,由软件(如 Winlogon)在受保护的内存中管理。

登录与认证流程

当用户尝试登录或访问资源时,流程如下:

  1. 提供手势:用户向系统提供生物特征“手势”,如面部扫描、指纹或TPM PIN码。
  2. 身份识别:系统将采集的生物特征与注册时存储的生物特征模板进行比对。此过程通常涉及人工智能模型计算匹配度。
  3. 密钥释放:识别成功后,系统使用与“手势”关联的保护器密钥来解密身份验证密钥,最终释放出存储在TPM中的用户ID私钥
  4. 密码学质询:系统使用释放的私钥对来自身份提供商的密码学质询进行签名。
  5. 完成认证:身份提供商使用对应的公钥验证签名。验证通过后,即完成身份认证。

核心公式可以简化为:
用户手势 -> 保护器密钥 -> 身份验证密钥 -> 用户ID私钥 -> 密码学签名 -> 身份认证

系统架构与组件 🏗️

了解了整体流程后,我们深入到本地机器的系统架构层面。

Windows Hello 涉及多个软件组件协同工作。以下是其主要交互方式:

标准模式流程

  1. 硬件与驱动:生物识别设备(如摄像头)通过制造商驱动和微软定义的生物识别驱动,将数据传递给系统。
  2. Windows 生物识别服务:这是一个以 SYSTEM 权限运行在会话0的核心服务。它接收来自驱动的数据。
  3. 引擎与适配器:服务内部包含“引擎”组件,负责执行实际的生物特征匹配。它通过“适配器”与传感器和存储系统交互。
    • 传感器适配器:管理与特定类型传感器(如面部、指纹)的通信。
    • 存储适配器:管理与生物特征模板数据库的交互。
    • 引擎适配器:执行匹配算法。
  4. 客户端API:用户态应用程序(如登录界面)通过 WinBio API 与服务进行RPC通信,从而请求身份验证。生物特征数据始终被隔离在服务进程的内存空间中,以保护隐私。

增强安全模式

为了提供更高安全性,微软引入了增强安全模式

  1. 虚拟化安全:此模式利用基于虚拟化的安全技术,创建两个隔离的执行环境:普通世界的 VTL 0 和安全世界的 VTL 1
  2. 隔离服务:一个独立的 Windows 生物识别隔离服务VTL 1 中运行,处理最敏感的操作(如模板匹配和密钥访问)。
  3. 安全通信:普通世界的生物识别服务与隔离服务之间通过安全的密码学协议进行通信。
  4. 硬件要求:此模式需要设备硬件支持安全传感器和虚拟化技术。

代码/结构示意

标准模式:
[用户APP] --(WinBio API)--> [Windows生物识别服务] --(驱动)--> [硬件]

增强安全模式:
[用户APP] --(API)--> [普通世界服务 (VTL 0)] --(安全通道)--> [隔离服务 (VTL 1)] --(安全驱动)--> [安全硬件]

生物特征模板数据库 🔐

身份识别的核心在于将现场采集的特征与预先存储的模板进行比对。因此,模板数据库的安全至关重要。

数据库结构

根据逆向工程分析,模板数据库文件具有以下结构:

  1. 加密头部:这是数据库的安全核心。
    • 包含用于加密模板的数据库密钥和初始化向量。
    • 包含一个加密的 SHA-256 哈希值,用于验证整个数据库的完整性,防止篡改。
  2. 未加密头部:包含管理元数据,如数据库版本、记录数量等。
  3. 记录区:包含每个用户的模板记录。每条记录包括:
    • 记录头:包含用户身份信息(最重要的字段是用户的 SID)以及加密模板的大小和偏移量。
    • 加密的模板数据:用户的实际生物特征模板,使用数据库密钥加密。

安全模型与局限

数据库的安全依赖于加密头部。加密头部本身使用 Windows 的 CryptProtectData 等函数进行保护。这些函数通常依赖于用户上下文(如登录密码)来派生加密密钥。

然而,Windows 生物识别服务以 SYSTEM 权限运行。这意味着,任何能够以 本地管理员 身份执行代码的攻击者,都可以在服务的上下文中调用 CryptUnprotectData 函数,从而解密数据库头部,获得数据库密钥。

潜在攻击场景

  • 模板窃取:攻击者可以解密并提取任何已注册用户的原始生物特征模板。
  • 身份冒用:攻击者可以将自己的生物特征模板注入到目标用户的记录中,从而通过生物识别认证冒充该用户。
  • 数据库篡改:攻击者可以修改数据库内容(如交换不同用户的SID),并更新加密的哈希值以通过完整性检查。

演示与总结 🎯

在演讲的现场演示中,攻击者(以本地管理员权限)使用自定义工具解密了数据库,将其本人的面部识别模板替换了受害者用户的模板。随后,攻击者成功通过面部识别,以受害者用户的身份登录了系统,并访问了域环境中的资源。

核心要点总结

本节课中我们一起学习了以下关键内容:

  1. 重要性提升:Windows Hello for Business 正成为微软安全生态的核心组件(如 Windows Recall),其重要性日益增加。
  2. 架构复杂:其系统涉及多层组件,包括服务、驱动、适配器,并支持增强安全模式以提供硬件级隔离。
  3. 数据库安全是薄弱环节:在非增强安全模式下,生物特征模板数据库的加密密钥可被本地管理员访问,这是一个根本性的安全局限。
  4. 威胁升级:此漏洞可能导致 本地管理员权限提升至域用户权限,在企业环境中构成严重威胁。

安全建议

基于以上分析,我们提出以下建议:

  • 优先使用增强安全模式:如果设备硬件支持,务必启用 ESS 模式,它能将关键操作隔离在安全环境中。
  • 考虑使用 PIN 码:在不支持 ESS 的设备上,可以优先使用 TPM PIN 码。PIN 码可作为熵源,并受益于 TPM 的抗暴力破解保护。
  • 遵循“一人一机”原则:如同不共享牙刷一样,避免多个用户在同一台客户端设备上注册生物特征。
  • 加强监控:监控对生物特征数据库文件的异常访问,因为正常情况下只有生物识别服务会访问它。

Windows Hello for Business 代表了向无密码未来的迈进,但其实现的安全性高度依赖于具体的配置和硬件能力。理解其内部机制有助于我们更安全地部署和使用这项技术。

逆向工程 macOS XProtect Remediator 🛡️

在本节课中,我们将深入探讨 macOS 安全组件 XProtect Remediator 的内部工作原理。我们将学习其检测逻辑、针对的恶意软件家族,并分析其使用的技术和潜在问题。本课程旨在为安全研究人员(无论是蓝队还是红队)提供关于 XPR 的深入技术理解。

概述

XProtect Remediator 是 macOS 恶意软件防御的第三层。它在前两层防御(如 Gatekeeper 和传统 XProtect)失效后启动,旨在检测并清除已在系统上活跃运行的恶意软件。本节课将解析其架构、扫描模块以及用于描述检测逻辑的领域特定语言。

XProtect Remediator 简介

根据苹果的平台安全文档,XProtect Remediator 是 macOS 恶意软件防御的第三层。第一层和第二层包括苹果的应用审核、公证和传统的 XProtect。这两层旨在防止恶意软件被执行或分发。但 XPR 在恶意软件已执行后介入。它的工作是检测或清除在系统上活跃运行的恶意软件。

XPR 在 macOS Monterey 中引入,取代了 MRT。此后,MRT 停止接收更新。XPR 通常每月应用一到两次更新。截至目前,XPR 包含超过 20 个扫描模块,据信每个模块针对特定的恶意软件家族。

例如,名为 XProtectRemediator.AR 的二进制文件是一个扫描器,用于清除知名的广告软件。还有其他扫描器,如 XProtectRemediator.BlueCargoBluetopBunco 等。

为什么需要修复机制?

某些样本可以绕过第一层和第二层防御。例如,在两年前报告的 3CX 供应链攻击中,那个被木马化的 3CX 应用通过了苹果的公证,意味着它通过了 Gatekeeper 检查并成功启动。

此外,一些恶意软件使用社会工程学手段诱使用户禁用 Gatekeeper。在这两种情况下,恶意软件都能绕过前两层防御。因此,苹果需要一种方法来检测或清除在系统上活跃运行的恶意软件。

研究动机

首先,从攻击性安全的角度看,XPR 是一个有吸引力的目标,因为它拥有强大的权限。例如,其中的漏洞可能导致 TCC 绕过。事实上,Gary Kman 曾在 Twitter 上发布过一个漏洞利用,演示了如何通过其中一个 XProtect 扫描器从低权限获取完全磁盘访问权限。

此外,XProtect 扫描器同时以 root 和用户权限运行,这意味着 XProtect 中的漏洞可能潜在地导致用户到 root 的权限提升。

从防御性安全的角度看,XPR 也是一个有趣的反向工程目标。由于苹果倾向于使用自己的命名方案来指代恶意软件,XPR 针对的几个恶意软件家族仍然未知。像 Howard Oakley 和 Phil Stokes 这样的研究已经识别出其中一些,但由于缺乏深入的反向工程,仍有几个家族未知。

此外,XPR 的检测逻辑也不够清晰。它似乎只是简单地扫描文件并使用 YARA 规则进行匹配。但仅此而已吗?这仍然是一个悬而未决的问题。

主要研究目标

主要的研究目标是位于 /System/Library/CoreServices/XProtect.app 的这个应用程序包。

在这个包的 Contents/MacOS 目录中,有 23 个不同的扫描模块。它们的大小都在 2 MB 左右。还有一个名为 XProtect 的二进制文件(不要与传统的 XProtect 混淆)。还有一个 XPC 服务,名为 XProtectRemediatorService

一个需要注意的点是,这些 XPR 衍生二进制文件是用 Swift 编写的。与其他用 Swift 编写的二进制文件一样,它们包含特定于 Swift 二进制文件的独特区段名称,如 __swift5_entry__swift5_typeref 等。

相关工作

Howard Oakley 发表了许多关于 XPR 的博客文章。Alden Shimizu 发现 XPR 包含用于 YARA 规则和文件路径的加密字符串。Facebook 也编制了 XPR 相关恶意软件名称的列表。

但据我所知,我还没有看到任何关于 XPR 的详细或深入的反向工程结果。

逆向工程方法

接下来,我们来看看我是如何进行逆向工程的。

我使用 Binary Ninja 对超过 20 个扫描器二进制文件进行了逆向工程。当然,这些二进制文件是去符号化的。但令人惊讶的是,一些符号仍然可以恢复。

这是因为我使用 bindiff 进行了二进制差异分析,并发现 XProtect 扫描器的函数与 XProtect 有效载荷摘要有重叠。这意味着我们可以将该摘要导出的符号导入到 XProtect 扫描器中。

尽管如此,逆向工程 Swift 二进制文件仍然具有挑战性,因为它们是去符号化的 Swift 二进制文件。Swift 二进制文件通常包含类型相关的符号,例如类型方法访问器和协议见证表。这些符号对逆向工程非常有帮助,因为它们告诉我们正在实例化哪些类型的对象。但在这种情况下,这些符号也被去除了,因此几乎没有结构信息可供使用。

但幸运的是,即使二进制文件被去符号化,我们仍然可以访问其中的大量类型信息。这是因为 Swift 支持反射。用于反射的元数据可以通过 Swift 特定的区段(如 __swift5_protos__swift5_types)访问。通过提取这些元数据,我们可以恢复类型信息。我们可以使用 blacktop 创建的 ipsw 工具中的 swift demangle 命令来提取这些类型信息。但提取的类型信息不能直接导入到反汇编器中。

因此,我开发了一个名为 binja-swift-demangler 的新 Binary Ninja 插件程序,并已发布在 GitHub 上。这个程序基于 ipsw 的 Swift 功能,它将类型元数据访问器、协议见证表符号和交叉引用方法注释到反汇编列表中。它还支持其他有助于 Swift 逆向工程的功能,如 Swift 字符串分析。

以下是一个快速示例:在没有这个插件的情况下,很难判断这个函数在做什么,引用了哪些类型的数据。但在运行插件后,该函数被重命名为适当的类型元数据访问器,为我们提供了更多的洞察力。

这是另一个例子:在运行插件之前,没有可用的类型相关信息,因此很难判断正在实例化哪些类型的对象。但在运行插件后,大量的类型元数据被注释出来,为我们提供了更多的上下文信息。

我还开发了动态分析工具来辅助逆向工程。Swift 二进制文件包含许多间接分支,例如通过虚函数表和协议见证表进行的调用。使用 LLDB 手动解析这些分支目标可能很繁琐。我的 LLDB 脚本捕获这些分支目标并将其导出为 JSON 文件。导出的数据可以通过 Binary Ninja 的同步插件导入。

以下是一个示例:捕获的间接分支目标索引可以像这样导入到 Binary Ninja 中。这个程序还会在可能的情况下注释协议见证表和函数符号。例如,如果一个函数是通过协议见证表调用的,这个程序会注释出与该调用关联的具体类型和协议。因此,它为逆向工程提供了大量有用的信息。

我还创建了一些自定义的 LLDB 命令。标准的 LLDB 表达式命令不能正确处理复杂的 Swift 对象,如存在性容器。因此,我构建了一些增强命令,用于转储更多的 Swift 对象。使用这些静态和动态分析工具,我能够更深入地研究 XProtect 扫描器。

检测逻辑概述

接下来,让我们进入逆向工程结果。首先,我将概述检测是如何工作的。

检测过程概述如下:位于 /System/Library/CoreServices/XProtect.app/Contents/MacOS/XProtect 的二进制文件同时注册为启动代理和启动守护进程。它的执行由 Duet Activity Scheduler 调度,这是一个基于系统活动和可用资源运行的后台任务调度器。

当 XProtect 进程运行时,它会向 XProtectRemediatorService 发送一个 XPC 请求,然后该服务会依次启动所有 XProtect 扫描器。

每个扫描器都包含自己的检测逻辑,这些逻辑使用检测构建器和所谓的 XProtect 插件 API 来实现。在检测文件时,扫描器还会收集文件的来源属性。这使它们能够识别每个被检测文件最初来自何处。最后,检测到的文件信息被报告回苹果。

扫描器初始化过程

每个 XProtect 扫描器都有一个名为 __swift5_typeref 的函数,该函数在其入口点之前运行。它的任务是解密敏感字符串,例如文件路径、YARA 规则和正则表达式。这些敏感字符串使用简单的异或密码进行加密。

解密这些字符串很重要,因为它能揭示每个 XProtect 扫描器的大量工作方式。Alden Shimizu 最初解密了这些字符串,他还为此提供了一个很好的 Binary Ninja 脚本。但有些字符串未能成功解密。他承认输出并不完美。因此,我开发了一个自定义的 LLDB 脚本来解密所有这些字符串。

以下是一些解密结果:我们可以看到诸如哈希值、文件路径、文本消息和 YARA 规则之类的字符串。

__swift5_typeref 函数完成后,扫描器移动到其入口点。在这个阶段,扫描器创建其插件图的一个实例。例如,在 AR 扫描器的情况下,它创建 ARPlugin 的一个实例。大多数 XProtect 扫描器只定义一个插件图。

然后,扫描器创建 XPPluginHelpers 的一个实例,并将其作为参数传递给插件的 main 函数。

那么,XPPluginHelpers 是什么?它提供对各种系统信息的访问。它的功能很大程度上可以从其属性名称推断出来。例如,它提供对启动服务、网络设置、钥匙串和进程内存内容的访问。

让我们仔细看看 XPPluginHelpers 中一个有趣的属性,它被称为 alertDelegate 属性。这个属性包含使用 NSAlert 向用户显示对话框的方法。我对这个属性的存在感到惊讶,因为当前的 XPR 在检测文件时是静默进行的,不会通知用户。

在我的研究过程中,我还没有观察到 XPR 使用这个属性。但这个属性的存在表明,苹果可能在未来的更新中引入通知功能。

现在,执行最终会进入插件的 main 函数。这个函数创建 XPRemediator 类的一个实例,使用 OSSignpost 测量其性能数据,移除环境变量(这是针对漏洞利用的固定措施),验证 XProtectRemediatorService 的权限,并最终启用快速老化。

让我简要解释一下什么是快速老化,因为它似乎并不广为人知。这个功能在进程级别上抑制文件的访问时间更新。可以通过 sysctl 查看。XPR 似乎启用了这个功能,可能是为了提高性能或保存取证工件。在检测完成后,此功能被禁用。

检测逻辑实现

接下来,让我们看看 XPR 如何实现其检测逻辑。在这里,我将介绍一组称为检测构建器的领域特定语言,它有助于以简洁的方式描述检测逻辑。但在深入细节之前,我想先谈谈我对苹果为何决定引入自己的 DSL 的看法。为什么首先需要它?

检测逻辑有时可能很复杂。当它们变得复杂时,代码往往会变得非常冗长。例如,假设我们只想在满足以下所有条件时删除一个文件:目标文件位于 ~/Library/Application Support 目录中;其文件大小为 2 MB 或更小;其格式为 Mach-O 且未经过公证;它匹配特定的 YARA 规则;并且如果扫描器以 root 身份运行,还应扫描一个额外的目录。

为了实现这个逻辑,我们可能会编写类似这样的代码:首先,枚举 ~/Library/Application Support 目录下的文件。然后过滤出大小为 2 MB 或更小的文件。接着将它们缩小到仅包含 Mach-O 文件。然后检查哪些文件未经过公证,找到与 YARA 规则匹配的文件。如果我们还想在扫描器以 root 身份运行时扫描额外的目录,我们需要用额外的条件复制这个循环。

这种方法可行,但在可读性和可维护性方面并不理想。如果你想添加另一个条件,你必须插入另一个 if 语句,使代码更加臃肿。

那么,我们如何才能更简洁地描述这个逻辑,同时保持其可维护性呢?我们的答案是使用 Swift 结果构建器。

那么,Swift 结果构建器到底是什么?它们是在 Swift 5.4 中引入的,旨在使编写领域特定语言更容易。如果你曾经使用过 SwiftUI,那么你已经使用过它们了。它们被用来描述用户界面。但它们不仅仅用于 UI。更一般地说,它们可以用来创建 DSL,用于组合多个元素并构建单个结果,例如 JSON、HTML 等结构化数据。在 XPR 中,苹果使用结果构建器将多个条件组合成最终的检测决策。

让我们看一个使用 Swift 结果构建器生成 HTML 的简单示例。如果你尝试用普通的 Swift 动态生成 HTML,你最终会得到非常冗长的代码,需要为每个元素声明中间变量,手动嵌套它们等等。在这个例子中,我们只想在 useChapterTitles 变量设置为 true 时添加一个特定的 h1 元素。为了描述这一点,我们声明了一个 div 变量,根据 useChapterTitles 变量的值,它可能包含一个 header。它包含了很多不必要的数据。仅仅看代码,很难判断最终生成的 HTML 结构会是什么样子。

现在,这是同一个例子,但这次是使用结果构建器提供的 DSL 实现的。它可读性高得多。你不需要声明不必要的中间变量。此外,生成的 HTML 的结构清晰地反映在 Swift 代码中。这两个代码块直接对应于两个 div 元素,甚至条件和哪些元素被添加都易于理解。例如,我们可以很容易地理解,只有当 useChapterTitles 变量设置为 true 时,才会添加这个 HTML 元素。这几乎就像编写你自己的模板引擎,但你是在使用 Swift 语言特性的 DSL 内部完成的。

那么,如果我们将这个想法应用到检测逻辑中会怎样?回想一下之前的例子,通过使用结果构建器提供的 DSL,我们可以更清晰地表达这个逻辑。这是相同逻辑的样子。你可以清楚地看到正在检查的文件函数:目标文件必须在 ~/Library/Application Support 目录下;文件大小必须为 2 MB 或更小;文件格式必须是 Mach-O;必须未经过公证;并且必须匹配那个特定的 YARA 规则。当扫描器以 root 身份运行时,还会扫描额外的目录。它简洁、可读且易于维护,对吧?

这正是苹果所做的。XPR 附带了一组称为检测构建器的 DSL。它定义了几个构建器,每个构建器都提供了一个 DSL 来组合检测条件。例如,如果你想描述与文件相关的检测逻辑,可以使用 FileRemediationBuilder 提供的 DSL。其他 DSL 也可用,例如 ProcessRemediationBuilderServiceRemediationBuilderSoftwareUpdateExtensionRemediationBuilder

检测数据并非被所有 XProtect 扫描器使用。正如你在这里看到的,它被一部分扫描器使用,例如 ARBlueCargoCopper 等。其余的扫描器依赖于一个称为 XProtect 插件 API 的低级 API 来实现其功能。

我已经根据我的逆向工程记录了检测构建器 DSL 的规范,并将其发布在 GitHub 上。如果你对 DSL 如何工作以及有哪些类型的条件可用等细节感兴趣,请随时查看。

现在,让我展示几个实际例子来说明这个 DSL 是如何在实践中使用的。

首先,让我们看看 XPR.AR。这是一个使用 FileRemediationBuilder 的简单例子。正如你在幻灯片上看到的,只有当路径是 /tmp/acre 且文件大小为 68 字节或更大,并且匹配 acre YARA 规则时,才会删除文件。是的,很容易理解。

接下来,让我们看看使用 ProcessRemediationBuilderXPR.Alureon。它只在进程未经过公证且其后台文件满足两个条件时才修复正在运行的进程:首先,文件路径必须包含某些字符串,如 ~/Library/Application Support/tmp;其次,文件必须匹配 Alureon YARA 规则。有趣的是,后台文件的条件可以使用 FileRemediationBuilder 来描述。

为了验证我的逆向工程结果,我实现了一个开源版本的检测构建器。它是 XPR.AR 行为的最小化实现。这个项目可以帮助你理解 Swift 结果构建器是如何被用来实现检测构建器的。

各扫描器检测逻辑详解

好了,现在让我们更仔细地看看每个扫描器的检测逻辑。让我们从 XPR.LaunchAgent 开始,它与 XPR.RustBucket 同时引入。XPR.RustBucket 旨在清除使用 3CX 供应链攻击的有效载荷。至于 XPR.LaunchAgent,其解密后的字符串只是两个哈希值。但这些有什么用呢?

这里的检测逻辑是使用检测数据描述的。正如我们所见,这两个哈希值是 CD 哈希。它被设计用来查找具有这些特定 CD 哈希的进程。第一个 CD 哈希是 a0b...。这是使用 3CX 供应链攻击的第二个阶段有效载荷,通常被称为 UpgradeAgent。这个样本由 Patrick Wardle 在两年前的 Black Hat USA 上展示过。第二个 CD 哈希仍然未知,但它很可能是 UpgradeAgent 的一个变体。据我所知,只有 UpgradeAgent 的一个版本被公开记录,我在之前的演讲中解释过。那个版本功能有限,它只向 C2 服务器发送系统信息,不执行任何进一步的操作。因此,Patrick Wardle 提出可能存在其他功能更强大的变体。这个未知的 CD 哈希可能支持他的假设,即可能存在其他功能更强大的 UpgradeAgent 版本。

接下来是 XPR.BlueCargo。其解密后的字符串似乎与修复无关,比如 right clickclick open。那么这些有什么用呢?事实证明,它与我在本演讲开头提到的恶意软件有关。在开头,我简要提到了使用社会工程学手段禁用 Gatekeeper 的恶意软件。该磁盘映像的背景图像包含诸如 right clickclick open 之类的字符串。这正是 XPR.BlueCargo 检测的内容:磁盘映像背景图像中的字符串。

XPR.BlueCargo 枚举系统上的多个磁盘映像,然后获取它们的背景图像,并使用 OCR 检索其中的文本字符串。之后,它搜索与 Gatekeeper 绕过相关的字符串,如 Option clickright click, click open。如果找到此类字符串,它会将包括磁盘映像信息在内的信息报告给苹果。

那么,XPR.BlueCargo 检测的是哪个恶意软件家族?老实说,我认为它并非针对任何特定的家族。事实上,XPR.BlueCargo 可以检测多个恶意软件家族使用的磁盘映像,例如 EmpireCobalt Strike。因此,苹果可能打算将 BlueCargo 扩展为一种威胁狩猎扫描器,以帮助识别新出现的威胁。

有趣的是,XPR.BlueCargo 曾经有一个机制来检测没有后台文件的进程。正如这里所说明的,这个机制是使用检测构建器像这样实现的。这个机制已经被移除

你的流量不会说谎:通过应用行为揭露供应链攻击 🕵️♂️

在本节课中,我们将学习如何通过分析应用程序的网络行为来检测供应链攻击。我们将介绍一个名为BEAM的开源工具,它能够分析网络流量,为应用程序建立行为模型,并识别潜在的恶意活动。

概述

供应链攻击,例如SolarWinds事件,对成熟的安全组织也构成了严重威胁。传统的安全措施(如漏洞扫描、渗透测试)有时无法检测到这类攻击。我们的研究旨在通过监控应用程序在部署后的网络行为,来识别异常和潜在的恶意活动。

上一节我们介绍了供应链攻击的严峻性,本节中我们来看看我们的研究在整个安全领域中的定位。

研究背景与定位

在讨论我们的研究之前,了解当前的安全态势很重要。如果我们观察软件开发生命周期,从开发者编写代码到软件在客户环境中运行,威胁可能存在于多个环节。

以下是软件供应链中可能存在的威胁点列表:

  • 开发者的凭证可能被泄露,代码可能被修改。
  • 攻击者可能直接攻击源代码管理系统并破坏它。
  • 攻击者可能绕过上一步,在代码进入CI/CD系统时进行修改。
  • 攻击者可能直接破坏CI/CD系统本身。
  • 攻击者可能在软件分发到分发端点的途中替换构件。
  • 攻击者可能直接破坏分发端点本身。
  • 攻击者可能完全跳过整个过程,直接在软件到达客户环境的途中替换应用程序。

如果软件有任何依赖库,那么所有这些威胁也存在于依赖链中。因此,Colin和我开始构思将检测器放置在何处。我们注意到,理想的检测位置是在“使用”阶段。我们希望建立一个控制措施,能够在应用程序行为异常、可能恶意或出现值得进一步调查的偏差时进行识别,并且能够解释发生了什么。

接下来,我们将看看这种检测的理想形态。

检测目标

我们希望检测器位于软件部署之后,即在真实环境的用户设备上运行。在大多数情况下,你会看到像Box客户端这样的应用程序在运行并与服务通信。我们的目标是发现应用程序突然不再只与B通信,而是开始与其他可能恶意的端点通信的情况。

如果我们真的在网络中发现了这种情况,我们希望看到什么样的信息呢?

在我们的理想场景中,我们希望看到类似这样的信息:主机 dgmai.io 的通信是异常的,并且它有一个特定的置信度(例如99%确信这是Box客户端的异常)。我们还希望看到原因解释,即它是如何得出这个结论的,具体哪里异常。

以下是我们在幻灯片上希望看到的三个解释示例:

  • URL熵值:此URL中字符的随机性与Box通常看到的URL不同,这使异常的可能性增加了5倍。
  • 应用程序主机:与此Box应用程序通信的典型主机列表中,没有出现过这个主机,这使异常的可能性增加了4倍以上。
  • 路径深度:Box与服务器通信时通常会访问包含文件哈希或API版本信息的路径,但这次通信的路径长度不同,是一个根路径,这使异常的可能性增加了3倍。

这听起来可能有些困难:监控一个拥有数千名员工、使用无数不同应用程序、每天进行各种活动的大型组织,并找到那根“异常的针”。然而,我们发现,如果我们将问题分解,单独为每个应用程序建立档案,问题就变得更容易处理。

基于这种思路,我们创建并发布了一个开源工具。

BEAM工具介绍

我们创建了一个名为BEAM(行为评估应用指标)的开源工具。BEAM分析网络流量捕获文件,为其中的应用程序建模,并检测这些应用程序中可能发生的入侵。该工具从今天起可用。

BEAM内置了8种不同常见应用程序的模型。在Netcope,我们的客户遍布全球各行各业,我们能够看到他们使用什么。因此,我们选择了8个最常见的应用程序。这意味着你可以进入我们的代码仓库,下载软件并部署,今天就可以检测这些应用程序的异常,而无需学习期。

但我们真正想讨论的是这项研究本身。接下来,让我们深入了解研究的数据基础。

数据基础

当我们谈论投入BEAM的研究时,必须从数据开始。我们通过分析数据获得了许多见解。在Netcope,我们整理了大约2000个组织的数据,产生了约560亿次“事务”。这里的一个“事务”指的是一个HTTP请求-响应对。例如,一个客户端应用程序向服务器发送GET请求,服务器返回200状态码和一些JSON数据,这个请求-响应对就是我们所说的事务。

这些事务来自420万台不同的设备(用户笔记本电脑、台式机、服务器等)。这些设备上运行着150万个不同的原生应用程序(不是浏览器或云服务网站,而是像Discord、Box客户端、Slack、Spotify等人们下载安装的应用程序)。这些应用程序有750万个不同的用户代理字符串。因此,在接下来的讨论中,当我们提到数据时,指的就是这些。

有了数据之后,我们遵循一个三步法来构建检测器。

三步法构建检测器

我们遵循一个三步法来构建检测器,并将在接下来的内容中逐步讲解。

第一阶段:归因。我们拥有这些事务,首先要做的是识别事务来自哪个应用程序。为此,我们从事务本身获取一些信息,并用应用程序信息为其打上标签。

第二阶段:建模。一旦我们拥有了某个应用程序的所有事务,接下来就是像Colin说的那样,建立一个档案。我们想要捕捉应用程序的本质:它是做什么的?对于这个特定应用程序,典型的数据模式是什么样的?

第三阶段:检测与解释。一旦我们有了应用程序的模型,对于任何新来的事务,我们对照已知的正常行为进行检查,看是否存在偏差。如果存在偏差,它是否大到足以构成异常?如果是异常,原因是什么?它是否恶意?这些见解最终被塑造成检测器。

接下来,Colin将详细介绍归因步骤。

第一步:归因

归因意味着我们查看一些网络流量,并希望识别是哪些应用程序生成了这些流量。在BEAM中,我们有一个组件负责这项工作。

我们首先在流量捕获中利用用户代理字符串。通常,安全专业人员会避免使用用户代理字符串,原因有几个:首先,它是可编辑的,用户可以修改它;其次,用户代理字符串没有标准结构,只是一堆文本,难以处理。

然而,正如我们提到的,Netcope拥有大量来自全球各地组织日常活动的数据,这些用户不会每次使用Slack或Asana时都修改他们的用户代理字符串。因此,我们对大量流量的原始用户代理字符串有很高的置信度。

我们如何应对用户代理字符串的非标准性呢?我们发现,通过实验,一些大语言模型能够很好地总结用户代理的含义。在BEAM中,我们包含了一个Llama模型,但也构建了一个连接器,可以连接到Gemini API(如果你有Gemini账户)。这是我们尝试将用户代理字符串转换为应用程序名称的一种方式。我们还使用了一些Python库来做同样的事情。我们最终想要得到的是一个应用程序名称和版本号,例如 Chrome 134Box

完成归因后,下一步是建模。

第二步:应用程序建模

现在我们已经有了事务,并用其来源的应用程序为这些事务打上了标签。接下来我们要做的是,正如我们讨论过的,为这些应用程序建立一个模型。我们通过一个模型训练阶段来完成。

当我们开始思考要从这些事务中提取哪些信号时,Colin和我开始列一个清单。我们肯定希望识别任何不寻常的域名连接(类似Sunburst恶意软件),看到任何异常的代码仓库访问(类似3CX攻击),并且绝对希望看到任何大型的、意外的出站数据传输(类似MOVEit事件)。

当我们列出这个清单时,最终得到了185个不同的信号,多到无法放在一张幻灯片上。我们这里只挑选了几个有代表性的例子。完整的列表可以在我们开源的代码仓库中找到。

以下是几个示例特征:

  • 请求耗时:客户端发送请求到收到响应的时间。我们提取其最小值、最大值、中位数、偏差等统计信息。
  • 请求间隔时间:请求之间的时间间隔。是固定的、机械的,还是更突发、更接近人类使用模式的?
  • 请求序列:应用程序是否遵循特定的请求模式(例如,先GET到A服务器,再POST到B服务器)?
  • 典型的HTTP方法和状态码:应用程序通常使用哪些HTTP方法(GET, POST, DELETE等)和状态码?
  • 传输的文件:是否有文件被移动?文件类型是什么?例如,云存储应用Box和音乐流媒体服务Spotify传输的文件类型会非常不同。

一旦我们有了这185个特征,下一步就是测试这个思路是否可行。

初步建模测试

我们选取了20个在几乎所有组织中都能看到的应用程序,还加入了一些我们已有的恶意软件流量。我们建立了一个简单的多分类随机森林模型,每个应用程序作为一个类别。这是一个快速测试,看看这种方法是否有效。

我们发现,即使数据量不大,模型也能相当好地区分不同的应用程序。在热力图中,纵轴是真实值,横轴是预测值。你可以看到从左上到右下有一条蓝色的阴影对角线,表明大多数时候我们都能正确区分是哪个应用程序。当然,也有一些难以区分的情况,例如Chrome、Edge和Box有点难以区分,Microsoft Word和Excel也有点难以区分。但总体而言,我们做得不错。恶意软件类别(从上往下数第四或第五个)也能与其他应用程序区分开来。

这给了我们继续构建检测器的信心。我们希望这个检测器不仅能给出预测,还能解释为什么会有这样的预测。接下来,我们进行了更大规模的建模。

大规模建模与可解释性

我们使用了尽可能多的数据,从560亿次事务中,为每个应用程序使用了50万次观察数据(而非之前的5000次)。并且,我们没有使用一个随机森林模型,而是改为为每个应用程序建立一个XGBoost模型。这样每个应用程序都有自己的模型,能更好地捕捉其真实行为。更多的流量、更好的模型、更好的设置。

以Box客户端应用为例,我们实际上能很好地判断哪些观察数据属于Box,哪些不属于。关于可解释性,模型到底捕捉到了什么?为了帮助我们理解,我们使用了SHAP图。SHAP图允许我们看到哪些特征对这个特定模型是重要的。

对于Box模型,重要的特征包括:

  • 客户端字节数:客户端应用程序发送到服务器的数据量(平均值、中位数、最小值、最大值)很重要。
  • 目标域名box.netapi.box.com 等域名很重要,因为那是Box通常发送数据的地方。
  • 服务器响应内容类型:服务器以JSON响应,这个特征也很重要。

所有这些特征帮助我们深入了解Box的行为方式,从而能够捕捉其本质。其他应用程序也有类似的结果,每个应用程序都有自己的模型、特征集和重要的信号集,并且都有较高的准确率、检出率和较低的误报率。

这给了我们很大信心进入下一部分,也是我最喜欢的部分:实际威胁检测。

红蓝队演练:实战检测

接下来的阶段是:很好,我们可以识别应用程序并为其建立档案,但这有用吗?我们能用它检测到真正的威胁吗?

为此,我们在内部进行了一次红蓝队演练。我们找到了一位在Netcope内部经常进行红队演练的同事Mohanraj,他同意帮助我们。我们告诉他:“我们正在做这个项目,分析这些常见应用程序。我们希望你在其中选择一个,设置一个场景:入侵它并与你自己的C2服务器通信。不要告诉我们你入侵了哪个应用程序,也不要告诉我们关于你的C2服务器的任何信息,什么都别说。只管做。然后我们看看能否在网络流量中找到它。”

我们的任务是对这些常见应用程序建模,然后检测这种通信。

Mohanraj最终选择了Spotify。他在一个叫做 GitHub Codespaces 的服务上设置了他的命令控制服务器。这是一个简单的示意图:受害机器运行,Mohanraj感染了它,Spotify在运行,它像预期那样与Spotify通信,同时也与GitHub Codespaces通信。如果只是聚合地看这个流量,可能不会引起任何警觉,因为这看起来就像是开发人员在听音乐并使用GitHub Codespaces。

在受害机器上,我们可以看到客户端在运行,并使用一个名为 superduperchains.github.dev 的服务器(即C2 URL)。攻击者控制台显示,攻击者成功获得了受害机器的远程代码执行权限,可以运行 whoamipwd 等命令。

然后我们获取了网络流量,并运行我们的概念验证工具。果然,我们的工具显示Spotify正在与这个 github.dev 域名通信,并以94%的置信度判定其为异常。我们成功了。

当我们把这个结果展示给Mohanraj时,他的反应让我们像小学生一样咯咯直笑。接下来,让我们解释一下这个异常检测背后的原因。

异常解释

Mohan设置了攻击,我们获取了流量,并通过早期版本的BEAM成功检测到了它。但检测具体依赖于什么呢?

这里我们再次使用了SHAP图。简而言之,SHAP图给出了对这个预测重要的特征列表,以及它们的影响方向:是将其推向“异常”一侧,还是推向“正常”一侧。

图中列出了所有将预测推向“异常”一侧(增量)的特征,也有少数蓝色特征将其推向另一侧。由于时间有限,我们无法深入讲解每一个,因此挑选了5个快速说明:

  1. 请求耗时:对于Spotify来说,这次通信的请求耗时与我们通常看到的Spotify通信模式不符。
  2. 客户端字节数:总和、平均值和最小值都与Spotify的典型模式不符。这是客户端发送到服务器的数据量。
  3. (补充) 值得一提的是,Mohan试图保持“低调缓慢”,因此我们观察到的事务数量与Spotify的正常通信模式一致,这稍微将预测推向了“正常”一侧(蓝色部分)。
  4. (补充) 但总体而言,所有其他特征都将其标记为异常。
  5. (补充) 因此,即使他试图低调,仍然出现在我们的雷达上,我们能够以94%的置信度将其标记为异常。

接下来,Colin将演示BEAM工具目前是如何操作的。

BEAM工具演示

到目前为止,我们展示的都是这项研究的前期工作。我们也想展示一下这个工具目前是如何操作的。我将运行一个演示,这个演示在GitHub代码仓库中也是可用的,每个人在下载后都可以运行。

演示包含了一个我们一直在讨论的场景的网络流量捕获:有一个Box客户端,突然开始与 dgmai.io 服务器通信。

在屏幕顶部,可以看到一个HAR文件正在被BEAM分析。它解析了300个网络事务,将它们映射到对应的应用程序,然后运行特征提取和我们的检测器。基本上,它会说:“在这个网络流量捕获中发现了7个应用程序,我为其中一个(Box)建立了模型。BEAM会自动运行检测器。”

在这个案例中,它运行了检测器,并发现了一个“严重入侵”。这正是它发现的与 dgmai.io 的通信。然后,它给出了前几个原因。我们不想在输出中添加过多文本,所以只显示了贡献于该异常概率的前几个指标。任何流量捕获文件都会以相同方式运行,显示前几个原因。如果你想查看更多,可以查看在文件系统上生成的SHAP图。

现在,让我们回到幻灯片,看看这个SHAP图。

深入分析SHAP图

每次我们运行那个演示都让我有点激动。我们快速浏览这些幻灯片,很容易让人以为研究进展得很快,但事实并非如此,其中有很多试错。不过,正如Colin所说,所有这些现在都可以在BEAM中实现。

如果你下载并运行它,你会得到一个类似下面的SHAP图。我们再次挑选了前四个特征来重点说明:

  1. URL熵值:URL的香农熵值与Box通常的通信方式不符。Box的URL通常包含更多用于识别文件、文件块更新等信息。
  2. 服务器字节数:服务器返回给应用程序的数据量也不符。
  3. 请求耗时:请求花费的时间与Box应用程序的行为不一致。
  4. 关键主机名:通常,当我们看到Box与服务器、主机通信时,这不是我们看到的通信主机类型。这不仅不是我们见过的任何主机,而且与任何已知主机都无关,因此非常异常。

由于这四个以及许多其他原因,我们以约99%的置信度将其标记为异常。

当我们讨论这些“推动”值时,需要强调它们是以对数几率表示的。例如,一个特征推动值增加0.05,实际上使异常的可能性增加了1.05倍;推动值增加1.7,则使异常的可能性增加了5.47倍。这是一个非常显著的增长,表明该特征与Box流量的偏离程度非常大。

回到Colin在介绍中提到的,我们希望构建一个能标记类似以下情况的检测器:与该域名的通信是异常的,置信度很高,并且我们想要其背后的可解释性。为什么是异常的?

  • URL随机性不符,这使异常的可能性增加了5倍。
  • 通信的主机不符,不仅不是典型主机,而且与任何已知主机无关,这使异常的可能性增加了4倍。
  • 路径深度不符,这使异常的可能性增加了3倍。

由于这些以及许多其他原因,我们将其标记为异常通信。

接下来,Colin将谈谈如何为你自己的应用程序添加模型。

支持自定义模型

你们可能会想:你们能用8个应用程序做这些很棒,但我运行的其他应用程序呢?

我们希望通过在BEAM中加入添加更多模型的能力来解决这个问题。你可以将自定义或专属模型添加到BEAM运行的模型组合中。你所需要的只是网络流量捕获文件(PCAP或HAR文件)。

我们有一个无监督机器学习组件,它会获取这些流量捕获,寻找任何非浏览器应用程序并为其建模。需要注意的是,像任何机器学习一样,数据越多越好。我们为任何应用程序设置了一个至少100次事务的阈值。如果你的流量捕获想训练一个新模型,里面需要至少有100次该应用程序的事务。如果没有,BEAM会发现该应用程序,但不会为其生成模型。

那么无监督训练是什么样的呢?它是一个集成模型,包含隔离森林、一类支持向量机和自编码器。这三者共同作用,能够在你提供的网络流量中发现异常。这与我们在Netcope离线做的略有不同,但这是我们今天能提供的最佳版本。

让我带你过另一个场景:假设我想为Notion创建一个模型。我创建了一个Windows客户端,下载了Notion客户端和Proxyman(用于捕获流量)。我设置好客户端和Proxyman,然后运行它。它在与Notion通信时捕获了流量,生成了一个HAR文件。现在,我将这个HAR文件作为输入提供给BEAM,并告诉它进行训练。它就会继续为我创建一个新模型。

另外请注意,我们有一个最小事务数的阈值。在这个例子中,不仅Notion在运行,VS Code也在运行,但它的流量不足以创建模型,所以我们只得到了Notion的模型。

到目前为止,我们一直在演示入侵检测。我也想展示一下如果没有入侵会是什么样子。我使用一个HAR文件为Notion创建了一个新模型,然后重用同一个HAR文件并通过检测器运行它。在这种情况下,它没有检测到任何异常,一切看起来都很好。

接下来,让我们谈谈未来的改进方向。

未来工作与改进方向

每次我们进行尝试和测试,当有成功的事情发生时,总会伴随出现两三个需要改进或做得更好的地方。由于时间有限,我们无法涵盖所有,因此挑选了目前我们最关注的三个方向:

  1. 高熵值应用程序:我们提到的8个应用程序,我们检测异常做得很好。但某些应用程序(例如浏览器)则相当困难。因为很难跨多个设备捕捉它们的本质或建立档案,每个人使用

“检测到坏点” - 苹果图形子系统安全评估 🖥️🔍

在本课程中,我们将学习苹果图形子系统的安全状况。我们将探讨其架构、其中发现的安全漏洞,并分析这些漏洞的成因与影响。课程内容基于对多个内核模块和固件组件的深入研究。

图形子系统架构概览

首先,我们快速浏览一下苹果图形子系统的架构。

我知道它看起来很复杂。现在请不要细读,稍后可以仔细查看。我们想在这里说明的观点是:图形子系统过于复杂,难以做到完美。

让我们首先关注内核模块,特别是中间部分。这部分包含了负责与不同供应商(包括英特尔、AMD和苹果自研芯片的GPU)的GPU进行通信的内核模块。

以下是我们在过去从这些模块中发现的三个漏洞,我将逐一介绍它们。它们分别对应AMD GPU平台、基于英特尔的内核插件扩展以及苹果英特尔和E帧缓冲内核扩展。

内核模块中的漏洞分析

上一节我们介绍了图形子系统的整体架构,本节中我们来看看其中一些具体的内核模块漏洞。

漏洞一:AMD支持内核扩展中的任意内存写入

第一个要讨论的漏洞可导致任意内存写入。这是调试器中崩溃的字符串截图。我们可以看到,偏移量被用来计算一个内核内存地址。

崩溃发生处的指令显示,寄存器RCX是一个用于计算内核内存地址的偏移量。如果你查看该寄存器中存储的值,它是一个“魔法值”,这意味着它完全可由用户控制。

从回溯中我们还可以看到,这个漏洞源于AMD支持内核扩展。漏洞的根本原因是该函数没有对用户输入进行充分的清理。

漏洞二:显示矩阵模块中的越界读写

类似地,由于缺乏检查,这个显示矩阵模块也存在一个越界读写漏洞。如果你注意一下符号,会发现这个模块中所有相关函数都没有符号名。这不是我们不愿意分享细节,而是因为苹果没有为这个模块提供内核调试符号。正如你所料,逆向工程这个模块耗费了我们大量的精力。

漏洞三:AppleIntelMEClientController模块中的类型混淆

这是AppleIntelMEClientController模块中的另一个类型混淆漏洞。在正常情况下,这些函数会在堆上分配一个大小为40字节的对象。然而,存在一个易受攻击的分支,它错误地将这些对象视为一个更大的结构体,从而导致越界内存访问。屏幕上显示的是发生越界访问和调用栈的位置。

我刚才讨论的这三个漏洞都相对较旧。现在,让我分享一个我们最近在AppleIntel图形模块中发现的新漏洞。

近期发现的漏洞

我们已经讨论了相对较旧的漏洞,现在让我们关注一个近期在AppleIntel图形模块中发现的新问题。

其根本原因是,In content key这个特定函数没有对用户提供的参数进行任何检查,而这些参数将被用于索引要写入的内存地址。正如我们所见,索引存储在寄存器RCX中,它被设置为一个魔法数字,这也意味着它可由用户控制。

另一个有趣的漏洞是我们在去年十月发现并提交的,但直到今年秋天才会修复,因此我们无法分享更多细节。我们怀疑该模块正在进行重大的代码重构以消除整个攻击面,这就是为什么修复需要将近一年的时间。

苹果自研GPU模块的漏洞

现在我们已经讨论了苹果用于英特尔和AMD GPU的内核模块,我们也不应遗漏苹果自己的GPU,对吧?

首先,这里有一些其他安全研究人员发现的先前漏洞的优秀资料,如果你想了解更多关于这些模块的信息,我们强烈建议阅读。

其中,第一篇和第三篇博客都是苹果图形加速器模块的经典漏洞。虽然第二篇博客是针对基于英特尔架构的案例研究,但文章中提到的攻击面与我即将讨论的一个新漏洞直接相关。

漏洞四:GPU通知队列机制

关于我们在苹果自家GPU模块中发现的漏洞,我想分享的第一个与GPU的通知队列机制有关。

在逆向工程接口时,我们发现了这个特定的函数create_notification_queue,它接受来自用户的两个关键参数,但清理不足:条目数量和条目大小,这将导致越界访问。

为了验证这是一个真正的漏洞,我们还制作了一个简单的概念验证来触发它。这是调试器中该崩溃的截图。

该漏洞的补丁也很直接。我们只需要确保输入经过清理并且是有效的。

一个有趣的故事是,我们确切知道这个漏洞会导致可被进一步利用的越界写入。然而,苹果安全更新的描述仅仅说这是一个拒绝服务漏洞。这是因为我们提交给苹果的概念验证只是由于访问了某些随机无效地址而导致内核崩溃。然而,如果我们精心构造概念验证,它就会变成一个更强大的越界写入原语。

你可能会问,为什么我们如此在意这一句可能没人会注意的话?我们确实在意。拒绝服务不如越界写入严重。安全社区已经达成明确共识,本地拒绝服务不应有资格获得CVE分配。所以我们对此很认真。这不仅仅是我个人的看法,这样的描述会导致混淆。我们还发现其他一些研究人员也被苹果更新的描述搞糊涂了,他们甚至写文章解释为什么例如空指针解引用无法被利用,以及为什么苹果甚至为这些低风险漏洞分配CVE。事实是,他们只是没有仔细考虑实际的根本原因和安全影响。我们已经与苹果沟通,他们承诺会更新描述以使其更清晰。

漏洞五:GPU资源分配函数

今天我想分享的另一个漏洞与GPU的资源分配函数有关。

这次的描述很清晰。这是一个影响iOS和macOS的内核内存写入漏洞。

正如我之前提到的,为了让描述尽可能准确,你必须证明这个漏洞是可被利用的。这是我们初始概念验证的崩溃截图。我们没有提交这个,因为我们确切知道苹果只会将其视为本地拒绝服务。因此,我们做了大量工作来改进概念验证,以证明这实际上是可被利用的。在这里我们可以看到,用于计算内核内存地址的寄存器是X8和X9,我们成功地操纵了这两个寄存器,使其指向一个有效的内核地址,从而导致可被利用的越界写入。

关于这个漏洞的另一件有趣的事情是,最初的补丁只处理了我们在概念验证中报告的代码路径。因此,他们没有进行充分的检查。我们发现了另一种不同的输入,可以绕过他们最初的补丁。

所以这是我们制作的新概念验证的另一次崩溃,在我们提交另一个概念验证给他们之后,他们不得不再次修补同一个漏洞。

IOMobileFramebuffer 模块的漏洞

接下来,我将讨论我们在另一个内核组件中发现的漏洞,特别是这个IOMobileFramebuffer。

如果你了解的话,这实际上是iOS安全社区中一个备受关注的攻击面。这是因为可以直接从网页内容访问此组件,这意味着该组件可以帮助攻击者突破浏览器沙箱等防御。

根据公开记录,过去20年中已报告了16个来自该模块的内核漏洞,其中4个被APT组织积极利用,两个被用于iOS越狱工具,还有一个在安全竞赛中亮相。

从2011年到2020年的时间线可以看出,这个特定模块IOMobileFramebuffer中的漏洞数量并不多,只报告了几个漏洞。

然而,在2020年左右出现了一个转折点。一次重大的代码重构引入了大量的内核漏洞。这就是为什么我们在接下来的两年里目睹了该模块安全问题的急剧激增。

在这里,我们想强调两点。首先,你可以看到大约有六个月的窗口期,这反映了安全社区对新模块中漏洞的典型响应时间,大约是半年。其次,我们认为这种鲁莽的重构有时会给系统带来灾难性的后果。

自那以后,该模块没有报告新的漏洞。这是否意味着它已经足够安全了?

这里需要注意的一点是,实际上2024年报告了一些其他漏洞。它们实际上被错误地归类为IOMobileFramebuffer漏洞。事实上,它们是来自显示协处理器固件的问题,我稍后会谈到。

对于想了解更多关于这个模块的人,请参考这些资源。这些都是非常好的资料。它们从一些简单且非常容易上手的目标开始。

架构转变与新攻击面

从2021年下半年开始,出现了一个新趋势。许多关键功能的实现已从IOMobileFramebuffer模块下移到更下一层,即显示协处理器固件。这种架构转变意味着用户模式不能再直接访问这个攻击面,有效地形成了一定程度的纵深防御。

在这种情况下,我们还能在这个模块中找到新的漏洞吗?答案当然是肯定的。否则,我就不会谈论它了。

以下是反编译的代码片段,我会展示几秒钟,看看观众中是否有人能发现问题。这只是带有单个参数的几行代码。

我还高亮了你应该注意的地方。从截图中我们可以看到,输入参数是一个有符号整数,但实际上在第15行被用作无符号整数。中间还有一个条件检查,以确保索引不会太大。然而,正如你所想象的,如果索引是负值,这很容易被绕过。

我相信,大多数编译器应该能够轻松检测到此类问题,但我们惊讶地了解到,这个漏洞直到最近仍然存在。这是该漏洞崩溃的截图。

这是该漏洞的调用栈。值得注意的是,这个漏洞可以直接由用户触发,无需申请任何权限或授权。

另一件有趣的事情是,我们实际上发现macOS的两个主要版本对此漏洞有两种不同的修复实现。第一种方法是保持输入参数索引为有符号整数,并在此函数中添加了另一个负值检测检查。第二种方法则完全不同。它将此索引转换为无符号值,这样他们就不需要在那里添加任何新的检查了。

我们很好奇为什么存在两种不同的补丁,这似乎意味着他们有不同的小组在为不同版本的macOS处理同一个模块。我不知道观众中是否有人对此有见解。如果能知道原因,那会非常有趣。

我们还发现了一些其他问题,但它们都很相似,因此不再赘述。

深入固件层

现在,让我们再深入一层,到固件层。

首先,我想参考这个Asahi Linux和M1N1项目作为背景。该团队在DCP架构的逆向工程方面做了非常扎实的工作。

我们还列出了该领域几个众所周知的漏洞,包括一些被称为Intro和Invite的CVE。强烈推荐阅读关于这些漏洞的分析报告。

为了理解DCP及其潜在的攻击面,我们基于此分析,对DCP架构及其与应用处理器的通信接口进行了逆向工程。基于此分析,我们开发了一个定制的模糊测试工具。

通过模糊测试,我们成功触发了大量的崩溃。例如,像这个,你可以从内存中看到一些关于崩溃的信息。例如,在这个红色方框中,你可以看到像“AT固件报告异常”这样的字符串。

这是另一个表明DCP固件存在问题的崩溃日志截图。我们还提供了崩溃的调用栈。你可以看到崩溃数据是通过这个RTBuddy机制在DCP和AP之间传递的。所以DCP和AP是不同的处理器。它们彼此通信的方式就是通过这个RTBuddy机制。这也是我们如何从固件收集详细错误报告的方式。我们直接从调试器读取内存数据来收集所有这些信息,这确实帮助我们更好地理解漏洞的根本原因。

我们的模糊测试还发现了几个有趣的新接口,包括一个在以往安全研究中很少受到关注的视频接口。使用这些接口,用户模式应用程序可以直接与DCP固件通信,无需任何权限或授权。

所有这些崩溃标志着我们研究的突破。通过进一步分析这些接口,我们发现了额外的漏洞,包括这一个。你可以看到这是最近才确认的,苹果确认这个漏洞实际上影响了iOS和macOS的最新版本。

这是模糊测试期间该漏洞的崩溃日志。我们可以看到DCP通过这个RTBuddy机制传输了大量信息。然而,由于攻击面仍然存在问题,我们目前无法披露其细节。我们现在可以分享的是,DCP显示协处理器固件中的许多寄存器,如R2、R8甚至这个LR链接寄存器,都可以由用户直接控制。这些漏洞和攻击面构成了重大风险。

总结与启示

最后,我们总结几点启示。

让我们回顾一下这张幻灯片。我们的研究在几乎每一个图形子系统组件中都发现了漏洞,涵盖了传统的AMD、英特尔GPU架构、AGX GPU设计、苹果的内核模块(如流行的IOMobileFramebuffer),甚至包括像DCP这样的固件。虽然已经取得了重大的安全进展,但我们相信仍有改进的空间。

我们将从三个角度总结本次演讲:安全工程、漏洞挖掘以及攻防态势。

首先,从安全工程的角度来看:

  • 新功能总是意味着新的攻击面。
  • 鲁莽的代码重构有时会对系统造成重大的安全影响。
  • 即使在人工智能和自动编码的时代,也无法保证它们总能产生正确的代码。这就是为什么我们应该制定策略或强制人们使用静态或动态分析工具,以使我们的代码更安全。
  • 定期审查编译警告是必要的。例如,有符号和无符号整数之间的比较,应该很容易被常规的静态分析器检测到,但它仍然被遗漏了。因此,我们建议人们定期审查所有警告,而不是忽略它们。

其次,从漏洞挖掘的角度来看:

  • 某些复杂的内核功能被安全社区反复发现包含严重漏洞。我们在苹果的蓝牙、Wi-Fi和图形子系统中发现了大量案例。
  • 就图形子系统中的漏洞数量而言,虽然我们只找到了比过去分析的其他模块更少的漏洞,但我们并不认为这是因为这个特定的图形子系统模块更安全。相反,我们觉得这只是因为苹果没有为相关模块提供足够的调试信息,而且他们确实有一些纵深防御措施,就像我前面提到的。他们将一些主要组件从一层移到另一层,这样攻击面就不会直接暴露给用户,但代码仍然在那里。他们只是把它们从上层隐藏了起来。但是,如果你知道它们如何在各层之间通信,你仍然可以找到触发那些有问题的代码的方法。
  • 正如我所说,多个领域之间存在显著的知识差距。系统本身已经足够复杂,更糟糕的是,苹果没有提供足够的信息。所有这些因素都使得安全研究更加困难。我们认为,弥合这些差距将真正有助于安全。我们拥有来自安全社区的优秀专家,他们不断致力于此,这将使整个系统更加安全。

最后,我们想强调这个特定的模块:IOMobileFramebuffer。正如我之前提到的,这个模块可以直接从浏览器和网页内容访问。这就是为什么该领域的攻防竞争一度达到了白热化的程度。

从时间线分析来看,在2020年至2022年期间,漏洞研究相对于代码重构发生的时间存在滞后,这反映了我们发现漏洞的时间大约有半年的滞后。

因此,将易受攻击模块(如IOMobileFramebuffer)的功能转移到显示协处理器固件的做法,在某种程度上是有效的,因为它使人们更难分析和理解代码。但这种缓解措施只是稍微提高了门槛。然而,如果你没有修复根本原因,人们最终仍然会在那里发现漏洞。

本节课中我们一起学习了苹果图形子系统的安全状况,分析了从传统GPU支持模块到现代自研GPU架构,再到关键内核组件和底层固件中存在的多种类型漏洞。我们看到了代码复杂性、重构引入的风险以及安全工程实践的重要性。希望这些内容能帮助你理解该领域的安全挑战与研究思路。

posted @ 2026-03-28 12:21  布客飞龙V  阅读(2)  评论(0)    收藏  举报