当前位置: 首页 > 科技观察

深入探究解释型语言背后隐藏的攻击面,Part1(上)

时间:2023-03-17 11:35:41 科技观察

本文将与读者一起深入探究解释型语言背后隐藏的攻击面。简介攻击面就像一层蛋糕。我们通常将软件攻击面定义为对攻击者控制的输入做出反应或受??其影响的任何事物。在开发高级解释型语言应用程序时,很容易假设语言本身的运行时系统,或者代码库中的底层代码是可靠的。经验表明,这种假设是错误的。通常,在高级语言的内存管理功能的实现代码中,存在一个相对脆弱的基于C/C++的攻击面。这种问题可能存在于语言本身的核心实现中,也可能存在于将向高级语言提供基于C/C++的库的第三方语言生态系统中。这些第三方库通常通过显式外部函数接口(FFI)或其他形式的API转换包装器提供其功能,这些包装器有助于从低级代码使用高级对象,反之亦然。通常称为本机模块、扩展或某种形式的FFI首字母缩略词,此类攻击面的特点是与高级应用程序的安全上下文中的C/C++代码相关的各种内存管理漏洞暴露给攻击者。在本系列文章中,我们将探讨在高级语言应用程序上下文中有时被忽视的C/C++攻击面的示例,其中一些是旧的,一些是当前发现的。在第一部分中,我们提供了解释语言的低级攻击面的背景,并展示了一些跨语言的安全漏洞。在以后的文章中,我们将描述针对现代解释语言生态系统的新颖攻击技术,以及哪些功能倾向于将看似微小的编程错误转变为实际可利用的安全漏洞。本系列文章主要面向希望就如何、为何以及在何处将其攻击面暴露给潜在恶意输入做出明智决策的开发人员,因此我们将在需要时提供相应的软件漏洞利用理论参考。解释。为了便于讨论,我们对软件漏洞利用的定义大致如下:利用输入内容的影响,将目标进程从其预期状态空间转移到非预期状态空间的过程。决定一个代码问题是“只是”一个软件错误还是一个安全漏洞完全取决于上下文。一个bug被判断为安全漏洞,应该满足以下条件:帮助攻击者以一定的状态、方式或形式发起攻击。这本身是高度上下文相关的,尤其是在处理核心语言问题时。受影响的API如何以及在何处暴露给攻击者输入决定了它是否可以被视为安全漏洞。在解释语言的上下文中,有两种主要的攻击场景。在第一种情况下,攻击者可以在目标解释器上运行自己的程序。通常,他们的目标是破坏解释器本身的安全措施,以欺骗托管解释器的进程跨越某种安全边界。这方面的例子包括网络浏览器使用的Javascript解释器中的安全漏洞。这个主题的变体包括攻击者在攻击的第一阶段获得了运行任意解释代码的能力的场景,但是解释器本身强制执行某种限制(例如:由于严格的PHP配置阻止使用命令执行功能),从而限制了他们进行进一步攻击的能力。当攻击者可以完全访问目标解释器时,通常会在核心解释器的实现中发现漏洞。例如,各种Javascript解释器中存在内存管理漏洞,这些漏洞通常会演变成Web浏览器中可利用的客户端漏洞。由于攻击者可以完全控制解释器的状态,因此从攻击者的角度来看,解释器本身的任何错误都可能非常有用。在第二种情况下,攻击者可以利用解释语言实现中的某些逻辑,为其提供输入但无法直接与解释器交互。在这些情况下,攻击者的攻击范围受到他们实际可以直接或间接向其传递数据的API的限制。当攻击者只能控制以高级语言实现的目标进程的输入时,他们只能影响接收这些输入的逻辑,从而限制他们的选择。在这些情况下,深入挖掘以找到处理输入的底层攻击面可以揭示从更高级别的逻辑角度看不到的漏洞。从攻击者的角度来看,我们的主要目标是增加攻击面的深度。不要侧着挖,往下挖!剥糖解释语言可以在较低级别利用的漏洞由来已久。在本文中,我们不会给出这些漏洞的完整历史,但是,我们将深入研究一些有趣的示例-这些示例向我们展示了高级编程语言中的错误如何转化为低级编程语言中的安全漏洞-希望这些“老坑”能给读者带来新的灵感。历史示例:当Perl格式错误时2005年Perl代码中的格式字符串漏洞是一个有趣的案例。要完全理解这个安全问题,我们首先需要快速回顾一下C程序中格式字符串利用的基础知识。C格式字符串漏洞简介虽然许多人认为格式字符串错误由于易于检测而在很大程度上已被根除,但它们仍然时常出现在意想不到的地方。在与低级代码交互的解释语言的上下文中考虑格式字符串错误也很有趣,因为它们可能会在攻击者控制下的较高级别预处理格式字符串,然后直接传递给较低级别??的格式化程序。功能。这种延迟类型的格式化问题并不少见,尤其是当格式字符串的源和所述格式字符串的目标之间存在很强的逻辑分离时。简单地说,格式字符串错误是一类错误,攻击者将自己的格式字符串数据提供给格式化函数,例如printf(attacker_control)。然后他们可以滥用受控格式说明符的处理来实现对目标进程空间的读写原语。针对此类漏洞的实际攻击主要依赖于滥用%n和类似%hn的格式说明符的能力。这些格式说明符指示格式化函数将当前打印字符的运行计数分别写入整数(%n)或短整数(%hn)变量,例如printf("abcd%n",&count)将通过指针参数将值4写入整型变量count。同样,在格式函数的输出对攻击者可见的情况下,攻击者可以简单地转储内存内容。当将预期的目标指针值与其%n对应值对齐时,这种“吃掉”堆栈的能力也变得非常重要。如果攻击者能够向格式函数的调用堆栈提供受控数据(通常通过恶意格式字符串本身),并禁用所有编译器缓解措施,则攻击者可以将写入字符计数器的控制与指针值的Combine控制相结合写入%n/%hn以便他们可以将他们控制的值写入指定的内存位置。通过使用诸如在格式说明符上设置精度/宽度、将写入字符计数器设置为特定值以及在支持的情况下设置直接参数访问索引等技巧,即使是少量的格式化字符串输入也可以转换为攻击者的强大攻击原语.C语言格式函数中的直接参数访问(DPA)特性允许我们指定用于格式标识符的参数索引。例如printf("%2$s%1$s\n","first","second")会打印“secondfirst”,因为第一个字符串格式标识符指定参数2(2$),第二个字符串格式标识符指定参数1(1$)。此外,从攻击者的角度来看,使用DPA可以让您直接偏移到堆栈位置,该位置保存给定%n/%hn写入所需的目标指针值。了解DPA的用途对于回顾历史Perl示例很重要。总结通常,在高级语言的内存管理功能的实现代码中,存在一个相对脆弱的基于C/C++的攻击面。这种问题可能存在于语言本身的核心实现中,也可能存在于将向高级语言提供基于C/C++的库的第三方语言生态系统中。在本文中,我们向读者介绍与此密切相关的C格式字符串漏洞知识。在下一篇文章中,我们将介绍这些底层实现如何影响解释型语言的安全性。