一种基于安全漏洞缺陷模式的检测方法

文档序号:6480334阅读:1127来源:国知局

专利名称::一种基于安全漏洞缺陷模式的检测方法
技术领域
:本发明涉及计算机软件测试技术,尤其涉及一种基于计算机安全漏洞缺陷模式的检测方法。
背景技术
:软件缺陷通常是在软件产品开发过程中产生的,已经影响或可能影响软件产品质量的问题。按照软件缺陷的定义和软件产品的开发过程,软件缺陷通常可分为文档缺陷、代码缺陷、测试缺陷及过程缺陷等类别。这里,所述文档缺陷指对文档的静态检查过程中发现的缺陷,一般可通过测试需求分析、文档审査来发现问题;所述代码缺陷是指对代码进行同行评审、审计或代码检查过程中去发现的缺陷;所述测试缺陷是指由测试执行活动发现的被测对象(被测对象一般是指可运行的代码、系统,不包括静态测试发现的问题)的缺陷,测试活动类型主要包括内部测试、连接测试、系统集成测试、用户验收测试;所述过程缺陷(又称为不符合项问题)是指通过过程审计、过程分析、管理评审、质量评估、质量审核等活动发现的关于过程的缺陷和问题。所述文档缺陷、测试缺陷和过程缺陷大多能够通过规范方法实现预防或避免,而代码缺陷最为常见,也最难预防。当前,软件工程中的有些缺陷或错误,只能通过人工方式的检测来发现;而有些错误,如语法错误可以通过编译器对其进行检测来识别,而像表达式错误则既可通过人工测试,也可以通过自动测试来完成检测。由于人工检测的方式效率较低,目前应用范围较窄;如果釆用自动方式对软件缺陷进行检测,则首先需要对各种软件缺陷进行合理的模式分类,但到目前为止,现有软件测试技术对软件缺陷或软件错误的分类还是比较粗糙的,需要在软件缺陷及缺陷分类、面向某类缺陷的测试方法等方面做进一步的研究。由于软件的复杂性和软件缺陷的复杂性,自软件测试技术诞生以来,尽管有很多科学家在软件缺陷模式方面做了大量研究工作,但收效甚微,这在很大程度上影响了软件测试技术的发展和进步。进入本世纪以来,随着社会对软件测试技术的需求越来越大,软件的质量越来越受到重视,软件的测试理论也得到快速的发展。判断一种软件测试理论是否成熟的重要标志是测试对象是否有比较好的缺陷模式定义,即要求该模式下的故障应该符合实际、在实际软件工程中大量存在、缺陷模式的故障数目可以容忍,并且在该模式下的故障可以通ii观Ji式;^《亍确《。软件安全漏洞是计算机软件缺陷的一种,最常见的安全漏洞通常是指视窗(windows)、Linux等操作系统环境下的系统软件安全漏洞,还包括大量应用软件,如office系列办公软件、IE浏览器、Realplayer播放器、Mediaplayer播放器、网络下载工具和即时通信软件(如MSN、QQ)等常用软件中的安全漏洞;除此之外,还包括公开源代码的自由软件以及带有操作系统的智能终端中的软件的安全漏洞缺陷。软件工程中安全漏洞的存在,可能为他人攻击该软件及计算机系统提供方便,一旦安全漏洞被网络黑客利用后实施攻击,则该系统就可能被攻击方控制、进而导致系统内机密信息遭窃或系统瘫痪等后果,由此造成严重损失。由于开发软件所用计算机语言自身的问题,不同的计算机语言或多或少都存在一定程度的安全漏洞。并且在网络技术快速发展和互联网日益普及的今天,计算机系统已不再是一个个的信息孤岛,大部分的计算机都需要跟外界打交道,而计算机与外界网络沟通的过程中很可能遭到网络攻击。因此,研究一种兼容多种计算机语言的针对软件安全漏洞缺陷的检测技术,提高计算机系统和计算机网络的安全性是非常紧迫的任务。
发明内容有鉴于此,本发明的主要目的在于提供一种基于安全漏洞缺陷模式的检测方法,通过对包括(:/0++/^^等计算机语言中存在的安全漏洞进行检测,降低软件测试的漏报率和误报率,提高测试的准确度,从而提升软件产品的质量。为达到上述目的,本发明的技术方案是这样实现的一种基于安全漏洞缺陷模式的检测方法,该方法包括A、读取被测程序源代码文件及软件安全漏洞模式对应的安全漏洞状态机描述文件,对所述被测程序进行预处理和解析安全漏洞状态机描述文件,并对被测程序进行词法分析和语法分析,生成被测程序的抽象语法树;B、根据所构造的抽象语法树,生成反映被测程序控制结构的控制流图和/或根据所构造的抽象语法树,并创建被测程序的符号表;C、根据所生成的控制流图和所创建的符号表,沿着被测程序控制流正向遍历控制流图;釆用递归调用的方法,进行变量取值区间集的计算与更新;并且根据生成的符号表,对被测程序进行函数调用关系分析,生成函数调用关系图,同时建立ud/du链;D、建立安全漏洞状态机,以函数为单位,根据函数调用关系图对控制流图进行遍历,并根据所述建立的ud/du链对程序代码进行软件漏洞测试,并生成软件漏洞测试报告。其中,所述被测程序源代码文件为Java语言或C/C十+语言。所述软件安全漏洞模式类型包括未验证的输入模式,用于描述一些没有验证的输入,直接作为函数的参数进行调用的;滥用应用程序接口API模式,用于描述那些由调用者错误地信任被调用方所造成的漏洞;安全特性缺陷模式,用于描述有关信息安全所涉及的认证、访问机制、机6密性保障、加密算法、权限管理方面的安全漏洞;竟争条件模式,用于描述分布式计算过程中与时间和状态有关的资源共享方面存在的安全漏洞;不合理的异常处理模式,用于描述与出错处理相关的安全漏洞缺陷;低质量代码模式,用于描述软件质量欠佳所导致的无法预期的安全漏洞;封装不当模式,用于描述函数所涉及的系统变量、系统资源和用户信息进行操作时的安全漏洞。步骤A所述对所述被测程序进行预处理的过程为对被测程序进行测试之前要进行宏替换、文件包含和条件编译。步骤A所述解析安全漏洞状态机描述文件,为利用解析程序将所述安全漏洞状态机描述文件解析成后续处理中,安全漏洞模式分析引擎能够识别的内存数据结构。步骤A所述对被测程序进行词法分析的过程为将被测程序转换为可以进行语法分析的记号流。步骤B所述生成反映被测程序控制结构的控制流图的过程为通过采用访问者模式遍历抽象语法树得到,其方法是在遍历抽象语法树的基础上,由一个控制流图生成访问者实现;所述访问者采用递归下降的办法生成控制流图,在每个抽象语法树中代表语句节点的访问者函数中加入相应产生控制流图的代码;每一个控制语句对应抽象语法树节点的访问者函数负责生成该控制语句的部分控制流图,在遍历的过程中将这些部分控制流图一一连接组织起来就构成了被测程序的控制流图。步骤C所述建立ud/du链的过程为通过对变量的赋值和变量的使用将定义的使用关系存储在ud链中、通过保存当前定义所有可能的使用列表保存在du链中,所述udydu链用于供安全漏洞检测状态机调用。步骤D所述根据所述建立的ud/du链对程序代码进行软件漏洞测试的过程为根据函数调用关系图对控制流图进行遍历,并根据安全漏洞状态机描述文件中关于安全漏洞状态、状态变迁以及引起状态变迁的动作的描述,计算控制流图上每个节点安全漏洞状态机的状态变迁,如果安全漏洞状态机进入软件缺陷状态,则报告对应的检查点IP。所述检査点IP定义了与安全漏洞缺陷相关联的变量的定义代码行、安全漏洞发生的代码行和漏洞的类型。本发明所提供的基于安全漏洞缺陷模式的检测方法,具有以下优点本发明通过对Java语言和C/C+十语言中存在的软件安全漏洞缺陷进行系统的总结,并对所述安全漏洞进行合理的分类并定义为若干类安全漏洞模式,即未验证的输入、滥用API模式、安全特性缺陷模式、竞争条件模式、不合理的异常处理模式、低质量代码模式和封装不当模式;当使用自动软件测试工具,如申请号为CN200810114261.0所述的基于软件缺陷模式的测试系统对待测软件的程序源代码进行测试时,使用本发明方法中的安全漏洞模式所对应的缺陷模式状态机以及建立用于供所述缺陷模式状态机调用的ud/du链,能够快速查询变量的赋值和使用,提高了测试的自动化程度,结合所述合理的安全漏洞模式的分类,能够在测试中降低软件测试的漏报率和误报率,提高软件测试的准确度。图1为本发明基于安全漏洞缺陷模式的测试方法流程示意图。具体实施例方式下面结合附图及本发明的实施例对本发明的方法作进一步详细的说明。本发明的基本思想为首先读取被测程序源代码文件进行预处理,解析软件安全漏洞模式对应的安全漏洞状态机描述文件;再对被测程序代码进行词法分析和语法分析,构造出被测程序的抽象语法树;根据抽象语法树,构造控制流图,生成符号表;然后进行变量取值区间集的计算与更新,并根据符号表、对被测程序进行函数调用关系分析,生成函数调用关系图,再建立ud/du链;最后,通过建立安全漏洞状态机并调用ud/du链,对控制流图进行遍历,计算控制流图上每个节点安全漏洞状态机的状态变迁,如果安全漏洞状态机进入缺陷状态,则报告对应的检查点(IP,InspectivePoint),生成软件安全漏洞测试报告。图1为本发明基于安全漏洞缺陷模式的检测方法流程示意图;如图1所示,该方法包括如下步骤步骤101:读取被测程序源代码文件及软件安全漏洞模式对应的安全漏洞状态机描述文件,对所述被测程序进行预处理和解析安全漏洞状态机描述文件,并对被测程序进行词法分析和语法分析,生成被测程序的抽象语法树。这里,所谓状态机是指一个行为,用于指定一个对象在其整个生命周期中对事件作出响应而先后经历的各种状态,同时表明响应和动作。本发明中将对应于安全漏洞模式的状态机称为安全漏洞状态机,所述每种安全漏洞模式对应一类安全漏洞状态机。所述对被测程序进行的预处理是指对被测程序进行测试之前要进行宏替换、文件包含和条件编译。所述对安全漏洞状态机描述文件进行解析,是利用解析程序将所述安全漏洞状态机描述文件解析成后续处理中安全漏洞模式分析引擎能够识别的内存数据结构。所述词法分析是将被测程序转换为可以进行语法分析的记号流。所述抽象语法树为软件编译技术术语,是指编译器将程序源代码解析,转换为便于计算机处理的数据结构,由于该数据结构通常为树状结构,因此称为抽象语法树。本发明方法中所述的抽象语法树由不同类型的节点组成,所有的节点都支持一个统一的访问者模式接口,这样就能很方便地对抽象语法树通过访问者模式进行进一步的不同形式的加工、遍历访问和输出。步骤102:根据所构造的抽象语法树,生成反映被测程序控制结构的控制流图和/或根据所构造的抽象语法树,创建被测程序的符号表。8这里,所述控制流图可通过采用访问者模式遍历抽象语法树得到,其方法是在遍历抽象语法树的基础上,由一个控制流图生成访问者实现。所述访问者采用递归下降的办法生成控制流图,即在每个抽象语法树中代表语句节点的访问者函数中加入相应产生控制流图的代码。每一个控制语句对应抽象语法树节点的访问者函数负责生成该控制语句的部分控制流图,在遍历的过程中将这些部分控制流图一一连接组织起来就构成了被测程序的控制流图。由于被测程序的控制流图与抽象语法树是相对应的,控制流图的每一个节点对应抽象语法树的语句节点,通过控制流图可以访问抽象语法树,同样的,从抽象语法树的语句节点也可以很方便的访问到控制流图的相应节点。另外,控制流图的每个节点对应被测程序中的一条语句。所述被测程序的符号表,用于记录被测程序标识符的类型、作用域以及绑定信息,并对被测程序进行语义分析。所述符号表的生成与控制流图的生成相类似,也是通过釆用访问者模式遍历抽象语法树得到,只是在每个抽象语法树中代表语句节点的访问者函数中加入的是相应产生符号表的代码。所述符号表将标识符与其类型和在程序中所处的位置进行映射,在处理类型、变量和函数的声明时,这些标识符可以在符号表中得到解释。当发现有标识符被使用时,这些标识符都可以在符号表中找到。步骤103:根据所生成的控制流图和所创建的符号表,沿着被测程序控制流正向遍历控制流图;采用递归调用的方法,进行变量取值区间集的计算与更新;并且根据生成的符号表,对被测程序进行函数调用关系分析,生成函数调用关系图,同时建立ud/du链。这里所采用的区间运算对基本的区间运算进行了扩展,支持区间集运算和实数、布尔变量、句柄变量和数组变量多种数据类型的区间运算,可以对声明语句、赋值语句和条件语句进行区间计算,在对控制流图遍历时,通过区间运算可以大概计算被测程序变量的取值范围,该信息用于后续基于缺陷模式的测试和帮助识别不可达路径。所述对被测程序进行函数调用关系分析包括分析函数在源代码中的位置、函数之间的调用关系以及函数调用的先后顺序和次数等。所述ud/du链即use-def和def-use链,是一种数据流分析方法。这里,对变量的赋值出现称为变量定义,除了定义之外的变量其他出现称为变量使用;定义的使用关系可以存储在use-def链中,即对于每个变量x的每次使用,x的use-def列表保存了所有可以到达当前使用的x的定义;def-use链则保存了当前定义所有可能的使用列表。所述ud/du链的目的是为了供安全漏洞检测状态机调用,用于快速查询变量的赋值和变量的使用,类似的还有def-undef和undef-def链也具有相近的作用。步骤104:建立安全漏洞检测状态机,以函数为单位,根据函数调用关系图对控制流图进行遍历,并根据所述建立的ud/du链对程序代码进行软件漏洞测试,并生成软件漏洞测试报告。这里,所述对被测程序代码进行测试,以函数为单位,根据函数调用关系图对控制流图进行遍历,并根据安全漏洞状态机描述文件中关于安全漏洞状态、状态变迁以及引起状态变迁的动作的描述,计算控制流图上每个节点安全漏洞状态机的状态变迁,如果安全漏洞状态机进入软件缺陷状态,则报告对应的检查点。这里,是利用预先定义的安全漏洞模式分析引擎对控制流图进行遍历,实现对安全漏洞状态机的状态变迁的计算,报告检查点IP。检查点IP定义了与安全漏洞缺陷相关联的变量的定义代码行、安全漏洞发生的代码行和漏洞的类型。对于控制流图上的每个节点,其相应动作改变安全漏洞状态机的状态,如果有安全漏洞状态机进入出错状态(Error),则报告存在一个安全漏洞,当测试结東后根据相应的指标计算方法统计漏报率、误报率、准确率等。下面结合Java、(3化++程序设计语言为例,对本发明的软件安全漏洞模式的分类、定义以及解决方法等分别举例进行描述一、以Java语言为例,该语言存在的缺陷模式种类主要包括A类、未验证的输入;其中包括如下几个类型Al、系统函数暴露以下这些高安全级别的函数,涉及对系统变量或者Java虛拟机(JVM,JavaVirtualMachine)的操作。如果恶意攻击者修改系统参数或者直接对JVM进行搡作,将会导致系统执行不安全的代码,或者拒绝攻击等问题。所述函数举例如下staticStringclearPropertvfStringkey)Removesthesystempropertyindicatedbythespecifiedkey.voidaddShutdownHook(Threadhook)Registersanewvirtual-machineshutdownhook.Processexec(Stringcommand)Executesthespecifiedstringcommandinaseparateprocess.OutputStreamgetLocalizedOutputStream(OutoutStreamout)Deprecated.v4_y<70尺pr^/^fredway/o//^ww/afe"t/w/codec/zan3c&厂W"ea/w/"/oavoidload(Stringfilename)Loadsthespecifiedfilenameasadynamiclibrary.例如:故S名称:HH系统^-—'-一一'-一'一-................publicvoidcheckHost(ServletRequestreq)throwsIOException{StringhostName=req.getParameter("userHostName");Stringcommand="nslookup"'+hostName+Processproc=Runtime.getRuntime().exec(command);〃parseresultsofcommand原因分析通常在应用程序中,由外部命令进行进程的创建或执行将会涉及到安全问题。用户输入作为被执行的命令字符串的任何部分,都将产生严重的威胁。攻击者可以注入额外的命令,并在应用程序服务器上执行从而导致进程或者命令被注入,这种执行任意命令的能力将可能导致拒绝服务、数据恶化、数据安全遭到破坏以及其他风险。A2、系统资源暴露以下这些函数,涉及对系统文件资源的操作,当未验证的输入,作为文件名或文件路径,当被查找或者创建时,将有可能导致系统资源暴露。所述函数举例如下:———File(Fileparent,Stringchild)CreatesanewFileinstancefromaparentabstractpathnameandachildpathnamestring.File(Stringpathname)CreatesanewFileinstancebyconvertingthegivenpathnamestringintoanabstractpathname.intcompBrcTo(Fikpathname)Comparestwoabstractpathnameslexicographically.booleanequals(Objectobj)Teststhisabstractpathnameforequalitywiththegivenobject.String[];list(FilenameFilterfilter)Returnsanarrayofstringsnamingthefilesanddirectoriesinthedirectorydenotedbythisabstractpathnamethatsatisfythespecifiedfilter.bno]eansetLastModified(longtime)Setsthelast-modifiedtimeofthefileordirectorynamedbythisabstractpathname.例如,故障名称未验证的文件名;当未被验证的用户数据被用作创建或修改的文件名的一部分的时候。protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{Stringname=req.getParameter("userName");FileuserDir=newFile("userFiles",name);Fileprofile=newFile(userDir,"profile");if(!profile.exists()){FileOutputStreamstream=newFileOutputStream(profile);createFileWithSensitiveInfomiation(stream);stream.close();原因分析这种情形与数据注入结合,就可以被用作将数据注入到任意文件中,如/etc/passwd。而单独的文件注入可以被攻击者用来创建他们自己所命名的文件或者目录,以便在以后的攻击中使用。譬如,攻击者可以强制应用程序在任意一个可读取的位置创建带有敏感信息的文件。再例如,故障名称未验证的临时文件名或临时目录路径;当未经验证的用户输入作为临时文件名时,导致系统创建一个不允许的文件。这种操作会让系统抛出IOException异常,导致出现类似于Dos(拒绝服务攻击)的攻击现象,或者直接使得系统文件暴露给恶意攻击者。见如下程序代码protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{Stringname=req,getParameter("USERNAME");〃use'userNameasuniqprefixFilefile=File.createTempFile(name,"加p");dumpSensitivelnfoAndRunSomeApp(file);file.delete();再例如,故障名称未验证的文件路径;这类错误发生在当没有验证或者污染的数据被直接用作与系统或者文件读写相关的方法的文件或者路径的名称。攻击者可以使用文件分隔符和相关的路径名称读取那些他们不能访问的文件。见如下程序代码publicStringgetUserProfile(ServletRequestreq)throwsIOException{〃SourceofdataHTTPrequestinservletStringuserName=req.getParameter("userName");〃Profiledirishardcodedintheapplicationpathrelativetoserletsinstallationdir11Stringprofile=System.getProperty("PROFILES—DIR")+File.separator+userName;BufferedReaderreader=newBuffere服eader(newFileReader(profile));Stringline=reader.readLine();reader,close();returnline;原因分析通常,在主机系统上使用应用程序访问与创建文件是与系统安全相关的。如果用户输入未被检查的用作可执行程序中的文件或者路径字符串的一部分时,将存在安全威胁。此时,攻击者可以通过操作文件或者路径对数据进行写操作或者访问主机系统的数据。如,攻击者可以操作一个文件名访问来自于主机的/etc/passwd文件。通常,路径注入可能会危及到主机服务器上的文件系统的安全。A3、数据库信息暴露。这类错误主要是指,未验证的输入作为数据库查询的参数或者直接用作査询语句,将会引起SQL(结构化查询语言)注入攻击,所造成的后果,包括暴露数据库中的数据给攻击者,或者不安全的恶意数据被存储到了数据库中等。例如,故障名称未验证的SQL信息;未验证的数据直接被用作SQL查询,导致数据信息暴露。见如下程序代码publicResultSetgetUserData(ServletRequestreq,Connectioncon)throwsSQLException{〃SourceofdatafromHTTPrequestinservletStringaccountNumber=r叫getParameter("accountNumber,');〃UseofstringdirectlyinSQ^statementStringquery-"SELECT*FROMuser—dataWHEREuserid=,"+accountNumber+"',,;Statementstatement=con.createStatement(ResultSet.TYPE一SCROLL一INSENSITIVE,ResultSetCONCUR一READ—ONLY);ResultSetresults=statement.executeQuery(query);returnresults;分析SQL注入为数据库中的数据带来风险。因为用户输入的内容未经验证即被用在SQL语句中,攻击者可以对任何其想要执行的SQL语句进行注入。这包括对数据的删除、更新和创建等操作。同时,通过利用这些缺陷,也可以重新找到数据库中的敏感数据。如果命令被用来进行验证,这将导致来验证访问的发生。再例如,故障名称数据库存储信息暴露;在数据库中存储了不安全的内容,这类错误发生在把未经证实的用户数据插入到SQL数据库查询中。见如下程序代码publicvoidsetUserLastName(ServletRequestreq,onnectioncon)throwsSQLException{〃SourceofdatafromHTTPrequestinservletStringlastName=req.getParameter("IastName,');intuserld=Integer.parseInt(req.getParameter("userId"));〃Usingpreparedstatements,eveniflastnamecontains'〃like"O'Conner"itwillbeok!〃SafeforSQLinjectionshereStringquery-"UPDATEuserDataINTOlastName-WHEREuserid=,';PreparedStatementstatement=con.prepareStatement(query);statementsetString(l,lastName);statement.setlnt(2,userid);statement.executeUpdate();分析一些恶意的数据,直接被更新到了数据库里面。A4、用户信息修改注入这类错误是指用户信息被不安全的暴露给了攻击者,或者攻击者恶意修改了用户信息。造成的后果包括信息泄露,拒绝服务等。故障名称Session中属性修改和注入。这类错误可能发生在当未被认证的用户数据存储在半信任的存储中,如Session属性。详见如下程序代码protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServetException,IOException{Stringname=req.getParameter("userName");HttpSessionsess=req.getSession();sess.setAttribute("user",name);createPage(resp,sess);privatevoidcreatePage(HttpServletResponseresp,HttpSessionsess)throwsIOException{resp.getOutputStream().println("Hello"+sess.getAttribute("user"));分析Session中的信息来自不安全的输入。同时保存在Session中的信息,在系统中又认为是安全的。这样,当不安全的内容被当作安全信息时,导致信息泄露等一系列的攻击。再例如,故障名称未验证的email信息;这类错误发生在未被检验的用户输入被用作email地址信息或者email的其他部分。详见如下程序代码protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOException{try{〃somebaseworkmessage.setFrom(newInternetAddress("admin@my.company.com"));finalStringemail=req.getParameter("email");Addressaddr=newInternetAddress(email);message.setRecipient(Message.RecipientType.TO,addr);message.setSubject("HelloJavaMail");message.setText("WdcometoJavaMail");〃SendmessageTransport.send(message);}catch(Exceptione){thrownewServletException(e);分析E-mail地址是web应用程序中非常普通的输入域。一些时候,E-mail地址被应用程序用来传递邮件到用户,或者在网站显示邮件地址。这类攻击可以包括,传送带有恶意病毒的邮件或者不停的发送垃圾邮件,导致目标邮箱崩溃等。A5、其他故障名称数组索引溢出。这类错误发生在当非证实的用户输入被用作一个数组的索引或者通过一个方法作为一个数组的索引。见如下程序代码ArrayListmyData=newArrayList();booleanlock=false;protectedsynchronizedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{Stringsind=req.getParameter("secretIndex");finalintindex=Integer,parselnt(sind);if(lock=true)resp,sendError(505,"Tryagain");lock=true;Stringkey=(String)myData.get(index);13lock=false;〃dosomethingwiththekeyhere...resp.getOutputStream().println("Success!"+key);分析如果未被认证的用户输入数据被用作数组的索引,或者通过方法作为一个数组的索引的话,受到攻击可以导致方法抛出ArrayOutOffiounds异常。这可能导致拒绝服务或者利用对象状态来创建一个对攻击者有利的控制流。再例如,故障名称系统日志的暴露;这类错误发生在未被验证的用户将信息写入至ij系统日志文件中。再例如,故障^l称未i证值的http头。这类错误发生当http客户端或数据库来的值未经过验证被方法写到了http头中。再例如,故障名称JS脚本注入;当这类错误发生在运行中时,把外界传入的文本直接作为脚本解释执行。再例如,故障名称printf格式化参数注。这类错误发生使用未检查的字符串作为PrintStream.printf的格式化参数。B类、滥用应用程序接口(API)模式。其中包括如下几个子类型例如故障名称不正确的对象比较;这类错误发生在程序试图比较两个对象的类名,去查看两个类是否相等的情况。见如下程序代码-.publicvoidprivateMethod(Objectobjectl,Objectobject2)if(objectl,getClass().getNaine().equals("anotlierClass")){〃wrong〃doworkbasedontheassumptionwe'redealingwiththerightobject分析当通过名字比较类(class)时,允许了混合搭配的攻击,也就是攻击者利用恶意代码类编写新的代码,并链接到你的程序代码中或者将两个不相关的类链接到一起。不用使用一个对象的equals方法去找到类名,代替的,先找到第一个类带有getClass方法,然后通过加载器找到第二个对象的类。if(objectl.getClass()==object2.getClass()){〃correct〃doworkbasedonthefactthattheobjectsaretheofthesameclass再例如,故障名称不正确的finalize()方法;这里指实现了finalize方法却没有调用superfmalize()。如果一个超类实现器重载了超类fmalizer但是忘记了调用超类finalizer,超类fmalizer将永远不会被调用。这意味着对于超类的资源清除不会执行而导致资源泄漏。再例如,故障名称不安全的DNS查询;这类错误发生在过于相信DNS查找函数的域名或IP地址。由于攻击者可以更改DNS服务器,所以在安全方面不要过于依赖DNS查询。,见如下程序代码Stringip=requestgetRemoteAddr0;InetAddressaddr=InetAddress.getByName(ip);if(addr.getCanonicalHostName().endsWith("trustoe.com"》{trusted=true;分析代码试图通过DNS查询来确定一个入站请求是否来自于信任主机,但如果攻击者能够感染DNS缓存(也称DNS缓存中毒),那么他们就可以取得信任。再例如,故障名称未检查返回值;没有检查方法的返回值,从而造成信息的泄露。再例如,故障名称equals()和hashCode()重载问题;一个类重载equals()和hashCode()中的一个。再例如,故障名称错误实现StateHolder;实现StateHolder接口的类仅实现了saveState()和restoreState()之中的一个。C类、安全特性缺陷模式。其中包括如下几个子类型例如,故障名称硬编码密码问题;这类错误发生在当硬编码,或者硬编码的一部分作为密码或者加密的摘要的时候。见如下程序代码publicstaticvoidmain(String[]args)throwsSQLException{Propertiesinfo=newProperties();info.setProperty("user","root");info.setProperty("password","A6nRSYo一");DriverManager.getConnection("jdbc:mysql:〃localhost:3307",info);分析在源码中直接记录密码是不安全的。首先,这允许其他开发者可读。字符串密码可以轻易的从java字节码中读取,这使得有字节码的用户可以读。同时,如果不升级软件则不可以修改密码。硬编码字符串被用作摘要的一部分可能会给攻击者关于密钥生成的提示,因此攻击者会试图预推密钥。密码应该动态的输入并存储不可再用的摘要,譬如使用md5。如果方面在纯文本中要求密码,存储加密的口令到配置文件中。再例如,故障名称空字符串用作密码问题;这类错误发生在当空的字符串被用在接受密码或者进行保密的方法中时。见如下程序代码publicstaticvoidmain(String[]args)throwsSQLException{Propertiesinfo=newProperties();info,setProperty("iiser","root");info.setProperty("password",',");DriverManager.getConnection("jdbc:mysql:〃localhost:3307",info);}分析空的密码可以很简单的对系统进行攻击。再例如,故障名称明码字符串作为密码的问题;这类错误出现在从未加密的文件存储器或者网络到使用该字符串作为密码的方法进行跟踪。见如下程序段Publicstaticvoidmain(String[]args)throwsSQLException,FileNotFoundException,IOException{Propertiesinfo=newProperties();finalFilelnputStreamst=newFneInputStream("config.ini");info.load(st)jst,close();DriverManager.getConnection("jdbc:inysql:〃localhost:3307",info);}分析如果存储或者网络不是通过外部加密进行保护的,则任何可以进行访问的人都可以获得密码的内容。解决的办法密码应该动态的输入。如果不能这样,则应该将密码存储在不可逆的摘要中,如md5,如果方法需要从纯文本中获取密码,则将加过密的密码存储在配置文件中。再例如,故障名称不安全的随机数问题;这类错误发生在安全要求比较高的情形下,程序却使用了一个不安全的随机数值。见如下程序代码再例如,故障名称未正确处理私密信息问题;这类错误发生在没有正确的处理私密信息的地方,比如将客户密码等重要信息记录在程序的曰志中。D类、竟争条件模式。其中包括如下几个子类型例如,故障名称非原子文件操作;这类错误发生在当非原子文件搡作被使用的时侯,如,进行file,exists()检査后再创建文件。见如下程序代码Filefile二newFile(profilesDir,name+".dat");Stringdata="New";if(file,exists()){data="Existing";}FileOutputStreamst=newFikOutputStream(fHe,true);分析这是典型的时间校对与时间利用的竟争条件(TOCTOU)。在时间检测和时间利用间存在漏洞的窗口,这意味着在使用的状态下,检查的状态可能不再为真。这发生在代码没有被synchronized而且相同的代码被多个线程同时执行的时候。如果其他外部进程利用这种状况,它还有可能在synchronized块中发生,如,若另一个JVM也在运行中,或者存在一个直接的文件系统操作的时候。这将导致特权的扩大化、数据注入、信息泄漏或者数据中断。解决办法有时候,使用语言的本地方法会更好一些,例如,FilecreateNewFile可以将检查和创建作为原子搡作。此外,当文件操作与安全相关的时候,应该使用低等级的文件操作。例如,检查所有已经打开且不能篡改的文件的属性,或者使用文件/目录锁。再例如,故障名称线程间的数据泄漏;Servlet程序的成员域可以允许一个用户看到其它用户的数据。见如下程序代码publicclassGuestBookextendsHttpServlet{StringnameiprotectedvoiddoPost(HttpServletRequestreq,HttpServletResponseres){name=req.getParameter("name");out'println(name+",thanksforvisiting!");分析在Servlet/JSP容器中,一般仅实例化一个Servlet/JSP实例,启动多个该实例的线程来处理请求。而实例变量是所有的线程所共享,所以,实例变量不是线程安全的。E类、不合理的异常处理模式;其中包括如下几个子类型例如,故障名称异常死锁问题;unlock在代码中的位置不当,如果程序在try内部发生异常,则unlock()将无法调用,上了锁之后不释放则会引起死锁,这就需要在finally中显式释放。见如下程序代码voidaction(){Lock1=newReentrantLock();Uock();try{dosomething();}catch(java.lang.Exceptione){thrownewRuntimeException("xxx");}l.unlock();改进方法l.lock();try{}finally{l.unlock();再例如,故障名称异常反馈信息泄漏;在抛出异常时,打印过多关于系统信息。见如下程序代码protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{Stringname=req.getParameter("userName");Filefile=newFiie(System.getProperty("web.root"),name+".dat");try{FileOutputStreamstr=newFileOutputStream(file);str.close();}catch(IOExceptione){thrownewServletException("Cannotopenfile"+file+":"+e.getMessage());再例如,故障名称避免使用printStackTrace方法;e.printStackTmce()通常用来打印异常信息,但是它的存在可能泄漏系统的底层实现细节。F类、低质量代码模式。其中包括如下几个子类型例如,故障名称Web应用程序中的main方法问题;这类错误发生在web应用程序,J2EE应用程序和applets中含有main方法的情形下。见如下程序代码publicvoiddoGet(HttpServletRequestreq,HttpServletResponseres)throwsServletException,IOExceptionpubicStringgetServletInfo(){return"Aservletthatknowsthenameofthepersontowhomit,s"+"sayinghello";privatevoidwork(){〃testsomecodewithinourapplication}〃leavingthisaroundisunwantedonceinproductionpublicstaticvoidmain(String[]args){Example—205ex=newExample一205();〃testthatourcodeisworkingex.work();分析将main方法放到web应用程序中将会导致该程序存在一个简单访问的后门。Web应用中的安全设计趋向于不考虑main方法访问,因此这是一个风险。解决办法是在产品代码中移除所有的main方法。再例如,故障名称创建临时文件但未删除;这类问题发生在当临时文件被创建,而在退出或者在使用完后没有安排删除。见如下程序代码protectedvoiddoPost(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{Filefile=File.createTempFile("aaa",".加p");useFile(file);分析第一个问题是如果一个临时文件包含敏感信息,攻击者可以在应用程序结東后得到对这些信息的访问权。第二个问题是可能会导致一个web应用程序资源耗尽,因为应用程序可能使用光临时文件名或者目录无法保留所有的文件。解决办法临时文件应该在使用之后立刻被删除。至少标记所有的临时文件为deleteOnExk。再例如,故障名称临时文件删除问题;这类错误发生在当临时文件计划在退出时被删除,但是又没有明确的删除。这类缺陷大多数存在于服务器或者servlet的环境中。如果一个文件包含敏感信息,最好尽快的删除。没有被安排删除的临时文件的问题是将被错误跟踪。G类、封装不当模式。其中包括如下几个子类型例如,故障名称返回值泄露;该方法可能在返回与易变对象相关值时泄露内部的表达(EI—EXPOSE—REP)。恶意applet可以通过修改返回结果修改对象的内部状态。见如下程序^码privateArrayListadminUsers;publicCollectiongetAdminUsersOreturnadminUsers;voidmaliciousUserCode()getAdminUsers().add("myself');解决办法这些威胁可以通过不在公共方法中存储可变对象相关内容来防止,可以使用不可变对象代替。再例如,故障名称方法权限设置;这类错误发生在当方法没有定义为私有时。这错误不会在接口和方法重载或被重载时报告。范围解释规则限定了类的可用范围,默认情况下范围是对Applet类的扩展。见如下程序代码publicclassExample—218extendsApplet{privatevoidmethodAO{publicvoidmethodB(){再例如,故障名称内部类系统信息暴露。这类错误发生在存在内部类定义时。见如下程序代码publicclassinnerClsDef{privateStringdata;classMylnnerClass{publicvoidprint(){System.out.println(data);分析Java字节码没有对于内部类的概念。编译器将内部类转换成在同一18包中可以访问所有代码的普通类。这样,即使被声明成私有的,内部类也获得了对封装类的域的访问权。攻击者可以使用内部类来访问其对应的外部类。再例如,故障名称垃圾回收器访问权限异常;垃圾回收器应该是protected,不是public。二、针对(70++语言,具体的安全漏洞缺陷模式包括如下类别A类、未验证的输入。其中包括如下几个子类型Al、缓冲区溢出如果程序员想要向缓冲区中存储的数据比缓冲区所能存储的数据量还要大时,就要发生BufferOverflow错误。这些额外的数据将被存储到相邻的内存单元中,这将损坏系统原来存储在这里的数据,虽然BufferOverflow导致系统错误的发生是偶然的。但是它是软件安全问题中最常见的问题了。在利用BufferOverflow攻击时,这些额外的数据可能包含一些恶意代码,它可能会破坏用户文件、改写数据或者窃取用户的隐私。之所以能够利用缓冲区溢出进行攻击,是因为很多(^化++的程序语言结构不能自动的进行范围检查,并且许多程序员对这个问题也没有给予足够的重视。其主要包括以下内容Al.l、故障名称输入函数导致溢出。07。++语言中有些输入函数,在从外界读取内容的时候,没有限定读入数据的长度。当读入的数据长度超过分配的内存限制,将会导致系统内存数据被破坏,程序崩溃或者执行恶意代码等问题。这类函数主要有号函数名或操作符函数功能威胁1cin从流中读取字符串cin函数直接从数据流中读取数据,完全忽略了数据长度检测gels(char[])从流中取一字符串同cin,没有对读入的数据行进长度检测3getenv(char*envvar);从环境中取字^:串同cta,没有对读入的数据行进长度检测4LoadString(HINSTANCEinstance,UINTuID,LPTSTR1pBuffer,intnBufferMax)从一个宇符源中读取数据,并且分配到缓冲区中同cin,没有对读入的数据行进长度检测read(inthandle,void*buf,intnbyte);从文件中读去nbyte长度的字符虽然在nbyte上面对读入的长度数据长度进行T控制,但是nbyte会超过siring的长度6fgets(char*string,intn,FILE*stream);从流中读取一字符串同readscanf(char*format[,argument,...])执行格式化输入同cin,对于读入的数据的长度没有进行检测8gettext(intleft,inttop,intright,intbottom,void*destin)将文本方式屏幕上的文本拷贝到存储区同cin9fread(char*,intnuml,intnum2,FILE*fp)文件读操作同read例如,见如下程序代码:charbuftBUFSIZE];cinbuf;分析cin没有对buf的长度和读入数据的长度进行检测,当读入数据的长度超过buf的BUFSIZE时,将会导致内存泄漏。解决的方法是使用带有检测函数或对读入长度限制的库函数来取代这些函数。A1.2、故障名称输入变量导致缓冲区溢出。如果数据是从外部传进来的,19而且在使用之前也没有进行检测,那么,这是个错误.这样的变量主要有argv[],optarg,env[]。同时,如果一个变量传入到一个公有函数中,或者一个全局变量(不知道声明在何处)被公有函数使用,并且没有对变量合法性的进行检查。A13、故障名称字符串操作导致缓冲越界。在(:(++语言中,有些字符串操作函数是通过源数据大小制定缓冲区边界而不是根据目标分配的缓冲区大小进行操作。这样,当源数据的大小超过目标数据分配的大小时,将会导致缓冲区溢出。这类函数有<table>tableseeoriginaldocumentpage20</column></row><table>intmain()chara间;charb[100];strcpy(a,b);分析sizeof(b)>sizeof(a),所以将b的内容拷贝到a的缓冲区的时候发生内存溢出错误。A1.4、故障名称内存操作函数导致的内存溢出。在0++语言中,一部分函数可以直接对内存区域进行操作,当被操作的内存的大小没被监控时,可能会发生内存溢出。如下表所示的函数<table>tableseeoriginaldocumentpage20</column></row><table>例如memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的敲据长度,如chara[100],b[50];memcpy(b,a,sizeof(b));注意若用sizeof(a),会造成b的内存地址溢出。A1.5、故障名称不正确的字符串结東符位置。不正确的字符串结東符号位置,将会使得字符串非正常结東,如果这个字符串结東符的位置长度超过字符串分配的缓冲区长度,发生溢出。见如下程序代码voidreceive(intsocket){charbuftMAX];intnbytes=recv(socket,buf,sizeof(buf),0);buf[nbytes]=分析nbyte的长度大于max的话,由于在nbyte上设置'\0,将会使得buf的长度超过已经分配的max长度。导致缓冲区溢出的问题。A1.6、故障名称符号数为负值时的比较条件。当从外界读入一个有符号数据的数值的时候,因为读入的数据有可能超过有符号数据的最大正数表示范围,导致此数的实际值是一个负数值。见如下程序代码voidTypeConvert(){charinput[MAX];charoutput[MAX];fillBuffer(input);intlen=getI叩utLength();if(len<=MAX){memcpy(output,input,len);分析当len为一个负值时,len<=MAX的判断条件成立,导致memcpy函数发生缓冲区溢出错误。A1.7、故障名称整数溢出。整数的表示范围有限,当从外界读入的数据被赋值给系统中的整数的时候,如果超过整数的取值范围,导致整数溢出。溢出的变量在使用时,可能导致整个系统出现问题。见如下程序代码char*processNext(char*strm){charbuf[512];shortlen=*(short"strm;strm+=sizeof(len);if(len<=512){memcpy(buf,strm,len);process(buf);returnstrm+len;}else{return-1^原因分析当strm为一个负数的时候,发生溢出,导致系统崩溃。A1.8、故障名称数组越界,即数组越界访问。见如下程序代码charRead(){charbuf[5];return0+buf[O]+buf[l]+buf[2]+buf[3]+buf[4]+buf[5];分析buf!5]越界。A2、轻量目录访问协议(LDAP,LightweightDirectoryAccessProtocol)21攻击。所述LDAP是一种基于客户机/服务器模式的目录服务访问协议,LDAP也是一种特殊的数据库。当LDAP内容被恶意更改的时候,相当于数据信息被更改,可能会给攻击者使用的用户名赋予不恰当的权限,导致信息泄漏;可能会使得系统内容被恶意更改;可能会得到不正确的数据,最终可能导致系统的崩溃。A2.1、故障名称LDAP查询信息恶意更改。当未被验证的用户数据被用作创建LDAP过滤器的时候,将会导致攻击者恶意修改LDAP信息。见如下程序代码fgets(manager,sizeof(manager),socket);snprintf(filter,sizeof(filter,"(manager=%s)",manager);if((rc=ldap—search—ext—s(ld,FIND_DN,LDAP—SCOPE—BASE,filter,null,0,sjull,nul[,ldap—n5—limit:LDAP—NO—LIMIT,&result))==.LDXp_§"UCCESS){..}_分析当通过manage关键词査找信息,并对查找结果进行修改的时候,由于manager已经被恶意篡改,故得到的结果为非想得到的结果。导致错误的查找和数据修改。A2.2、故障名称LDAP操纵。当作为查询的LDAP查询语句含有用户输入的恶意数据时,将会得到错误的返回结果。见如下程序代码rc=ldap—simple—bind—s(ld,NULL,NULL);if(rc!=LDAf—SUCCESSH■fgets(dn,sizeof(dn),socket);if((rc=ldap—search—ext—s(ld,dn,LDAP—SCOPE—BASE,filter:&resi7lt■))!=LDAP—SUCCESS){分析dn作为变量传递到了LDAP的查询语句。A3、SQL攻击。例如,故障名称SQL注入。类似于LDAP,当未验证的用户输入用于SQL的査询语句的时候,将会导致得到错误的查询结果。见如下程序代码ctx.getAuthUserName(&userName);{CStringquery二"SELECT*FROMitemsWHEREowner='"+userName+"'ANDitemn識e='"+request丄ookup("itetn")+',",;dbms.ExecuteSQL(query);分析userName被恶意的更改。A4、未验证的输入用于文件。例如,故障名称变量被用做文件名。如果数据未经有效性检查就被作为文件名使用,那么把它归为Defect。file*configf=NULL;char*config=getenv("CONFIG—FILE");if(config!=NULL){—configf=fopen(config,"r");.■在本例中,认为因Defect是来自函数getenv()的数据,没有经过有效的检查,就被作为一个文件名应用到了函数fopen()中,这样黑客会很容易读到受保护的文件。A5、未验证的输入用于系统级别函数A5.1、故障名称系统设置恶意修改。当外界读入的信息被用于系统级别的函数时,将会导致系统设置被恶意修改。这些函数一般多为linux下使用函数,类似的函数主要有名称功能名称功能getdtablesize进程所能打开的最大文件数getpid获取进程标识号getpgid获取指定进程组标识号getppid获取父进程标识号setpgid设置指定进程组标志号getpriority获取调度优先级getpgrp获取当前进程组标识号setpriority设置调度优先级setpgrp设置当前进程组标志号举例sethostid(argv[l])。由于sethostid是涉及到系统级别的函数,当用argv[l]做参数的时候,可能使得系统信息被恶意篡改。A5.2、故障名称系统资源恶意修改。当外界读入的信息被用于系统级别的函数时,将会导致系统资源被恶意修改。见如下程序代码char*rPort=getenv("rPort");serv_addr.sin—port=htons(atoi(rPort));if(connect(sockfd,&servaddr,sizeof(serv—addr))<0)error("ERRORconnecting");分析因系统资源被修改,使得系统中一个port被恶意打开。A5.3、故障名称不正确的库函数加载。当加载的库函数没有被制定绝对路径,可能会被攻击者恶意的加载一个其他的同名的库函数。这类函数有编号函数调用名编号函数调用名1LoadLibrary15ReplaceFile2LoadLibraryEx16SearchPath3AfxLoadLibrary17SetFileSecurity4CopyFile18DecryptFile5CopyFileEx19DuplicateEncryptionlnfoFile6CreateDirectory20EnctyptFile7CreateDirectoryEx21EncryptionDisableSCreateFile■22FileEncryptionStatus9DeleteFile23OpenEncryptedFileRaw10MoveFile24QueryRecoveryAgentsOnEncryptedFile11MoveFileEx25■CJueryUsersOnEncryptedFile12MoveFileWithProgress26RemoveUsersFromEncryptedFile13OpenFile27GetExpandedName14RemoveDirectory28LZOpenFile若用LoadLibrary("liberty.dll");则会因为liberty.dll没有指定路径。攻击者可以加载一个恶意的liberty.dll。A6、其他。A6,l、故障名称拒绝服务。当未验证的用户输入用于线程控制函数时,将会导致线程死锁,Dos攻击。见如下程序代码unsignedintusrSleepTime=uatoi(usrl叩ut);sleep(usrSleepTime);分析让用户输入一个线程sleep的时间,如果usrSleepTime过大,线程将会始终停留在睡眠状态,拒绝服务。A6.2、故障名称诱骗安全风险。使用了一些系统调用,如gethostbyaddr,gethostbyname,sethostname,会带来安全风险。因为这类方法取决于远程服务器的数据,有可能是虛假的信息。见如下程序代码#include〈netdb'h〉externinth一errno;structhostent*myGethostbyname(constchar*name)returngethostbyname(name);分析name是由用户输入的信息,当name是系统管理员或者其他关键人物用户名时,将会泄漏出系统信息。因此,需要检査各种情况下的代码,包括不可信的用户输入。A6.3、故障名称使用不可靠的SHELL命令。系统执行SHELL明令时使用命令行字符串作为参数,一个用户可以注入该字符串执行任意代码。B、滥用API模式。主要包括以下内容Bl、故障名称不恰当的chroot()系统调用。不恰当的chroot()系统调用会使攻击者逃脱chroot的约束。见如下程序代码chroot(7var/ftproot");fgets(filename,sizeof(fikname),network);localfile二fopen(filename,"r");while((len=fread(buf,1,sizeof(buf),localfile))!=EOF){fwrite(buf,1,sizeof(buf),network);fclose(localfile);分析此代码可以用来执行的FTP的GET命令。FTP服务器在其初始化例行程序时调用chroot()以试图阻止在/var/ftproot外访问文件。但由于服务器没有通过调用chdir('V")来改变当前的工作目录,因此攻击者可以请求文件"../../../../../etc/password",并取得该系统的密码文件的一份拷贝。B2、故障名称未清除堆的内存释放。使用realloc()、fork()、vfork()来调整缓冲区大小来存贮敏感信息将可能导致敏感信息暴露给攻击者,因为它没被清除出内存。解决办法在程序中识别关键数据并检查其使用情况。在使用完这些函数后,立即销毁临时缓冲区中的数据。见如下程序代码cleartext一buffer=get—secret();cleartext一buffer=realloc(cleartext一buffer,1024》scrub_memory(cleartext—buffer,1024);分析—代码试图将i感数据从内存中清除,但realloc()被使用,该函数常用来增加已分配内存块的大小。这个搡作往往需要将旧的内存块的内容复制到一个新的和更大的内存块。原来的内存块仍然完整的存在,因此数据的拷贝仍旧存留在起初分配给cleartext_buffer的内存中。B3、故障名称不安全6fDNS查询。这类错误发生在过于相信DNS查找函数的域名或IP地址。因为攻击者可以更改DNS服务器,所以在安全方面不要过于DNS查询。见如下程序代码structhostent*hpjstructin—addrmyaddr;char*tHost="trustme.trusty.com";myaddr.s—addr=inet—addr(ip—addr—string);hp=gethostbyaddr((char"&myaddr,sizeof(structin_addr),AFJNET);if(hp&&!strncmp(hp->h—name,tHost,sizeof(tHost))){trusted=true;}else{trusted=false;分析该代码想通过DNS查询来确定一个入站请求是否来自于信任主机,但如果攻击者能够感染DNS缓存(也称DNS缓存中毒),那么他们就可以取得信任。B4、故障名称socket绑定问题。不能确保没有socket在同一端口已经被绑定到INADDR—ANY中特定的地址上,网络服务中的包可能被偷或是欺骗。在大多数系统中,设置SO—REUSEADDR的socket选项,调用bind()方法都允许任何处理使用INADDR一ANY来绑定到一个之前处理已经绑定的端口,这就允许用户在一个无特权的端口上绑定到一个服务器的特殊地址上,偷走它的udp包或者tcp连接。见如下程序代码#include<sys/types.h>#indude<sys/socket.h>#include<netinet/in.h>^include<unistd.h>#include<stdio.h>#include<arpa/inet.h>voidbind—socket(void){intserversockfdjintserver一lenjstructsocKaddr一inserver—address;unlink("server—socket");server—sockfd:socketAF—TNET,SOCK—STREAM,0);server_address.sin_family=AF一INET;server—address.sin_port=21;server一address.sin—addr.s—addr=htonl(INADDR—ANY);server一len=sizeof(structsockaddr一in);bmd(server一sockfd,(structsockaddr*)&sl,server一len);}一一解决办法把服务器的socket地址限制到已知的局部的地址。B5、故障名称命名管道的脆弱性。调用操纵资源的函数而未对其返回结果进行判断,忽略资源分配函数的返回值会导致对已有共享资源的重用,会赋予用户更高的搡作权限而给系统带来风险。这种类型的故障通常发生在下面两种情况第一种,使用时调用了CreateNamedPipe,没有检查是否返回了INVALID—HANDLE—VALUE;也没有调用GetLastError检查是否返回了ERROR—ACCESS—DENIED。第二种,使用时调用了CreateMutex,没有检查是否返了NULL;也没有调用GetLastError检查是否返回了ERRORALREADY—EXISTS。C、安区特性缺陷模式;主要包括以下几种类型Cl、故障名称不可靠的进程创建。本地权限扩大的暴露,一些系统创建进程的调用会允许恶意代码的执行,包括下列系统调用:<table>tableseeoriginaldocumentpage26</column></row><table>举例,见如下程序代码〃SV.BRM.CONSTLONGfoo(HKEYhkey,LPCTSTRlpSubKey,DWORDulOptions,PHKEYphkResult){returnRegOpenKeyEx(hkey,lpSubKey,ulOptions,KEY—ALL—ACCESS,phkResult);}—一解决办法使用需要的最少权限。C3、故障名称使用不可靠的注册。使用HKEY—LOCAL一MACHINE作为参数注册,会违背最少权限原则,导致低权限者拥^管理者辰限。或者使用变量作为这些函数的参数,都可能导致安全故障的发生。C4、故障名称不可靠的密码。使用不可靠的密码,容易被破解时,会报此类错误。C5、故障名称明文密码。这类错误出现在密码被存储在应用程序的配置文件或其它数据存储空间的明文里,存储密码在明文里面会危及系统的安全。见如下程序代码RegQ呵ValueEx(hkey,TEXT(.SQLP戰),NULL,NULL,(LPBYTE)pwd,&size);rc=SQLConnect(*hdbc,server,SQL—NTS,uid,SQL—NTS,pwd,§"QL—NTS);分析:'这段代码从注册表中读取密码并访问数据库。它可以很好的运行,但是任何人,如果他能访问存储密码的注册表,那他就能读取密码值。如果一个不诚实的雇员访问了这些信息,他就有可能侵入系统。解决办法密码应该动态的输入。如果不能这样,则应该将密码存储在不可逆的摘要中,例如md5。如果方法需要从纯文本中获取密码,则将加过密的密码存储在配置文件中。C6、故障名称硬编码密码。这类错误发生在当硬编码,或者硬编码的一部分作为密码的时候。硬编码密码可能会危及系统的安全,这种危害不容易被补救。C7、故障名称不安全的随机数。使用不可靠的随机函数所产生的随机行为或数据不能达到应有的效果比如,黑客可能会猜到你的程序下一步将会如何执行或者将使用什么数据。最不可靠的随机函数是srand()和rand(),并且还有很多很不可靠的函数不能用,如,rand48()、random()、srandom()、setstate()、initstate()和srand48(),及其他所有的tand48()函数。见如下程序代码char*CreateReceiptURL(){intnumjtime—ttl;char*URL=(char*)malloc(MAX—URL);if(URL){_(void)time(&tl);srand48((long)tl);/*usetimetosetseed*/sprintf(URL,"%s0/od0/0s","http:〃test.com/",lrand48(),".html");returnURL;分析这段代码用srand48()这个函数,来产生接受的页面里的"唯一"的标识。因为这个函数是个统计伪随机数发生器,所以它产生的字符很容易被攻击者猜出来。C8、故障名称不安全的权限提升.权限提升的暴露会导致危险的功能。一些函数需要特殊的权限来执行,在某些情况下,这些函数只能被特定的用户或者群组来执行。最常见的需要是用户应该是本地的管理员。其他函数需要用户的账户拥有特珠的权限。大部分程序需要权限或者特殊账户来获取对超级用户才能访问的系统资源的访问。见如下程序代码#indude<unistd.h>#include<sys/types.h>intCheckPoorEncryption(void){uid—tmyid=getuid();somecodesetuid(O);/*■■codethatneedstoberunathighprivilege..*/return0;分析在执行一个更高权限的操作时,需要使用setuid提升权限,这允许一个普通用户拥有root权限。在setuid中常见的可能导致的安全漏洞有未声明的或暗示的假设;数字或缓冲的溢出;改变或者删餘文件;引用子进程等等。C9、故障名称显式提高用户权限。一些函数的正确执行需要用户具有一定的权限,因此在在设置较高权限时应谨慎。在程序中,如果要降低某用户的权限,保证先改变其群组标识,再改变用户标识。因为如果先改变用户标识,程序就不再有高级用户的权限来设置群组标识。C10、故障名称忽略检查函数的返回值。一些系统函数的返回值表明了此次操作成功与否,因此在调用这些函数时必须对其返回值进行检查,否则将削弱这些系统函数的功能。比如,可能会使得应用获得比实际更高的优先级而给系统带来风险。D、竞争条件模式主要包括以下内容Dl、故障名称时间检查与时间使用产生的竟争条件(TOCTOU)。这类错误的竞争条件产生的原因是一个给定的资源的在时间检测和时间利用间存在安全漏洞的窗口,这意味着在使用的状态下,检查的状态可能不再为真。对于文件名称的一些操作函数会导致"TOCTOU",这些函数主要有编号名称功能编号名称功能1acct12■chgrp2access'13creat3chmod14opsn4lchown15pathconf5chown16opendir6fopen17lstat7fdopen18stat8freopen19renam69fchmod20link10fchown■21■lchown11chdir2228举例,见如下程序代码do{if(iterator->dir==NUIX){iterator->dir=opendir(iterator->bucket—name);if(iterator->dir==NULL){—switch(errno){caseENOENT:{break;case0:{structstatdirstat;if(stat(iterator->bucket—name,&dirstat)==0){break;分析程序员设计的是采用叩endir()和stat()同时操作于同一个文件,但是黑客可能会以极快的速度移走该文件,从而导致这两个操作不能按程序员设计的那样作用于同一个文件上。解决办法避免使用上述将文件名称作为参数的系统函数,采用文件句柄或文件描述符,因为一旦系统给文件句柄和描述:符赋值,文件就不像字符链接式的文件名那样容易改变。D2、故障名称信号处理不当。为多个不同的信号建立一样的信号处理器,如果不同的信号在短期内同时到达将会导致竟态条件。D3、故障名称状态同步故障。状态同步是指一组缺陷,其中涉及在执行一个进程中的矛盾对立状态,它会导致一些未定义的行为。D4、故障名称access()与remove()之间的竟争。下面的例子展示的是access()和remove()之间造成的竟态条件,很明显这两个操作在同一个函数中,并且用的是同一个全路径。voidremove—if_possible(char*filename){if(access(filename,O))remove(filename);D5、故障名称opendir()与access()之间的竞争。程序员设计的是采用opendir()和stat()同时操作于同一个文件,但是黑客可能会以极快的速度移走该文件,从而导致这两个操作不能按程序员设计的那样作用于同一个文件上。见如下程序代码do{if(itemtor->dir==NULL){iterator->dir=opendir(iterator->bucket—name);if(iterator->dir==NULL){一switch(errno){caseENOENT:{break;case0:{structstatdirstat;if(stat(iterator->bucket—name,&dirstat)==0){break;29F、低质量代码模式;主要包括以下类型Fl、故障名称可预测的临时文件名。有些临时文件名是很危险的,因为这样可能会让黑客提前猜到它们的名字,从而导致黑客可以访问专用数据。黑客或者制造一个同名的假文件,让程序读取,或者黑客通过可以读取这些文件,从而看到程序的相关信息。见如下程序代码staticbooldo一edit(constchar*filename_arg,EBufbuf){一一charf画e加p[MAXPGPATH;[;FILE*stream=NULL;constchar*fname;boolerror=false;intfd;if(filename—arg)fname=filenamearg;elseGetTempFileName(".","psql",0,fnametmp);^"defectfname=(constchar*)foametmp;fd=open(fname,O—WRONLY|O一CREAT|O一EXCL,0600);if(fd!=-1)stream=fdopen(fd,"w");分析GetTempFileName()的第三个参数必须是一个随机数,否则生成的临时文件名就是可预测的。在下面的例子中,第三个参数是O,所以,这个IP是defect。F2、故障名称暴露绝对路径。文件操作函数使用绝对路径会泄露重要数据。见如下程序代码intmain(intargc,char*argv[])intfh;fh=creat("/usr/bin/ls",—S—IREAD|_S—IWRITE);if(fh==-1)—__—return-1;elsewrite(fh,argv[l],sizeof(argv[l]))dose(fh);return0;解决办法检查文件名操作。F3、故障名称堆栈变量地址返回。函数返回了堆栈变量的地址,这将造成意想不到的程序行为,比如程序崩溃。见如下程序代码char*getName(){charname[STR一MAX];fillInName(naine);returnname;原因分析因为局部变量是分配在堆栈上,当一个程序返回一个指向局部变量的指针时,它返回的是堆栈的地址。随后的函数调用是有可能重新使用此30相同的堆栈地址,从而覆盖的指针的值,使其不再对应到相同的变量。在许多情况下,它会导致程序崩溃。F4、故障名称重复释放。这个错误发生在已经释放的内存被再次释放。在某些情况下,这个错误可能导致缓冲区溢出。F5、故障名称释放资源使用。使用已释放的资源会使程序崩溃。见如下程序代码char*ptr=(cha")malloc(SIZE);if(err){abrt=1;free(ptr);if(abrt){logError("operationabortedbeforecommit",ptr);分析该例中指针变量ptr已经被释放,而后面的函数logError()却仍在使用它。F6、故障名称变量未初始化。代码使用了未初始化的变量,将会导致一个不可预测的结果。F7、故障名称符号数与无符号数转换。函数声明返回一个无符号数,但实际上却返回了一个有符号值。见如下程序代码unsignedintreaddata(){intamount=0;if(result=ERROR)amount=-1^returnamount;分析有符号数和无符号数之间的转换,可导致各种错误,但是从安全的角度来看,最常见的是与整数溢出和缓冲区溢出有关。G、封装不当模式;主要包括以下类型Gl、故障名称系统资源泄漏。系统数据或者调试信息被无意识的泄露出去,可以使攻击者了解系统信息。增加了系统被攻击的可能性。见如下程序代码if(!filel叩ut.Open(PATH,CFile::modeRead,&ex》{ex.ReportError();else{fileI叩ut.Close(》分析根据系统不同的配置,错误信息可能会被输出到控制台,log文件,将会暴露给恶意攻击者。如果在这些错误信息中含有系统相关的内容,攻击者将会得到被攻击系统的相关信息。G2、故障名称没有捕获异常。如果没有捕获一些危险函数抛出的异常,将会导致程序崩溃。见如下程序代码voidfunction(char*szData)31PVOIDp=—alloca(lstrlen(szData));〃usep分析如果攻击者提供一个比内存大小还要长的szData,—alloca会引发一个异常并导致应用程序停止,进而造成Dos。处理这种错误'f况的正确方法是将对—alloca的调用打包在异常处理程序中,并在出现错误时重置内存堆栈区域。其奴进方法为voidfunction(char*szData)_tryTPVOIDp=—alloca(lstrlen(szData));〃使用p}—exc印t((EXCEPTION—STACK—OVERFLOW==GetExceptionCode())EXCEPTION—EXECUTE—HANDLER:EXCEPTION—CONTINUE—SEARCH)厂_—_一resetstkoflw();}一采用本发明的基于安全漏洞缺陷模式的测试系统(DTS,DefectTestingSystem),能对釆用C/C+十/Java语言编写的程序进行有效的缺陷测试和规则测试,具有测试精度高和自动化程度高的特点。首先,该系统定义了基于软件缺陷的测试方法的主要技术指标,并且提供缺陷模式状态机描述文件,该文件釆用xml技术描述了要检测的缺陷模式状态其次,系统的处理流程是读取待测软件,对待测软件源程序进行词法分析、语法分析、语义分析和函数调用关系分析,生成待测软件的抽象语法树、控制流图、符号表和函数调用图,然后通过区间运算来计算变量在程序中的取值区间,最后提供缺陷模式分析引擎,通过该引擎对程序控制流图进行遍历,对缺陷模式进行统一测试。再次,该系统提供了友好的DTS用户界面,并提供缺陷模式报表对缺陷分布情况进行分析。因此本发听使用测试系统DTS对C/C++(VC)/Java编写的程序进行安全漏洞缺陷检测。下面是使用本发明基于安全缺陷模式的DTS系统,对10个釆用Java语言编写的开源软件进行测试的结果。(注以下软件均来源于开源代码,其中xx/xx的数字形式表示对缺陷进行确认的结果,意即确认个数/不定个数/总数)软件名称(版本)文件个数/文件行数不合理的异常处理封装不当未验证的输入滥用API模式安全特性故障总计Sa扁b(l.0.2)990/2698914/0/413/1/140/0/03/0/00/0/020/1/21Contine。(3.0.4)224/547676/0/628/3/311/2/30/0/00/1/135/6/41Mycm'e411/100599簡/1617/7/2420/10/300扁1/0/154/17〃1j2ssh(0.2.9)442/894236/4/1033/5/380/0/04/0/41/0/144/9/53XuiPro(3.2)799/1552906/1/731/31/62.0/01/0/10/0/038/3/41Xui32(3.2)552/1131531/1/223/0/231/0/125/1/26Azi證is(3.0.5.2)2726/57272127/6/3312/3/152/0/230/6/3671/15/76Phex(3.2.6.106)790/16610614/0/1431/9/400/0/00/0/04/0/449/9/5832SSHToo1s-SSHDaemo'i(Win32-0.0.9)308/390705/0/524/1/250/0/04/0/40/0/033/1/34Drftpd(2.0.5)316/5558718/3/2110/2/120/0/05/0/50/0/033/5/38下面是使用基于安全缺陷模式的DTS系统,对10个采用0++语言编写的开源软件进行测试的结果。(注以下软件均来源于开源代码,其中xx/xx的数字形式表示对缺陷进行确认的结果,意即确认个数/不定个数/总数)软件名称(版本)文件个数/文件行数未验证输入低质量代码风险操作滥用API故障总计winscp(416)164/125940/7/217/0/270/0/00/0/07/7/48odbtp(l丄4)23/50160/1/61/0/20/0/00/0/21/1/10a誦(0.97.2)75/127760/16/160/0/00/0/00/0/00/16/16italc(1,0.9)148/130520/2/21/0/112/0/120/0/013/2/15pueblo370〃93990/22/2219/1/206/0/60/0/025/23/48eMule199/100470/1/1。/。/0/0/00/0/00/1/1fileZilla(3丄2)181/280130/10/4621/4/680/0/00/0/021/14/116firtex(1.0.3)3,88390/0/121/0/192/0/20/0/03/0/33Freeweb(t)丄3.2)75/55780/1/384/0/60/0/00/0/04/1/44myIEG.01)70/135783/0/40/0/517/3/200/0/020/3/29下面是使用基于安全缺陷模式的DTS2.0测试系统,对10个C语言的开源软件进行测试的结果。(注以下软件均来源于开源代码,其中xx/xx的数字形式表示对缺陷进行确认的结果,意即确认个数/不定个数/总数)软件名称(版本)文件个数/文件行数未验证输入低质量代码风险操作安全特性缺陷竞争条件模式故障总计mcnustos575/357250/10/212/1/52/2/60/0/00/0/04/13/32adproject147/255230/0/110/0/00層0/0/00/0/00/0/11openh32332/361900/0/02/0/24/0/40/0/00/0/06/0/6robodoc84/216370/6/61/0/12/0/20/0/00/0/03/6/9sttcrc叩105/1847662/13/154/0/40/0/00/0/00/0/06/13/19kadcwin303/458491/1/40/0/623/0/230/0/00/0/024/1/33amsn49/88621/7/110/0/00/0/00/0/00/0/01/7/11fpgac25/81760/8/80/0/60/0/00/0/00/0/00/8/14Pg2111/794790/1/17/0〃,2/1/30/0/00/0/09/2/11ucd曙snmp153/1006191/40/412/1/38/0/80/0/00/1/112/41/53综上所述,从以上三张测试结漏洞模式的DTS系统进行测试时,以上所述,仅为本发明的较《果统计表中可以看出,使用本发明基于安全它的误报率较小,测试准确度较高。实施例而已,并非用于限定本发明的保护范权利要求1、一种基于安全漏洞缺陷模式的检测方法,其特征在于,该方法包括A、读取被测程序源代码文件及软件安全漏洞模式对应的安全漏洞状态机描述文件,对所述被测程序进行预处理和解析安全漏洞状态机描述文件,并对被测程序进行词法分析和语法分析,生成被测程序的抽象语法树;B、根据所构造的抽象语法树,生成反映被测程序控制结构的控制流图和/或根据所构造的抽象语法树,并创建被测程序的符号表;C、根据所生成的控制流图和所创建的符号表,沿着被测程序控制流正向遍历控制流图;采用递归调用的方法,进行变量取值区间集的计算与更新;并且根据生成的符号表,对被测程序进行函数调用关系分析,生成函数调用关系图,同时建立ud/du链;D、建立安全漏洞状态机,以函数为单位,根据函数调用关系图对控制流图进行遍历,并根据所述建立的ud/du链对程序代码进行软件漏洞测试,并生成软件漏洞测试报告。2、根据权利要求l所述的检测方法,其特征在于,所述被测程序源代码文件为Java语言或0/0++语言。3、根据权利要求l所述的检测方法,其特征在于,所述软件安全漏洞模式类型包括未验证的输入模式,用于描述一些没有验证的输入,直接作为函数的参数进行调用的;滥用应用程序接口API模式,用于描述那些由调用者错误地信任被调用方所造成的漏洞;安全特性缺陷模式,用于描述有关信息安全所涉及的认证、访问机制、机密性保障、加密算法、权限管理方面的安全漏洞;竟争条件模式,用于描述分布式计算过程中与时间和状态有关的资源共享方面存在的安全漏洞;不合理的异常处理模式,用于描述与出错处理相关的安全漏洞缺陷;低质量代码模式,用于描述软件质量欠佳所导致的无法预期的安全漏洞;封装不当模式,用于描述函数所涉及的系统变量、系统资源和用户信息进行搡作时的安全漏洞。4、根据权利要求1所述的方法,其特征在于,步骤A所述对所述被测程序进行预处理的过程为对被测程序进行测试之前要进行宏替换、文件包含和条件编译。5、根据权利要求1所述的方法,其特征在于,步骤A所述解析安全漏洞状态机描述文件,为利用解析程序将所述安全漏洞状态机描述文件解析成后续处理中,安全漏洞模式分析引擎能够识别的内存数据结构。6、根据权利要求1所述的方法,其特征在于,步骤A所述对被测程序进行词法分析的过程为将被测程序转换为可以进行语法分析的记号流。7、根据权利要求1所述的方法,其特征在于,步骤B所述生成反映被测程序控制结构的控制流图的过程为通过采用访问者模式遍历抽象语法树得到,其方法是在遍历抽象语法树的基础上,由一个控制流图生成访问者实现;所述访问者采用递归下降的办法生成控制流图,在每个抽象语法树中代表语句节点的访问者函数中加入相应产生控制流图的代码;每一个控制语句对应抽象语法树节点的访问者函数负责生成该控制语句的部分控制流图,在遍历的过程中将这些部分控制流图一一连接组织起来就构成了被测程序的控制流图。8、根据权利要求l所述的方法,其特征在于,步骤C所述建立ud/du链的过程为通过对变量的赋值和变量的使用将定义的使用关系存储在ud链中、通过保存当前定义所有可能的使用列表保存在du链中,所述ud/du链用于供安全漏洞检测状态机调用。9、根据权利要求1所述的方法,其特征在于,步骤D所述根据所述建立的ud/du链对程序代码进行软件漏洞测试的过程为根据函数调用关系图对控制流图进行遍历,并根据安全漏洞状态机描述文件中关于安全漏洞状态、状态变迁以及引起状态变迁的动作的描述,计算控制流图上每个节点安全漏洞状态机的状态变迁,如果安全漏洞状态机进入软件缺陷状态,则报告对应的检查点IP。10、根据权利要求9所述的方法,其特征在于,所述检查点IP定义了与安全漏洞缺陷相关联的变量的定义代码行、安全漏洞发生的代码行和漏洞的类型。全文摘要本发明公开了一种基于安全漏洞缺陷模式的检测方法,包括读取被测程序源代码文件进行预处理,解析安全漏洞模式对应的安全漏洞状态机描述文件;再对被测程序代码进行词法、语法分析,构造出被测程序的抽象语法树;根据抽象语法树构造控制流图,生成符号表;然后进行变量取值区间集的计算与更新,并根据符号表、对被测程序进行函数调用关系分析生成函数调用关系图,再建立ud/du链;通过建立安全漏洞模式状态机并调用ud/du链,对控制流图进行遍历,计算控制流图上每个节点安全漏洞状态机的状态变迁,若安全漏洞状态机进入缺陷状态,则报告对应的检查点,测试完毕后输出安全漏洞测试报表。本发明方法具有自动化程度高、测试精度高的优点。文档编号G06F11/36GK101482847SQ20091000308公开日2009年7月15日申请日期2009年1月19日优先权日2009年1月19日发明者宫云战,李飞宇,杨朝红,庆肖,金大海,陈俊亮申请人:北京邮电大学
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1