怎 样 寻 找 安 全 漏 洞

怎 样 寻 找 安 全 漏 洞 (转贴自安络科技)
    
描述:
怎 样 寻 找 安 全 漏 洞
  
详细:
备注:我没有找到任何安全漏洞,因此拿这篇文章当作小菜一碟。对于这篇文章有更好的组织和语法建议,我张开双手欢迎。任何错误的报告都是紧急必需的。

如果一个有漏洞的程序在极端的情况下表现出来,那么,正常地,它只是一个小问题。通常,你只须避免这种极端的出现,那么臭虫不是个问题。如果你愿意,通过自己编程,你能复制引起这个臭虫的效果。

但是,有时候,程序处于安全的边缘。它们从某些没有同样权限的程序中读入操作。有些例子:你的邮件阅读器从你的发信人之处读入,这种信通常只对你有权而对其它人不开放。任何连上互联网的电脑的TCP/IP堆栈读取网上所有人的资源。对此而言,网上大部分人都无权如此。

做这此事情的程序必须小心设计。若有任何漏洞,它就有潜在的可能允许其他人(末授权用户)做他们权限之外的事。有这种特征的臭虫、称“漏洞”或更正式一点――“脆弱性”。

下面是一些通常漏洞的分类。

结构方面:
当你写一个软件,你的目标是使用者正确操作时,某事成为可能。当你写一个安全敏感的软件时,你也必须使某事不可能而不管不信任用户如何做。这意味着你的程序的某些部分必须在一个十分广阔的环境中运行正确。

漏洞的改变:
大量的漏洞来自于运行于不同环境下的程序。首先是一个小小的问题,甚至是一个便利,最终变成了一个漏洞。

例如:假设你有一个脚本解释器,它本设计成让你在打印之前预览文档。这不是个安全敏感漏洞。脚本解释器无任何你本身不具有的权力。但是,如果你使用它浏览其它你不认识的甚至是不可信任人的文档。突然,这个脚本解释器变成了一个线程。某些人就能够寄一篇摧毁你文档的东西给你,或者将你方件拷贝于他们能得到的地方。

在大多数UNIX系统的TCP/IP堆栈中,这是问题的根源。它们发展于一个人们相互信任的网络之上,但是现在它们被网上不该信任的用户所得用。

这也是SENDMAIL的问题。在进行审计之前,它一直是个漏洞。

在一个更微妙的层次:当函数不跃过信任边界时,它们十分安全,但稍一越轨,灾难便开始了。函数GETS()是个极好的例子。你使用GETS()控制输入,你只是提供了一个比你预料大一点的缓存。但若偶然地提供过大的输入,这个模式便不会运作它或可能溢出缓存进行编译。

但当数据来自于一个不可信任源时,GETS()能溢出缓存并能导致程序做任何事。冲突是最普遍的结果,但你通常能小心地架构数据使程序以可执行代码运行。

这就给我们带来了――缓冲区溢出漏洞

当你往数组中写入一个字符串并继续写过剩下的数组,重写了那个数组的缓冲区溢出便发生了。

缓冲溢出安全问题在下列环境中能出现:
* 当直接往缓冲直接读入时
* 当从一个大的缓存拷贝入小的缓存时
* 当将其它进程的输入放入一个字符串缓存

记住,当输入是被信任的时候,它不是个安全漏洞,只是一个潜在的威胁而已。

在大多数UNIX环境中,这十分混乱,若数组是函数中的局部变量,那就可能返回地址在堆栈之后。这似乎是一个广被利用的漏洞。在过去的几年里成千上万的这种性质的漏洞被发现。

甚至某些时候其它地方的缓存也能溢出而导致安全漏洞特别是位于、函数指针或被信任信息附近。

举例如下:
* 无任何边界检查的危险函数:strcpy,strlen,strcat,sprintfs,gets;
* 带边界检查的危险函数:strcpy,snprintf,这类中的某些将会忽略写零于字符串的未尾。这导致以后能拷贝其它数据进入。这类数据通常是敏感的或与程序有冲突。Strucat无这个问题,我不清楚sprintf是否存在这个问题,但strcpy一定有。
* strcat的误用,这能导致在数组的未尾写入零字节。
* 安全敏感程序冲突。任何一个冲突 来自一个指针臭虫,并且在生产代码中的指针 臭虫主要来自于缓冲溢出。
* 试图为安全敏感数据程序装入大的输入――在环境变量(若它是不可信的)中,在命令行函数中(若它是不可信的),在他们阅读的不可信文件中,在不可信网络连接之上。
观察冲突,若你能看见,注意冲突地址象你的输入。
* 不正确的边界检查。若边界检查散布于几百、百行代码中,而不是集中在两到三个地方。那么出错的机率极大。一个保险的

解决方案是用边界检查编译所有的安全敏感程序。

我知道的第一个为GCC作的边界工作是由Richard W.M.Jones 和 Paul Kelly 做的,位于:
http://www.doc.ic.ac.uk/~phjk/Bounds checking.html/

Greg McGary(gkm@eng.ascend.com)做了其它工作。发布于http://www.cygnus.com/ml/egcs1998-MAY/0073.html. Ricard Jones 和Herman ten Brugge 做了其它工作。发布在http://cygnus.com/ml/egcs/1998-May/1557.html. Greg 比较了两种方法的不同:http://www.cygnsu.com/ml/egcs/1998-May/0559.html

令人困惑的代理(confused deputies)

当你让一个程序打开一个文件,这个程序请求操作系统打开文件。既然程序用你的权限来运行的。如果你无权打开文件,操作系统会拒绝程序的要求。至此,一切都好。

但你若将一个文件名给了一个安全敏感数据,一个CGI SCRIPT(通用网关接口脚本),一个设置用户证明的程序,任何网络服务器――它不一定会依赖操作系统内建的自动防卫,那是因为它能做一些你无权做的事。例如,在一个WEB服务器中,它能做而你不能做的事也许的、很少但它可能至少读些带私人信息的文件。

多数程序对它们收到的数据作某种检查,经常掉入某些陷阱。
* 它们在一个你能参予的时间内检查它,若一个程序在打开它之前首先stats()或lstat()这个文件,用一种无改写方式打开它,然后fstat()那个打开的FD,再比较看是否你已经得到了那个你stat()过的文件。
* 它们把文件分段来检测,但是是用一种不同的操作系统的方式。对于许多微软系统的WEB服务器而言,这是个问题,操作系统对文件进行精密的分段来找出它实际所参照的文件在。WEB服务器察看文件名来察看你对它的权限。若缺省权限让你亠读一个文件,那么改变这个文件名使WEB服务器认为它是个不同的文件,但操作系统分段此文件到同一个文件,这同样给你读的权限。这是个双重分段问题,我们待会讨论。它也源于开启失败。
* 由于原作者对程序理解的错误,它们用一种带漏洞且复杂的方式检测文件。
* 它们根本不检查它,这非常普遍。
* 它们以一种有漏洞的方式检查。例如,许多老的UNIX服务器让你下载某人公共目录中的任何文件(除非操作系统阻止它们)。但若你对某个人私人文件作了符号链接或硬链接,若WEB服务器有权,你是能下载它们的。

另一个问题是:标准库在环境变量中打开文件,但没有丢掉特权。因此,我们被迫分段文件来看它是否合理。

并且,如果你能设计一个SETUID的程序冲突,你能覆盖一个其它程序所有者能覆盖的文件。(带使用者特权的倾倒核心经常导致使用者能读他在正常情况不能阅读的来自核心文件的数据。)

打开失败: 

大多数安全系统在某些情况下不能做正确的事情。他们以两种方式表现:
他们允许不该允许的事情,这叫打开失败。
他们拒绝他们不该拒绝的事情,这叫关闭失败。

例如,当停电时一个用电力控制关闭的电门锁会不能关闭,导致这个门被容易打开。当solenoidu关闭失败时,一个用弹簧装载插销的锁门系统会不起作用,当solenlid无电时,它是不可能回插的。

cgi脚本通常执行其它程序,把用户命令行上的数据传递给他们。为了避免这个数据被shell作为命令解释执行给其它程序或文件,cgi脚本去掉了像“<”,“|”之类的特殊字符。你能够 通过一系列的被移掉的坏字符来使用这种打开失败方式。这后若你忘了它,那便成为一个漏洞了。你能能过一系列被移掉的“好数据”来使用关闭失败方式。如前所示,又有可能是个被遗忘的陷阱。一个perl 的例子http://www.geek-girl.com/bugtraq/1997/0013.html.

若经常失灵,关闭失败比打开失败更不便。它们也更可能是一个避难之所。

通常,我所见的打开失败的是Mac 各微软的操作系统桌面,若你能在某种程度上利用这个程序,你将取得对电脑的完全控制。相反,若你损坏了UNIX的登录程序,你将不能使用计算机。

资源缺乏:

大多数程序设计都假设有足够的资源可用(见上文结构问题)。很多程序甚至不考虑当没有充分的资源时会发生什么情况,某些时候他们做了不该做的事。

看几个例子:
 *当没有足够的内存和某些配置失败,会从宏和新返回零。
 *若非信任用户用尽系统资源(这可能是一个拒绝服务问题,即使程序处理时不允许入侵。但对多数软件而这种问题非常严重)
 *若程序运行出了fds,将会发生什么问题--open()函数将会返回-1。
*若程序不能fork(),或由于资源困乏它的子程序在启动的时候死亡,将会发生什么情况?

信任不该信任的通道:

若你在一个有非信任用户的以太网上以一种透明方式发送口令,若你创建了个所有人都能改的文件而稍后试图从那个文件读回数据,如果你在tmp下用O_TRUNC但没用O_EXCL创建了一个文件,你信任了一个不该任的中介来做你想做的事。若一个进攻者能颠覆非信任通道,也许他们能够通过改变通道数据来拒绝对你的服务,也许能够在你不知觉的情况下改变数据(这导致非常糟糕的事发生:若攻击者将那个TMP下的文件和一个信任文件建立了链接,你将摧毁这个持权文件的内容而不是只创立了了个临时文件。GCC有一些这种臭 虫,这导致攻击者能将代码插入你编译的文件中。)即使他们不能做这些事情,他们也能读他们不该读的数据。

不合理的缺省值:

明显的但有安全漏洞的缺省值,人们也许会忽略它。例如,你打开一个RPM包并创建了一些人人可写的配置文件除非积极的寻找漏洞,否则你可能不会注意。这意味着解包的大多数人将会在自己的系统上留下漏洞。

大接口:

小的安全接口比大的要安全。这是个常识,若我的房子有一张人们能进入的门,在我上床之前我应该记得锁上它,但若有五张门它们全都通向外部,这就可能我会忘记其中一张了。

因此,网络服务器比SETUID程序更为安全。SETUID程序从各个不信任源取得信息――环境变量,文件描述器,虚拟内存映射,命令行参数,文件输入等。网络服务器只从网络套接字得到输入(也可能是文件输入。)

QMAIL是一个小安全接口的例子。只有一小部分的QMAIL(尽管与我前面提到的LINUX安全审计邮件列单相比,它超过十行)以ROOT方式运行、剩下的以特别QMAIL用户或邮件接受者身份运行。

对于QMAIL内部来说,缓冲溢出检查集中于两个小函数,并且所有用来调节字符串的函数都对这些函数进行检验。另一个小安全接口的例子――检测工作出错的机率微乎其微。

你运行的网络守护程序越多,你和互联网间的安全接口就越大。若你有防火墙,你和互联网间的安全接口便减少到了一台机器上。

浏览非信任的HTML页面各非信任的JAVA脚本页面之间的区别之一是接口大小问题,后者的解释器中的ROUTINES要比前者RENDERER中的地ROUTINES大且复杂。

经常被利用的程序:

这去经常被利用的程序在将来有可能会有漏洞,某些时候应该被替代。基于此因,BSD中的/bin/mail被mail.local所替代。

若你正在审计,对这样的程序作出全面的审计是个非常好的主意,但有时候重写他们或不要把他们用在第一地方更好。

定义不完善的安全组件

一个安全系统被分为安全组件。例如,我的LINUX系统有很多称为使用者的组件,其中一个叫内核,也有的叫网络――它被分为称网络接口的亚组件。这些其于系统组建和授权的组件间有一种定义得非常完善的信任关系。(例如,在我发出一个口令后,我的使用者KRAGEN信任我的网络接口。)

在安全组件接口间的信任关必须被加强。若你正在运行一个库终端,你也许想这个终端只对数据库有读取权。你不想它对UNIX的SHELL能
进行操作。我不能确定怎样完成这个任务,但我确信你能看出我想要表达的。

MIRABILIS ICQ信任整个网络发给它正确的用户标识,显然,这是安全的。

在某一点,TCP_WRAPPERS信任它得自逆向域名解析的数据,把它传给SHELL。(但现在不了)。

当使用SQUID作为一个代理服务器时,网景的探索者浏览器有时会在永久资源列表中插入一个用户键入FTP口令。JAVASCRIPT程序和其它WEB服务器能读这个永久资源列表。

被忽略的例子:

非可信任逻辑语句IF-ELSE和SWETCH-CASE是危险的,因为它很难检测。若你找到一个从末运行过的分支,它就有可能是错误的。若你能找到一个逻辑数据流的结合――例如,若有两个独立行事的例程,第一个的输出是第二个的输入,若给的是四个末经检测的结合体(COMBINATIONS),那就有可留下个漏洞。

检查ESLES和SWETCH句中的缺省值,确保它们不能被关闭(failed-closed)命令gcc –pg –a 会使程序产生一个bb.out文件,那将有助于你在执行所有的分支语句时确定你的检测的有效性。

我相信这就是近来IP拒绝服务问题的根源。

只是一个小小的疏忽:

许多人信任只有少数人阅读过的代码。若代码只是一个被少数人自过的软件,那就可能留下漏洞;若代码是有严格安全要求的,那就可能破坏这种安全。最近的3COM障碍是个极好的例子。他的所有的地COREBUILDER和SUPERSTACK II集线器都被发现有秘密后门口令,它们在一种极端的情况下能被顾客看到。

对LINUX安全审计而言,这不应该是个主要的焦点。

这篇文档的问题:
几个分类大量重复。它末经任何实践而成,因此我对不同问题的侧重点有可能有所偏颇,而且我也许汛、漏写了某些重要的东西。并且,部分内容思想深度不够。但是,我依然认为对那些不是很有LINUX安全统计经验的人而言,这篇文档仍是个很有用的工具。

对那些有兴趣写安全软件的人给的信息提示:

太阳世界在线(SUNWORLD ONLINE)有一篇关于设计安全软件的文章。尽管sun 不是世界最有名的安全公司,这篇文章依然很值一读。
GUGTRAQ每天详细的报道UNIX安全漏洞,geek-girl.com保存了一些可回溯至1993年的方档。这是学习新安全漏洞或寻找旧漏洞的一个非常有用的来源。但它不是个索引安全漏洞的工具书。

ADAM SHOSTACK在http://www.homeport.org/~adam/review.html张贴了一些好的代码浏览指导(被一些公司放在其防火墙上浏览代码)。

COPS带有一个SETUID(7)联机帮助,其中包括找出和预防SETUID程序不安全因素的指导,它发布在 http://www.homeport.org/~adam/setuid.7.html 。

EDS 的John Cochran 指引了我寻找AUSCERT编程列单。
ftp://ftp.auscert.org.au/pub/auscert/paper/secure programming cheklist
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值