通过限制代码中原语的数量,开发人员可以使黑客利用软件的过程更加困难,从而增加利用成本并降低其可能性。
软件对军队的野战防御和作战支援能力越来越重要。军事和航空航天系统中的嵌入式软件必须既可靠又安全,因为安全漏洞可能与行业开发的许多控制措施来防止的功能缺陷一样危险。
许多用于解决功能或质量缺陷的相同技术也可以减少安全漏洞。在软件开发方面,安全缺陷应被视为软件缺陷,并作为开发过程的一部分进行管理。事实上,安全和质量之间的区别有时可能是微妙的。今天表现为系统故障的缺陷明天可能会被攻击者利用。
缺陷本质上是潜在的利用原语1,黑客可以创造性地将其串在一起进行攻击。开发人员可以通过消除尽可能多的原语来使攻击者利用软件的过程更加困难。下面的示例演示如何将多个基元链接在一起以实现远程代码执行。
多基元攻击示例
假设驻留在远程上的代码中存在安全漏洞。虽然确定根本原因足以修复缺陷,但成功利用该漏洞取决于多个预先存在的条件。对于此示例的上下文,我们假设攻击者尝试实现远程代码执行 (RCE),从而在远程计算机上运行攻击者选择的代码。虽然触发安全漏洞是实现RCE所必需的,但它实际上需要许多小步骤,我们称之为利用原语。通过将这些原语链接在一起,攻击者可以创建一个可靠工作并在漏洞利用结束后保持稳定性的漏洞利用。
在我们的示例中,攻击者使用(但不限于)四个唯一的基元。使用的第一个原语是软泄漏2,它利用合法的程序功能来操作目标应用程序中的内存,而不会对稳定性或安全产生影响。这些基元恰好是最常见的,因为它们依赖于预期的有效程序功能。例如,根据设计,服务器将接受来自客户端的请求。该客户端发送在会话终止发生之前一直保留的信息。漏洞利用编写者可以通过确定这些请求和会话的工作原理,根据特定应用程序的功能对其内存布局做出某些假设。
下一个使用的基元是硬泄漏2。硬泄漏或资源泄漏对于大多数 C/C++ 程序员来说非常熟悉。当程序员忘记释放在运行时动态获取的内存时,就会发生泄漏。虽然大多数程序员认为这是一个质量问题,在最坏的情况下会导致大量内存消耗,但许多开发艺术家认为这是确保漏洞利用稳定性的机会。攻击者可以通过永久获取内存来确保内存的某些部分在进程的整个生存期内永远不会被使用。
使用的第三个基元是整数溢出。如果数学运算尝试存储大于整数可以容纳的数字,则多余的数字将丢失。多余数据的丢失有时称为整数换行。例如,无符号 32 位整数可以保存最大正值。通过将 1 加到该最大正值,整数将在零 (UINT_MAX + 1 == 0) 处再次开始计数。一个真实的例子是汽车在行驶 100 万英里后翻车并从零重新开始里程计数的里程表。攻击者可以通过在分配例程中使用此溢出整数来分配比预期更少的内存。
最后,最后一个使用的基元是缓冲区溢出。这是 C/C++ 程序中最常见的具有安全影响的缺陷类型。当程序写入超过缓冲区末尾时,会导致缓冲区溢出,从而导致相邻内存内容损坏。在某些情况下,这可能会导致覆盖堆栈或堆的内容,从而允许攻击者破坏系统的正常运行,并最终接管程序的控制流。
RCE 中的原始用法
现在,基元类型已经介绍完毕,让我们讨论示例中的攻击者如何利用它们来实现远程代码执行。首先,通过使用现有的程序功能,攻击者发送有效的请求,导致根据其输入的大小分配许多内存块。这似乎无害,但对于实现堆确定性至关重要:将应用程序的内存布局操作到已知的理想状态,这在利用基于堆的缓冲区溢出时是强制性的。接下来,漏洞利用作者知道一些内存一旦分配,就永远不应该再释放。通过利用应用程序中的硬泄漏,可以实现在进程的整个生命周期中保持内存的目标,从而提高开发后的稳定性。
触发了导致未充分分配的堆缓冲区溢出的整数溢出。这会导致分配缓冲区的实际大小与其包含的预期数据元素数不匹配。然后,攻击者可以利用缓冲区溢出来覆盖相邻内存的内容。例如,假设无法确定一张规则纸的最后一行。如果你按顺序继续写句子,你最终会在桌子上写字,并可能写下那件漂亮的新衬衫。通过覆盖相邻内存,攻击者可以用他控制的数据覆盖重要信息。
无论严重性如何,将基元链接在一起的能力都可以更好地控制利用和开发后功能。如果我们的攻击者没有能力在应用程序中创建硬泄漏,他将不得不找出一种不同的方法来确保他的内存在会话超时时不会被释放,或者他至少会意识到最终的程序崩溃是不可避免的。如果整数溢出不存在,我们的攻击者根本没有机会利用。
利用原语和安全漏洞之间的联系可以是直接或间接的。某些类型的基元(如缓冲区溢出)可能导致许多不同类型的漏洞,具体取决于攻击者的技能、创造力和决心。然而,显而易见的是,拥有更多可用的原语使攻击者更容易利用更严重的漏洞并开发破坏性漏洞。因此,在开发过程的早期查找和消除大量利用原语可以极大地帮助减少应用程序服务期间的安全漏洞暴露和维护成本。
保护代码开发的实用方法
开发可靠且安全的软件是 IT 团队面临的一项艰巨挑战,因为将安全测试尽早集成到开发生命周期中的计划尚未得到广泛采用。这并不是说开发人员不想开发安全的产品,而是他们专注于提供新的特性和功能,并且经常面临满足发布截止日期的巨大压力。除了缺乏投资加强安全性的经济激励外,开发人员传统上没有接受过安全专家的培训。计算机科学课程的重点是培养具有成为优秀应用程序开发人员基础的程序员,但不一定是安全专家。因此,今天的开发人员基本上没有意识到他们可以在代码中引入安全问题的无数种方式,并且在发现安全问题时也没有资金来修复它们。
开发测试解决方案需要从开发人员的角度进行设计。这意味着要解决使开发人员回避传统安全评估工具的主要问题:缺乏可用性和高误报率。寻求将安全测试集成到其流程中的开发经理应寻找能够提供以下功能的自动化开发测试工具:
清晰解释缺陷,噪音小:开发人员根本没有时间浪费时间试图筛选嘈杂的结果,或重现实际上不存在的虚幻缺陷。他们需要易于理解且误报尽可能少的缺陷。
在编写代码时及早并经常检测缺陷:确定缺陷的确切原因需要付出大量努力,修复缺陷可能涉及大量的体系结构更改。尽早发现关键缺陷使开发团队能够预测工作负载和对发布计划的影响,从而降低整个项目的成本。
有关如何修复安全缺陷的可操作且正确的建议:作为安全评估的一部分提供的缺陷修正建议通常不会针对软件包中使用的相关框架、语言或库进行自定义。开发人员很难将通用建议转化为有效的修复程序,这通常会导致应用错误或不完整的修复程序,从而导致客户流失和返工。
缺陷是软件开发不可避免的事实。虽然可能无法完全防止在代码开发过程中引入漏洞,但现在存在的技术和流程可以帮助开发人员尽可能快速有效地查找和修复这些缺陷。
审核编辑:郭婷
-
服务器
+关注
关注
12文章
9015浏览量
85169 -
C++
+关注
关注
22文章
2104浏览量
73482 -
代码
+关注
关注
30文章
4742浏览量
68330
发布评论请先 登录
相关推荐
评论