缓冲区溢出:使您的软件Software运行起来: 了解有关缓冲区溢出方面的基础知识

  本周专栏包括了最初由 Tom O'Connor(Surety.Com 软件Software工程师)编写些材料

  几十年来缓冲区溢出直引起许多严重安全性问题其中最著名例子是:1988 年因特网蠕虫在 fingerd 中利用缓冲区溢出感染了因特网中数万台机器使得各地服务器管理员都对此极为头痛;请参阅本专栏稍后 参考资料但是缓冲区溢出问题并非已成古老历史据统计仅去年缓冲区溢出就占使 CERT/CC 提出建议所有重大安全性百分的 5十以上(CERT/Coordination Center 是位于匹兹堡“软件Software工程协会”个部门;请参阅 参考资料)并且数据显示这问题正在扩大而不是在缩减;请参阅 “缓冲区溢出: 卷土重来”

  很明显至此您不会认为缓冲区溢出将是过时所以为什么现在仍产生缓冲区溢出这种致命呢?这是引起灾难思路方法总是惊人地简单部分采用语言设计(通常是 C 和 C)再结合员拙劣编写手段就会发生这种大问题尽管象 Java 这样不具备某些令人难以置信异常编程方式、现代“安全”语言避免了缓冲区溢出但这问题缓冲区溢出也会发生在非 C 和 C 语言在任何情况下合理原因通常都证明诸如 C 和 C 等语言使用是正确因此了解它们缺陷就非常重要了

  引起缓冲区溢出问题根本原因是 C(和其后代 C)本质就是非安全没有边界来检查和指针引用也就是开发人员必须检查边界(而这行为往往会被忽视)否则会冒遇到问题风险标准 C 库中还存在许多非安全串操作包括:

  strcpy

  strcat

  sprf

  gets

  出于这些原因对编写苛求安全性代码 C 和 C 员必须自我进行有关缓冲区溢出问题教育最佳防范就是有关这些问题良好教育这就是下面 4个专栏将讨论缓冲区溢出原因本专栏概述了缓冲区溢出问题专栏将涉及防范编程窍门技巧(用 C)并介绍说明为什么某些系统容易出问题以及应如何解决本系列最后两个专栏将检查引擎工作并介绍说明缓冲区溢出攻击在特定体系结构上是如何进行破坏

  什么是缓冲区溢出?

  缓冲区溢出开始于每个都需要些情况:放置位元空间多数计算机都在内存中创建多个地址用于信息存储C 编程语言允许员在运行时在内存两个区别部分(堆栈和堆)中创建存储器通常分配到堆数据是那些 malloc 或新建时获得数据而分配到堆栈数据般包括非静态局部变量和所有按值传递参数大部分其它信息存储在全局静态存储器中(从现在开始我们将在两个专栏中论述它们实质细节)在分配同数据类型相邻块时这块内存区域称为缓冲区

  在写入缓冲区时C 员必须注意存储在缓冲区中数据不能超过它所能容纳缓冲区只能容纳定数量就象个杯子只能盛定量如果放到杯子中水太多多余水就会溢出到别地方相似地如果试图放入缓冲区数据比它能装入要多额外数据就会溢出到别处并且您不希望它到其它地方!

  当写入超过缓冲区边界时这就是所谓“缓冲区溢出”发生缓冲区溢出时会覆盖下个相邻内存块由于 C 语言本质上不安全性所以它允许随意(或者更准确地说是完全出于偶然)溢出缓冲区没有运行时检查来这防止写入超过缓冲区末尾所以员必须在其自己代码中执行这检查否则继续下去会遇到问题

  读取或写入超过缓冲区末尾时会导致许多区别(并且通常是不可预料)行为:1) 执行很奇怪2) 完全失败或者 3) 可以继续而且在执行中没有任何明显区别缓冲区溢出副作用取决于:

  写入数据中有多少超过缓冲区边界

  当缓冲区已满并且溢出时覆盖了哪些数据(如果有话)

  是否试图读取溢出期间被覆盖数据

  哪些数据最终替换被覆盖内存

  存在缓冲区溢出不确定行为使得对它们调试异常棘手最坏情况是:可能正发生缓冲区溢出但根本没有任何副作用迹象因此缓冲区溢出问题常常在标准测试期间是发现不了认识缓冲区溢出重要点是:在发生溢出时会潜在地修改碰巧分配在缓冲区附近任何数据

  为什么缓冲区溢出是安全性问题?

  您可能会想:“有什么大不了点点水溢出根本不会对任何人造成伤害”将我们类推再引深试想水溢出在有许多暴露在外电线工作台上根据水滴溅位置火花会 4处飞散同样地当缓冲区溢出时额外数据会摧残将来可能要访问其它有用数据有时这些其它数据更改会导致安全性问题

  最简单情况就是考虑直接在缓冲区后面内存中分配个布尔标志这个标志决定运行用户是否可以访问专用文件如果有不怀好意用户覆盖缓冲区则会更改标志从而指出攻击者是非法访问专用文件

  缓冲区溢出导致安全性问题个思路方法是通过摧毁堆栈摧毁堆栈是导致个特定编程故障:不仔细使用分配在运行时堆栈上数据缓冲区即局部变量和自变量有效摧毁堆栈所造成后果比上举例中提到改变布尔访问控制标志后果更为严重有创造力攻击者会通过摧毁堆栈利用缓冲区溢出弱点然后运行任何代码这种想法是相当直接:在某处插入些攻击代码(例如 shell 代码)并以将控制传递给攻击代码方式来覆盖堆栈(我们将在缓冲区溢出第 3和第 4专栏中详细讨论堆栈摧毁)

  般地攻击者利用缓冲区溢出得到机器上交互式会话 (shell)如果被利用以较高优先权在运行(如 root 用户或管理员)则攻击者就会在交互式会话中得到该优先权最惊人缓冲区溢出是堆栈摧毁它会在超级用户或 root、shell 中造成后果许多可以利用脚本都能在网络(请参阅 参考资料)上找到它们对特定体系结构上堆栈进行摧毁

  缓冲区溢出: 卷土重来

  根据 David Wagner、Jeffrey Foster、Eric Brewer 和 Alexander Aiken 在今年“网络和分布式系统安全性”会议 (NDSS2000) 上发表篇论文中分析当今被广泛利用薄弱环节中多达百分的 5十都是缓冲区溢出而且该分析指出这比例正随着时间而不断上升由于缓冲区溢出问题近年来在安全性领域中已受到瞩目数据是相当令人灰心由于某些原因开发人员尚未积极推动消除缓冲区溢出这软件Software安全性主要陷阱

  过去十年中 CERT/CC 提出建议弱点数目

  使您<img src='/icons/64401de.gif' />软件Software运行起来: 了解有关缓冲区溢出方面<img src='/icons/64401de.gif' />基础知识

  以上图表中显示了可以直接归为缓冲区溢出弱点数正如数据所显示问题并没有任何好转事实上缓冲区溢出正越来越普遍

  堆溢出和堆栈溢出对比

  堆溢出利用通常比堆栈溢出更困难(虽然存在些成功堆溢出攻击)由于这个原因有些员从来不静态分配缓冲区而是用 malloc 或新建所有东西并相信这样会防止出现溢出问题他们通常是对没有多少人具有利用堆溢出所需专门技术但是动态缓冲区分配本质上并不比其它思路方法更安全不要依靠动态分配所有而遗忘缓冲区溢出问题动态分配并不能根本解决所有问题

  让我们更深入地了解某些缓冲区溢出会造成严重安全性隐患原因许多有趣 UNIX 应用都需要特殊权限来完成它们作业它们可能需要写到具有某些特权位置(如邮件队列目录)或打开个有特权要求网络套接字这样通常是 suid(设置 uid)root也就是即使常规老用户运行该时系统也会按请求将特殊权限扩展给应用从安全性来看无论何时授予特权(即使是临时)都有发生特权扩大潜在可能因此可以说在特权扩大时成功缓冲区溢出攻击发挥到极至许多用得很好 UNIX 应用包括 lpr、xterm 和 eject都被滥用 而在代码 suid 区域中利用缓冲区溢出放弃了 root 权限

  常用破坏技术是在 suid root 中查找缓冲区溢出然后利用缓冲区溢出偷取交互式 shell如果以 root 权限运行时运行了利用脚本则攻击者将得到 root shell利用 root shell攻击者可以执行任何操作包括查看专用数据、删除文件、设置监视站、安装后门(用 root 工具箱)、编辑日志以隐藏痕迹、伪装成其他人、意外地破坏材料等等非常可怕

  同时许多人认为如果他们不运行 suid root他们就不必担心他们代码中安全性问题了不会使得到更高访问级别这种想法部分正确但仍是个危险主张您从不会知道谁将执行您并在 2进制中设置 suid 位当人们无法得到某些东西以正确工作时他们会变得不顾我们已经看到这类情况会导致整个目录不必要地设置 suide root再说这是非常可怕

  也有些软件Software用户根本没有任何特权这意味着任何成功缓冲区溢出攻击都将使他们比原来拥有更多特权通常这样攻击涉及到网络例如外部用户可以利用网络服务器缓冲区溢出可能使攻击者登录到机器产生会话具有运行危及网络服务进程特权这类攻击随时都会发生通常这些服务以 root 权限运行(并且般是利用有特权低端口)即使这样服务不是以 root 权限运行时 旦攻击者得到机器上个交互式 shell通常机器被“占有”只是个时间问题――“占有”即攻击者获得机器完全控制如 UNIX 操作系统上 root 访问权或 Windows NT 操作系统上管理员访问权 这样控制般是通过利用交互式 shell 运行另个利用脚本而扩大特权所获得

  堆溢出和堆栈溢出对比

  堆溢出利用通常比堆栈溢出更困难(虽然存在些成功堆溢出攻击)由于这个原因有些员从来不静态分配缓冲区而是用 malloc 或新建所有东西并相信这样会防止出现溢出问题他们通常是对没有多少人具有利用堆溢出所需专门技术但是动态缓冲区分配本质上并不比其它思路方法更安全不要依靠动态分配所有而遗忘缓冲区溢出问题动态分配并不能根本解决所有问题

  让我们更深入地了解某些缓冲区溢出会造成严重安全性隐患原因许多有趣 UNIX 应用都需要特殊权限来完成它们作业它们可能需要写到具有某些特权位置(如邮件队列目录)或打开个有特权要求网络套接字这样通常是 suid(设置 uid)root也就是即使常规老用户运行该时系统也会按请求将特殊权限扩展给应用从安全性来看无论何时授予特权(即使是临时)都有发生特权扩大潜在可能因此可以说在特权扩大时成功缓冲区溢出攻击发挥到极至许多用得很好 UNIX 应用包括 lpr、xterm 和 eject都被滥用 而在代码 suid 区域中利用缓冲区溢出放弃了 root 权限

  常用破坏技术是在 suid root 中查找缓冲区溢出然后利用缓冲区溢出偷取交互式 shell如果以 root 权限运行时运行了利用脚本则攻击者将得到 root shell利用 root shell攻击者可以执行任何操作包括查看专用数据、删除文件、设置监视站、安装后门(用 root 工具箱)、编辑日志以隐藏痕迹、伪装成其他人、意外地破坏材料等等非常可怕

  同时许多人认为如果他们不运行 suid root他们就不必担心他们代码中安全性问题了不会使得到更高访问级别这种想法部分正确但仍是个危险主张您从不会知道谁将执行您并在 2进制中设置 suid 位当人们无法得到某些东西以正确工作时他们会变得不顾我们已经看到这类情况会导致整个目录不必要地设置 suide root再说这是非常可怕

  也有些软件Software用户根本没有任何特权这意味着任何成功缓冲区溢出攻击都将使他们比原来拥有更多特权通常这样攻击涉及到网络例如外部用户可以利用网络服务器缓冲区溢出可能使攻击者登录到机器产生会话具有运行危及网络服务进程特权这类攻击随时都会发生通常这些服务以 root 权限运行(并且般是利用有特权低端口)即使这样服务不是以 root 权限运行时 旦攻击者得到机器上个交互式 shell通常机器被“占有”只是个时间问题――“占有”即攻击者获得机器完全控制如 UNIX 操作系统上 root 访问权或 Windows NT 操作系统上管理员访问权 这样控制般是通过利用交互式 shell 运行另个利用脚本而扩大特权所获得

  Windows 和 UNIX 对比:晦涩安全性好吗?

  目前我们举所有利用缓冲区溢出举例都是针对 UNIX 系统但是我们不想遗漏 Microsoft Windows!大量缓冲区溢出可能性也存在于 Windows 机器上近来家名为 eEye 公司发现 Microsoft “因特网信息服务系统 (IIS)”有个可利用缓冲区溢出漏洞使大约百分的 9十运行 Windows NT Web 服务器机器完全开放供任何脚本人员“占有”(脚本人员是将来黑客他们知识足够对易攻击机器运行预编码脚本但还没有足够知识创建这样脚本)请参阅第专栏 “使您软件Software运行起来”获取脚本人员详细信息)

  有些人认为在 Windows 中查找缓冲区溢出比在 UNIX 中难确是这样 Windows 往往是不带源代码交付而 UNIX 是带源代码交付当有源代码时就非常容易找到潜在缓冲区溢出(或者更进大多数安全性瑕疵)当可以获得源代码时攻击者会查找所有可疑然后尝试确定哪些是弱点查看该攻击者更容易得出如何利用实际输入导致缓冲区溢出在没有源代码时做这些事就需要有更多窍门技巧(可能还需要有些运气)



  当没有发布源代码而免除安全性问题通常称为“晦涩安全性”但是依靠这种安全性不是个好主意如果代码首先设计有问题技术高超攻击者仍能破坏它更好解决方案是编写可靠代码让其他人知道您所做这样他们可以帮助您找出漏洞从而保证它安全

  许多 Windows 开发人员无论是否知道这仍依靠晦涩安全性模型通常他们不知道这主要是他们在开发他们应用时从未真正考虑到安全性在这种情况下他们盲目地依靠有瑕疵思路方法

  安全性专家通常认为 Windows 代码比 UNIX 代码有更多可利用缓冲区溢出问题推理可以归为“许多人都来关注”现象这个现象是指开放源码软件Software往往能更好地检查因此更安全当然有些警告首先让人们查看您源代码并不能保证会发现其次对于 Windows也有许多开放源码软件Software;而对于 UNIX 机器至少也有许多封闭源码软件Software出于这些原因现象并非和体系结构有关

  结束语

  在本专栏中介绍了缓冲区溢出它始终可能是最糟软件Software安全性问题这里没有提供任何有关如何在您自己中避免这些问题建议而且在此仅提到了堆栈溢出是如何产生实质细节但是幸运是:将在下专栏中论述这些问题



Tags:  缓冲区溢出保护 缓冲区溢出漏洞 缓冲区溢出教程 缓冲区溢出

延伸阅读

最新评论

发表评论