本文已收录至《全国计算机等级考试——信息 安全技术》专栏
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的下访问或破坏系统。
漏洞是硬件、软件、协议在生命周期的各个阶段(设计、实现、运维等过程)中产生的某类问题,这些问题会对系统的安全(机密性、完整性、可用性)产生影响。
漏洞与Bug并不等同,他们之间的关系基本可以描述为:大部分的Bug影响功能性,并不涉及安全性,也就不构成漏洞;大部分的漏洞来源于Bug,但并不是全部,它们之间只是有一个很大的交集。
近几年来漏洞数量依然处在上升趋势,不仅如此,新漏洞从公布到被利用的时间越来越短,黑客对发布的漏洞信息进行分析研究,往往在极短时间内就能成功利用这些漏洞。除了利用已知漏洞,黑客们也善于挖掘并利用一些尚未公布的漏洞,发起病毒攻击,或出售漏洞资料,满足经济目的。因此漏洞的研究值得感兴趣的小伙伴们深度研究,国家信息安全漏洞共享平台(CNVD),对漏洞研究有成果的会员会给予相应奖励。
漏洞是在硬件、软件、协议的具体实现或系统安全策略上存在的缺陷,从而可以使攻击者能够在未授权的情况下访问或破坏系统。即某个程序(包括操作系统)在设计时未考虑周全,当程序遇到一个看似合理,但实际无法处理的问题时,引发的不可预见的错误
它不是安装的时候的结果 也不是永久后的结果而是编程人员的人为因素,在程序编写过程,为实现不可告人的目的,在程序代码的隐蔽处保留后门,受编程人员的能力、经验和当时安全技术所限,在程序中难免会有不足之处,轻则影响程序效率,重则导致非授权用户的权限提升。
缓冲区溢出是软件安全漏洞的主要来源。所谓缓冲区溢出,指的就是代码写入的数据超过了缓冲区的边界,比如向大小10KB的缓冲区写如12KB的数据,那么这个缓冲就溢出了。当然,前向溢出也算溢出,也就是写入的数据写入到了缓冲区的起始边界之前。
缓冲区溢出是一种比较常见的编码错误,特别是在字符串处理过程中。缓冲区造成的危害也是比较多样的。比较轻微的就是程序直接崩溃,除了用户体验也没什么大损失;比较严重的就是错误的写入覆盖了其他敏感数据,造成数据的丢失;最严重的莫过于执行恶意代码,因为数据写入越界,恶意代码可以将原先正常的函数修改为自己的代码,从而获得整个软件的执行权。
栈内的数据溢出
堆内的数据溢出
一款应用往往需要接收各种各样的输入,针对一款iOS应用,主要的输入有读取文件,读取用户输入,读取网络传输数据,或通过URL被启动(URL Schema)。各种类型的输入都有可能是非法的,甚至是恶意的,所以针对所有类型的输入,应用都要进行检验,确保输入的数据是符合程序要求的,合理的,合法的数据。
非法输入可能造成的危害主要有:
输入的数据大于接收缓冲,会造成缓冲溢出
格式化字符串注入,对这些字符串进行处理时,如果不小心会造成程序的崩溃,或某些敏感数据被篡改
URLSchema中的命令为恶意命令,执行了恶意的命令
代码注入,输入的URL或命令中带有脚本、代码等恶意片段
如果一个任务的完成需要几个特定的子任务以特定的顺序完成来完成,那么这个任务就是存在竞争条件这个漏洞的。黑客可以通过修改事件完成的顺序来改变应用的行为。
竞争条件类型的漏洞主要有以下两种:
应用运行的过程中,在某个操作之前,比如写文件,都会检查一下文件是否存在,在检查与真正的写入之间的间隔就是一个可以被利用的Race Condition,恶意软件可以将用户检查的文件替换成自己的文件,这样数据就泄露了。
处理信号的过程中,是随时可以被另一个信号的处理打断的,如果在处理一个信号的过程中另一个信号到来,那么这个过程会被马上中断,这样,系统就会处于一种未知的状态。
进程间通信采用的方法很多,共享内存,管道,油槽等,由于通信管道两端的应用的不同,那么,有可能存在这钟管道被恶意利用的肯能性,也就是说,进程间通信也是软件漏洞的一个来源,当与另一个应用通信的时候,要默认此应用是不安全的,要对通信的内容进行安全方面的验证。
应用对文件进行处理时,若果没有进行进行有效的验证,那么有可能处理的文件已经是被恶意软件修改过的,是不安全的。所以,进行有效的验证是安全处理文件的重要保证。不安全文件操作类型有以几种:
读取或写入一个位于其他应用也拥有读写权限路径下的文件。
对文件信息,例如权限等信息没有进行有效验证便进行处理。
对文件操作的返回结果没有进行有效利用
假定一个拥有本地文件名的文件就是真正的本地文件。
很多情况下,权限控制是安全机制保证的核心,同时也是漏洞的主要来源。每个应用都有与其匹配的权限,应用申请的权限应该物尽其用,不能申请超过自身需求的权限,而很多的软件漏洞就是因为应用申请了超过自身需求的权限,比如root权限,然后被恶意软件利用,也就有了对整个系统执行所有操作的权限。
很多情况下,对权限的申请进行验证是明智的选择,例如输入用户名及密码来提升权限。注意,在采用验证机制时,最好使用系统内置的权限验证方法,而不是自己取实现,这里需要额外提一下,权限控制是操作系统级别的,当硬件设备被控制时,各种权限的控制也就显得无力,这种情况下,数据的加密保护就显现出了其价值。
用户往往是安全保证机制中那薄弱的一环。即使提供再强大的安全保全机制,如果用户安全意识薄弱,同样会出现问题。很简单的例子,比如用户将密码设置的非常复杂,服务器端数据库的安全保证也很周全,黑客完全无法通过技术手段窃取用户密码,可黑客一个伪装客服的电话就完全有可能将用户的密码从用户的口中骗取到。这就是所谓的"社会工程". 在界面,使用习惯上教育,引导用户进行安全的操作,也是软件设计的重中之重。
按照漏洞的形成原因,漏洞大体上可以分为程序逻辑结构漏洞、程序设计错误漏洞、开放式协议造成的漏洞和人为因素造成的漏洞。
按照漏洞被人掌握的情况,漏洞又可以分为已知漏洞、未知漏洞和0day等几种类型。
这种类型的漏洞有可能是编程人员在编写程序时,因为程序的逻辑设计不合理或者错误而造成的程序逻辑漏洞。这种类型的漏洞最典型的要数微软的Windows 2000用户登录的中文输入法漏洞。非授权人员可以通过登录界面的输入法的帮助文件绕过Windows的用户名和密码验证而取的计算机的最高权限。
这种类型的漏洞也有可能是合法的程序用途被黑客利用去做不正当的用途。这种类型的漏洞最典型的就是后面案例中提到的Winrar的自解压功能,程序设计者的本意是为了方便用户的使用,使得没有安装Winrar的用户也可以解压经过这种方式压缩的文件。但是这种功能被黑客用到了不正当的用途上。
这种漏洞用一个比喻可能更容易理解。打一个比方来说,你开了一扇门,在门上开了一个狗洞,专门为了狗方便出入。正常情况下,人应该用钥匙打开锁才能进来。可是有个家伙他发现利用某个窍门人也可以从狗洞进出,那么这个从狗洞进出的方法就可以看着是一个安全漏洞。
还有一种类型的漏洞是编程人员在编写程序时由于技术上的疏忽造成的漏洞。这种类型的漏洞最典型的是缓冲区溢出漏洞,它也是被黑客利用得最多的一种类型的漏洞。
目前,国际互联网的通信采用的是具有开放性的TCP/IP协议。因为TCP/IP协议的最初设计者在设计该通信协议时,只考虑到了协议的实用性,而没有考虑到协议的安全性,所以在TCP/IP协议中存在着很多漏洞。比如说,利用TCP/IP协议的开放和透明性嗅探网络数据包,窃取数据包里面的用户口令和密码信息;TCP协议三次握手的潜在缺陷所导致的DDOS拒绝服务攻击等。
一个系统如果本身设计得很完善,安全性也很高,但管理人员安全意识淡薄,同样的会给系统留下漏洞。譬如说,系统本身非常完备安全,但系统登录所需要的管理 员帐户或口令,可是因为设置过于得简单而被黑客猜解出来了,那么其他的环节再安全也没有丝毫意义;再或者虽然管理员设置了很复杂的密码,可是他把密码写在 一张纸上,并随手扔到废纸篓里,那么也同样有可能造成密码泄露而导致系统被黑客入侵。
已知漏洞是指已经被人们发现,并被人们广为传播的公开漏洞。这种类型的特点是漏洞形成的原因和利用方法已经被众多的安全组织、黑客和黑客组织所掌握。安全组织或厂商按照公布的漏洞形成原因和利用方法,在他们的安全防护产品中或安全服务项目加入针对相应类型漏洞的防护方法。黑客和黑客组织利用公布的漏洞形成 原因,写出专门的具有针对性的漏洞利用程序文件,并能绕过安全防护软件。比如说针对某个IE浏览器版本的IE漏洞利用文件,或者他们干脆利用一些漏洞公布站点上提供的漏洞利用程序文件并不加任何修改地去攻击互联网上的计算机。
产生漏洞的软件的开发商则会针对被公开的漏洞的信息,修补他们开发的程序以供他们的用户修补已经存在漏洞的软件。
未知的漏洞则是指那些已经存在但还没有被人发现的漏洞,这种类型漏洞的特征是虽然它们没有被发现,但它们在客观上已经存在了,它们带给计算机网络安全的是隐蔽的威胁。如果它们哪一天被黑客有意或无意的找出来后就会对计算机网络安全构成巨大的威胁。
所以软件开发商、安全组织、黑客和黑客组织都在努力的发现漏洞,可以说谁先发现了漏洞,谁就可以掌握主动权。如果是软件开发商和安全组织先发现了漏洞,他们就可以在安全防护上取得主动权;如果是黑客或黑客组织先发现了漏洞,他们就可以在攻击上取得主动权。
所谓0day漏洞是指已经被发掘出来,但还没有大范围传播开的漏洞,也就是说,这种类型的漏洞有可能掌握在极少数人的手里。黑客有可能在这种类型的漏洞的信息还没有大范围的传播开的时候,利用这段时间差攻击他们想要攻击的目标机器,因为绝大多数用户还没有获取到相关的漏洞信息,也无从防御,黑客要想得手还是很容易的
由于种种原因,漏洞的存在不可避免,一旦某些较严重的漏洞被攻击者发现,就有可能被其利用,在未授权的情况下访问或破坏计算机系统。先于攻击者发现并及时修补漏洞可有效减少来自网络的威胁。因此主动发掘并分析系统安全漏洞,对网络攻防战具有重要的意义。漏洞的研究主要分为漏洞挖掘与漏洞分析两部分。漏洞挖掘技术是指对未知漏洞的探索,综合应用各种技术和工具,尽可能地找出软件中的潜在漏洞;漏洞分析技术是指对已发现漏洞的细节进行深入分析,为漏洞利用、补救等处理措施作铺垫。
根据分析对象的不同,漏洞挖掘技术可以分为基于源码的漏洞挖掘技术和基于目标代码的漏洞挖掘技术两大类。基于源码的漏洞挖掘的前提是必须能获取源代码,对于一些开源项目,通过分析其公布的源代码,就可能找到存在的漏洞。
例如对Linux系统的漏洞挖掘就可采用这种方法。但大多数的商业软件其源码很难获得,不能从源码的角度进行漏洞挖掘,只能采用基于目标代码的漏洞挖掘技术。对目标码进行分析涉及编译器、指令系统、可执行文件格式等多方面的知识,难度较大。
基于目标代码的漏洞挖掘首先将要分析的二进制目标代码反汇编,得到汇编代码;然后对汇编代码进行切片,即对某些上下文关联密切、有意义的代码进行汇聚,降低其复杂性;最后通过分析功能模块,来判断是否存在漏洞。漏洞挖掘技术从逆向分析的软件测试角度,又可分为白箱分析、黑箱分析和灰箱分析三类
漏洞挖掘是一个多种漏洞挖掘分析技术相互结合、共同使用和优势互补的过程。目前漏洞挖掘分析技术有多种,主要包括手工测试技术(manual testing)、Fuzzing技术、比对和二进制比对技术(Diff and BinDiff)、静态分析技术(static analysis)、动态分析技术(runtime analysis)等。
人工分析是一种灰盒分析技术。针对被分析目标程序,手工构造特殊输入条件,观察输出、目标状态变化等,获得漏洞的分析技术。输入包括有效的和无效的输入,输出包括正常输出和非正常输出。非正常输出是漏洞出现的前提,或者就是目标程序的漏洞。非正常目标状态的变化也是发现漏洞的预兆,是深入挖掘的方向。人工分析高度依赖于分析人员的经验和技巧。人工分析多用于有人机交互界面的目标程序,Web漏洞挖掘中多使用人工分析的方法。
Fuzzing技术是一种基于缺陷注入的自动软件测试技术,它利用黑盒分析技术方法,使用大量半有效的数据作为应用程序的输入,以程序是否出现异常为标志,来发现应用程序中可能存在的安全漏洞。半有效数据是指被测目标程序的必要标识部分和大部分数据是有效的,有意构造的数据部分是无效的,应用程序在处理该数据时就有可能发生错误,可能导致应用程序的崩溃或者触发相应的安全漏洞。根据分析目标的特点,Fuzzing可以分为三类:
1).动态Web页面Fuzzing,针对ASP、PHP、Java、Perl等编写的网页程序,也包括使用这类技术构建的B/S架构应用程序,典型应用软件为HTTP Fuzz;
2).文件格式Fuzzing,针对各种文档格式,典型应用软件为PDF Fuzz;
3).协议Fuzzing,针对网络协议,典型应用软件为针对微软RPC(远程过程调用)的Fuzz。Fuzzer软件输入的构造方法与黑盒测试软件的构造相似,边界值、字符串、文件头、文件尾的附加字符串等均可以作为基本的构造条件。
Fuzzer软件可以用于检测多种安全漏洞,包括缓冲区溢出漏洞、整型溢出漏洞、格式化字符串和特殊字符漏洞、竞争条件和死锁漏洞、SQL注入、跨站脚本、RPC漏洞攻击、文件系统攻击、信息泄露等。与其它技术相比,Fuzzing技术具有思想简单,容易理解、从发现漏洞到漏洞重现容易、不存在误报的优点。
同时它也存在黑盒分析的全部缺点,而且具有不通用、构造测试周期长等问题。常用的Fuzzer软件包括SPIKE Proxy、Peach Fuzzer Framework、Acunetix Web Vulnerability Scanner的HTTP Fuzzer、OWASP JBroFuzz、WebScarab等。
补丁比对技术主要用于黑客或竞争对手找出软件发布者已修正但未尚公开的漏洞,是黑客利用漏洞前经常使用的技术手段。
安全公告或补丁发布说明书中一般不指明漏洞的准确位置和原因,黑客很难仅根据该声明利用漏洞。黑客可以通过比较打补丁前后的二进制文件,确定漏洞的位置,再结合其他漏洞挖掘技术,即可了解漏洞的细节,最后可以得到漏洞利用的攻击代码。简单的比较方法有二进制字节和字符串比较、对目标程序逆向工程后的比较两种。
第一种方法适用于补丁前后有少量变化的比较,常用的于字符串变化、边界值变化等导致漏洞的分析。
第二种方法适用于程序可被反编译,且可根据反编译找到函数参数变化导致漏洞的分析。这两种方法都不适合文件修改较多的情况。复杂的比较方法有Tobb Sabin提出的基于指令相似性的图形化比较和Halvar Flake提出的结构化二进制比较,可以发现文件中一些非结构化的变化,如缓冲区大小的改变,且以图形化的方式进行显示。
常用的补丁比对工具有Beyond Compare、IDACompare、Binary Diffing Suite(EBDS)、BinDiff、NIPC Binary Differ(NBD)。此外大量的高级文字编辑工具也有相似的功能,如Ultra Edit、HexEdit等。这些补丁比对工具软件基于字符串比较或二进制比较技术。
静态分析技术是对被分析目标的源程序进行分析检测,发现程序中存在的安全漏洞或隐患,是一种典型的白盒分析技术。它的方法主要包括静态字符串搜索、上下文搜索。
静态分析过程主要是找到不正确的函数调用及返回状态,特别是可能未进行边界检查或边界检查不正确的函数调用,可能造成缓冲区溢出的函数、外部调用函数、共享内存函数以及函数指针等。对开放源代码的程序,通过检测程序中不符合安全规则的文件结构、命名规则、函数、堆栈指针可以发现程序中存在的安全缺陷。
被分析目标没有附带源程序时,就需要对程序进行逆向工程,获取类似于源代码的逆向工程代码,然后再进行搜索。使用与源代码相似的方法,也可以发现程序中的漏洞,这类静态分析方法叫做反汇编扫描。
由于采用了底层的汇编语言进行漏洞分析,在理论上可以发现所有计算机可运行的漏洞,对于不公开源代码的程序来说往往是最有效的发现安全漏洞的办法。但这种方法也存在很大的局限性,不断扩充的特征库或词典将造成检测的结果集大、误报率高;同时此方法重点是分析代码的"特征",而不关心程序的功能,不会有针对功能及程序结构的分析检查。
动态分析技术起源于软件调试技术,是用调试器作为动态分析工具,但不同于软件调试技术的是它往往处理的是没有源代码的被分析程序,或是被逆向工程过的被分析程序。动态分析需要在调试器中运行目标程序,通过观察执行过程中程序的运行状态、内存使用状况以及寄存器的值等以发现漏洞。
一般分析过程分为代码流分析和数据流分析。代码流分析主要是通过设置断点动态跟踪目标程序代码流,以检测有缺陷的函数调用及其参数。数据流分析是通过构造特殊数据触发潜在错误。比较特殊的,在动态分析过程中可以采用动态代码替换技术,破坏程序运行流程、替换函数入口、函数参数,相当于构造半有效数据,从而找到隐藏在系统中的缺陷。常见的动态分析工具有SoftIce、OllyDbg、WinDbg等