
1. 从一次“意外”的权限请求说起理解Serpent攻击的入口如果你在macOS上开发或者使用过一些需要访问系统敏感区域的工具大概率见过一个弹窗上面写着“钥匙串想要访问您的钥匙串”。大多数时候我们都会不假思索地点击“始终允许”。这个看似平常的交互正是Serpent攻击能够得逞的起点。这个攻击的核心并非利用了某个复杂的、需要0day级别的内存破坏漏洞而是巧妙地利用了macOS钥匙串Keychain服务中一个关于权限继承和令牌Token管理的逻辑缺陷。攻击者可以诱导用户授权一个看似无害的应用程序之后该应用便能持续、静默地访问并窃取其他高价值应用的敏感数据特别是新兴的Apple Intelligence功能所依赖的认证令牌。简单来说Serpent攻击像是一条“毒蛇”它没有强行破门而入而是骗取了管家钥匙串访问权限的信任拿到了一把能打开家里所有抽屉其他应用存储的密钥和令牌的万能钥匙。这个漏洞的可怕之处在于其隐蔽性和持久性。一旦用户点击了“始终允许”恶意程序就获得了对钥匙串中“登录”钥匙串的持续访问权。而许多应用程序包括那些处理AI服务的都会将认证令牌、API密钥等敏感信息默认存储在这里。为什么Apple Intelligence令牌会成为高价值目标随着苹果将AI能力深度集成到操作系统和各类应用中这些AI功能如Siri增强、写作辅助、图像生成等背后需要与云端服务进行身份验证。用于验证用户身份、授权AI服务调用的令牌就成了数字身份的关键。窃取这些令牌攻击者可能得以冒用用户身份滥用AI服务、访问用户的私有数据如邮件、备忘录、对话历史甚至产生额外的服务费用。因此理解并防御Serpent攻击对于保护个人隐私和数字资产至关重要。2. macOS钥匙串安全模型理想与现实的裂缝要彻底理解Serpent攻击为何能成功我们必须先拆解macOS钥匙串设计上的安全假设以及这个假设在现实中被如何绕过。钥匙串是苹果生态系统的核心密码管理系统其设计初衷是安全地集中存储密码、证书、密钥和笔记。2.1 钥匙串的访问控制机制沙盒与代码签名macOS通过一套组合拳来保护钥匙串条目访问控制列表ACL每个钥匙串条目都附有一份ACL定义了“哪些应用程序”在“满足何种条件时”可以访问该条目。条件可能包括需要用户密码Keychain Password、需要生物识别Touch ID或始终允许。代码签名Code SigningmacOS可以识别应用程序的唯一身份这是通过其代码签名证书实现的。ACL中的“应用程序”标识通常就是其代码签名哈希Code Signing Hash或团队标识符Team Identifier。这理论上可以防止一个恶意应用冒充另一个合法应用。钥匙串域Keychain Domains分为“登录”、“系统”、“本地项目”等。用户最常交互的是“登录”钥匙串它随用户登录而解锁存储了大多数用户级应用的秘密。当应用程序首次尝试访问钥匙串时系统会弹出授权对话框列出请求的应用名称和请求的钥匙串通常是“登录”。用户可以选择“拒绝”、“允许一次”或“始终允许”。如果选择“始终允许”该应用的代码签名身份就会被添加到目标钥匙串条目的ACL中。2.2 Serpent攻击利用的裂缝权限的过度继承这里就出现了安全模型中的一个关键裂缝当应用A被授权访问“登录”钥匙串后它获得的权限范围是什么理想的安全模型可能期望是应用A只能访问它自己创建或明确指定的条目。但现实是在macOS的某些实现逻辑中特别是涉及钥匙串的“搜索Search”操作时一旦应用被授予对某个钥匙串如“登录”钥匙串的访问权限它可能获得在该钥匙串内进行广泛搜索的能力。这意味着应用A可以枚举“登录”钥匙串中存储的、属于其他应用B、C、D的大量条目元数据如服务名称、账户名等。更致命的一步在于对于某些类型的条目特别是那些由系统框架或通用密钥链服务创建的、用于存储网络认证令牌的条目其ACL可能不够严格或者其访问控制依赖于钥匙串的整体解锁状态而非精细的每条目ACL。攻击者应用在通过“始终允许”获得钥匙串访问权后便可能直接读取这些条目的秘密数据而无需再次征得用户同意。一个生活化的类比这就像你给了快递员进入小区大门登录钥匙串的长期门禁卡本意是让他能把包裹放到你家门口的快递柜应用自己的存储区域。但小区的设计是所有住户的信箱其他应用的令牌都集中放在大门内的一个公共区域并且这些信箱的锁ACL很多都不牢靠或者默认对“进入小区的人”开放。于是这个快递员就可以在送包裹之余随意翻看所有住户的信件。Serpent攻击正是利用了这种“大门权限”被过度解释为“室内所有抽屉的访问权限”的逻辑缺陷。攻击者只需要诱导用户授予一次性的、对“钥匙串”本身的访问权限后续的窃取行为便可以完全在后台静默进行。3. 攻击链深度复现从诱导授权到令牌窃取理解了原理我们来看一个模拟的攻击链是如何一步步展开的。请注意以下描述仅用于教育目的以帮助开发者和安全研究人员构建更安全的防御切勿用于非法活动。3.1 阶段一制作诱饵与获取初始权限攻击者首先需要制作一个“诱饵”应用。这个应用通常会伪装成以下形态一个看似有用的工具如系统优化工具、壁纸管理器、文档格式转换器等。一个需要“合理”钥匙串访问权限的应用例如一个声称可以帮你管理Wi-Fi密码或自动填充密码的小工具。它会在其Info.plist文件中声明需要钥匙串访问权限或者在代码中调用钥匙串API。当用户下载并运行这个应用可能来自非App Store的不明来源或通过社交工程诱骗它首次尝试访问钥匙串时系统弹窗出现“‘XX优化工具’想要访问‘登录’钥匙串中的项目”。许多用户出于便利或对弹窗内容不假思索点击了“始终允许”。关键点此时攻击者应用假设其团队标识符为EVILTEAMID的代码签名身份就被添加到了用户“登录”钥匙串的访问者列表中。这不是针对某一个具体的钥匙串条目而是针对钥匙串本身的一个“信任”关系。3.2 阶段二枚举与定位高价值令牌获得钥匙串访问权限后恶意应用便可以在后台执行类似以下的代码逻辑以Python的subprocess调用security命令行工具为例实际恶意软件可能直接用原生APIimport subprocess import json import re def enumerate_keychain_items(): # 使用 security 命令列出登录钥匙串中的所有条目 cmd [security, dump-keychain, -d, login.keychain] try: output subprocess.check_output(cmd, stderrsubprocess.STDOUT, textTrue) except subprocess.CalledProcessError as e: # 处理错误可能权限不足 return [] items [] current_item {} lines output.split(\n) for line in lines: if line.startswith(keychain:): if current_item: items.append(current_item) current_item {keychain: line.split(: )[1]} elif : in line: key, value line.split(:, 1) key key.strip() value value.strip() current_item[key] value # 匹配可能包含AI服务标识的账户或服务名 if account in current_item and AppleIntelligence in current_item.get(account, ): # 或者匹配特定的服务标识符如 com.apple.private.appleintelligence.token pass if current_item: items.append(current_item) return items # 过滤出感兴趣的目标 all_items enumerate_keychain_items() target_items [] for item in all_items: acct item.get(account, ) svce item.get(service, ) # 攻击者会寻找与Apple Intelligence相关的特征字符串 # 这些特征可能来自逆向工程或对早期Beta版的分析 if appleintel in acct.lower() or appleintel in svce.lower(): target_items.append(item) # 也可能广泛窃取所有互联网密码、令牌从中筛选 elif item.get(class, ) inet: target_items.append(item)通过这种方式攻击者可以扫描钥匙串寻找包含“AppleIntelligence”、“Siri”、“MLModel”或其他相关关键词的账户名、服务名或注释字段的条目。3.3 阶段三提取令牌数据定位到目标条目后便是提取实际的秘密数据令牌。对于ACL宽松的条目可以直接读取。security命令同样可以用于获取具体条目的密码秘密# 假设找到了一个服务为com.apple.private.appleintelligence.auth账户为userexample.com的条目 security find-internet-password -s com.apple.private.appleintelligence.auth -a userexample.com -w-w参数会直接输出密码令牌字符串到标准输出。在恶意应用中这个过程被自动化获取的令牌会被立即加密并外传到攻击者控制的服务器。为什么Apple Intelligence的令牌容易中招在开发初期或某些集成场景下为了便于调试和实现无缝用户体验开发团队可能将这些令牌以“互联网密码”inet类型的形式存储在登录钥匙串中并且其ACL可能设置为“允许任何信任的应用访问”或者依赖于钥匙串的整体解锁状态而非严格绑定到特定的客户端应用。这就为Serpent攻击提供了可乘之机。4. 防御策略从用户习惯到开发实践面对Serpent这类利用权限模型的攻击防御需要用户、开发者和系统三方的共同努力。4.1 给普通用户的实用建议警惕“始终允许”当任何应用尤其是从非官方渠道下载的应用请求钥匙串访问权限时务必保持警惕。思考它是否真的需要这个权限。优先选择“允许一次”观察应用行为。审查与管理钥匙串权限打开“钥匙串访问”应用。在左侧选择“登录”钥匙串。右键点击钥匙串选择“显示简介”。切换到“访问控制”标签页。这里列出了所有被授予访问权限的应用程序。定期检查这个列表移除任何不信任或不再使用的应用。对于具体的敏感条目如银行、邮箱、AI服务密码可以右键点击该条目 - “显示简介” - “访问控制”将其设置为“询问钥匙串密码”或“需要确认”并移除不必要的应用访问权限。使用系统偏好设置中的隐私与安全性前往“系统设置” - “隐私与安全性” - “应用程序软件”。这里可以管理哪些应用可以控制其他应用、访问辅助功能等。虽然不是直接管理钥匙串但这是控制应用行为的重要关口。优先从App Store获取应用App Store的应用经过沙盒化和苹果的审核其权限请求和行为受到更严格的限制能有效降低此类风险。4.2 给开发者的安全编码实践如果你正在开发涉及敏感令牌如OAuth令牌、API密钥、Apple Intelligence服务令牌的macOS应用以下实践至关重要为钥匙串条目设置最严格的ACL不要依赖默认设置。在创建钥匙串条目时明确指定只有你的应用可以访问。使用SecAccessCreateWithRules和SecKeychainItemSetAccess等API将ACL严格绑定到你应用的代码签名哈希或团队ID。// Swift示例创建一个仅本应用可访问的钥匙串条目 let query: [String: Any] [ kSecClass as String: kSecClassInternetPassword, kSecAttrServer as String: api.apple-intelligence.example.com, kSecAttrAccount as String: userAccount, kSecValueData as String: tokenData, kSecAttrAccessControl as String: SecAccessControlCreateWithFlags( nil, // 使用默认保护 kSecAttrAccessibleWhenUnlockedThisDeviceOnly, [.applicationPassword, .privateKeyUsage], // 根据需求设置标志 nil )!, kSecUseDataProtectionKeychain as String: true // 关键使用数据保护钥匙串 ] let status SecItemAdd(query as CFDictionary, nil)使用数据保护钥匙串Data Protection Keychain这是现代macOS和iOS推荐的方式。它提供了更强的加密和访问控制与应用的沙盒和代码签名深度集成。确保在钥匙串查询中设置kSecUseDataProtectionKeychain为true。考虑替代存储方案对于最高机密的密钥考虑使用安全飞地Secure Enclave进行存储和运算适用于加密密钥。对于可再生的会话令牌评估是否可以不进行持久化存储或者使用内存中的加密存储并在应用退出时清除。令牌最小化与刷新使用短期有效的令牌并实现令牌刷新机制。即使令牌被窃其有效期也很短限制了攻击窗口。在Info.plist中明确定义钥匙串访问组如果你的应用包含多个可执行文件或扩展使用钥匙串访问组Keychain Access Groups来在应用组件间安全共享密钥同时阻止外部访问。4.3 系统层面的缓解与更新苹果在获悉此类漏洞后通常会在后续的macOS更新中修复。作为用户保持系统更新到最新版本是根本的防御措施。修复可能包括收紧默认ACL系统创建的、用于存储全局服务令牌的钥匙串条目其ACL会被设置得更严格。改进权限对话框的表述使提示信息更清晰明确告知用户授予的是对“整个钥匙串”的搜索和访问权限而非单个密码。引入更细粒度的权限控制可能在未来提供“允许访问此应用的密码”而非“允许访问钥匙串”的选项。Serpent攻击揭示了即使在设计良好的安全系统中权限模型的抽象与现实使用之间也可能存在认知偏差和实现缝隙。它提醒我们安全是一个持续的过程需要用户保持警惕开发者遵循最佳实践以及平台厂商不断加固系统边界。对于正在快速发展的Apple Intelligence生态而言在追求便捷智能的同时将安全设计前置严格管控其核心令牌的生命周期是避免其成为下一个攻击富矿的关键。