1.简介
我们经常使用静态分析来检测程序中的安全漏洞,其优点是不用执行程序就可以分析代码。一系列安全分析工具,如Pixy[1]、RIPS[2],哦,皮克斯[三]PHPSAFE公司[4],韦韦卡[5]和Joern-PHP[6],通常用于检测漏洞。然而,随着PHP应用程序的复杂性不断增加,当前的工具和方法面临着额外的挑战。多层web应用程序(如MVC架构)采用统一的入口点,广泛应用面向对象的代码,使得简单的函数名称匹配方法无法构建完整的调用图,导致无法执行全面的过程间分析。同时,应用封装、路由和全局配置等编程技术来隐藏通用数据流分析无法访问的复杂数据流中的漏洞[7]. 现有方法无法有效地对现代多层web应用程序进行静态分析,误报率提高[8,9]. 尽管有些方法试图通过动态分析和自动漏洞验证来解决这个问题[7,10,11,12,13,14]这些方法依赖于静态分析。现有的静态分析技术无法有效地处理多层web应用程序,从而导致误报并限制动态分析。为了缓解上述问题,我们将别名分析过程合并到代码属性图的构造中。我们使用别名分析技术推断对象类型,构造方法调用边,并改进调用图以执行完整的上下文敏感进程间数据流分析。此外,我们提出了一种污点分析方法,通过可变传播路径生成漏洞数据流路径,以提高图遍历在构建漏洞路径时的效率。 基于该方法,我们实现了一个新的静态分析工具VulPathsFinder。它基于Joern PHP分析器,增加了别名分析和可变访问路径构建的功能,增强了现代多层PHP应用程序的分析能力。我们将VulPathsFinder的工作流分为三个阶段。首先,我们将PHP源代码转换为中间表示形式P-TAC[1],类似于传统的三地址码[15]. 然后,我们基于抽象语法树构造代码属性图并进行别名分析[16]和上下文敏感数据流分析[17]在此基础上构造完整的调用图和可变的访问路径。我们主要通过以下方式对原始代码属性图进行改进:(1)收集变量别名信息并跟踪变量访问路径;(2) 利用别名信息和类型推理改进调用图;(3) 根据攻击字典标记用户输入(源)和安全敏感调用(汇)节点。最后,基于节点标签和可变访问路径构造易受攻击的数据流路径。 本文的主要贡献总结如下:
VulPathsFinder工具的设计和实现:我们开发了一个名为VulPathsFinder的静态分析工具,专门用于解决现代多层PHP应用程序中的安全分析挑战。该工具基于Joern-PHP,扩展了别名和污点分析的功能,以增强其对复杂应用程序的分析能力。
改进代码属性图的构造:我们重新设计了代码属性图构造过程。通过收集变量别名信息、跟踪变量数据传播路径以及推断类实例变量的类型信息,我们可以生成更准确、更全面的调用图。
别名分析和污点分析的新方法:在构造控制流图之后,我们设计了一个基于注释解析的别名分析过程。我们还用污点标记了用户输入和安全敏感功能节点。这些改进提高了工具检测的准确性,并减少了误报。
一种新的安全漏洞路径发现方法:我们提出了一种基于图遍历技术的数据流分析方法,可以有效地挖掘应用程序漏洞路径。此方法允许在过程和面向对象编程中对安全敏感函数进行有效的回溯分析。
通过实验,我们确认这些改进显著提高了复杂应用程序中静态分析的有效性。我们相信,VulPathsFinder以及本研究的其他贡献可以为PHP应用程序的未来安全分析提供新的视角和方法。
本研究的组织结构如下。第2节讨论了相关工作。第3节介绍了技术背景,通过一个运行示例讨论了基于MVC架构的应用程序为安全分析带来的挑战,并简要概述了VulPathsFinder为解决这些挑战而实施的解决方案。第4节描述了改进的CPG和漏洞路径构建算法的详细信息。第5节讨论了VulPathsFinder的实验评估。最后,第6节包括结论。 2.相关工程
在过去十年中,检测PHP代码中的安全漏洞一直是研究的重点。
2.1. 静态分析
2006年,谢和艾肯[18]解决了静态识别PHP应用程序中的SQL注入漏洞的问题。与此同时,Jovanovic等人。介绍了PHP静态污染分析工具PIXY[1]. 他们的重点是PHP应用程序中的跨站点脚本错误。他们总共分析了六个不同的开源PHP项目。在这些测试中,他们重新发现了36个已知漏洞(含27个误报)和另外15个先前未知的缺陷(含16个假阳性)。Wasserman和Su介绍了两部专注于静态查找SQL注入和跨站点脚本的作品[19,20]. Jovanovic等人。[21]将其方法扩展到SQL注入,作为Pixy工作的后续。尽管所有这些工具都是PHP应用程序漏洞自动发现领域的先驱,但它们只关注非常特定类型的缺陷,即跨站点脚本和SQL注入。 Dahse和Holz[2]拟定RIPS。RIPS构建一个控制流图,然后通过模拟每个基本块的数据流来创建块和函数摘要,从而执行精确的污染分析。在这个过程中,作者发现了osCommerce、HotCRP和PHPBB2中以前未知的缺陷。Dahse和Holz通过检测二级漏洞(例如,持久跨站点脚本)继续他们的工作,在六个不同的应用程序中识别了150多个漏洞[22]. 2015年,Olivo等人。[23]讨论了二阶拒绝服务漏洞的静态分析。他们分析了六个应用程序,其中一些与之前的工作中分析的应用程序重叠,发现了37个漏洞,伴随着18个误报。David Hauzar等人。现为WeVerca[5],一个允许为PHP应用程序定义静态分析的框架。它支持类型系统、方法调用、数据结构等。该框架通过独立于解决这些功能所需的值和堆分析定义最终用户分析来解决实现不精确或过于复杂的问题。赵静玲等。[8]提出一个检测PHP web应用程序漏洞的框架。该框架结合了静态和动态分析,以提高检测效率。Paulo A.L.D.Nunes等人。[4]提出phpSAFE,这是一个静态分析器,用于识别使用面向对象编程(OOP)开发的PHP web应用程序中的漏洞。本文针对两个著名的工具和35个广泛使用的CMS插件评估了phpSAFE。结果表明,phpSAFE明显优于其他工具。Michael Backes等人。[6]是第一个将代码属性图应用于挖掘PHP应用程序中的漏洞的公司,并实现了一种基于代码属性图的PHP应用程序漏洞发现方法。我们的工作基于它们的实现,通过收集函数、方法和实例化语句的摘要信息来完成调用边,我们进一步改进了调用图和数据流图。同时,利用摘要信息,结合攻击字典来标记用户输入和安全敏感操作节点。最后,我们使用图遍历技术构建了漏洞路径。该领域的其他工作涉及消毒程序的正确性[4,11,24]. 2.2. 利用漏洞生成
Abeer Alhuzali等人。[25]目前,Chainsaw是一种工具,它改进了最先进的web应用程序注入漏洞识别和漏洞生成。Chainsaw被用于分析九个开源应用程序,生成了超过199个一级和二级开发组合,超过了几个相关方法。第二年,Alhuzali等人。呈报的NAVEX[7]这是一个结合了动态和静态分析技术的工具,用于识别漏洞并在大型多层web应用程序中构建有效的自动漏洞利用。它们都应用静态符号执行来对状态间依赖关系进行建模,这可以产生种子来指导动态扫描程序发现代码中隐藏的漏洞。Lee等人。[10]提出了一个渗透测试工具FUSE,旨在发现服务器端PHP web应用程序中的UFU和UEFU漏洞。FUSE旨在生成上传请求;每个请求都会成为触发UFU或UEFU漏洞的攻击负载。FUSE发现了30个以前未报告的UEFU漏洞,包括来自33个现实世界web应用程序的15个CVE,从而证明了其通过文件上传发现代码执行错误的有效性。Park等人。[12]介绍FUGIO,第一个针对POI漏洞的AEG工具。作者提出了一系列静态分析、动态分析和模糊化技术来计算POP链并生成漏洞利用。FUGIO报告了30个真实PHP应用程序中已知POI漏洞中的68个攻击对象。FUGIO还报告了两个以前未知的POI漏洞,并生成了可利用的对象,证明了FUGIO在显著减轻面向属性编程的繁重负担方面的有效性。 总之,从检查安全敏感函数到控制流图,再到代码属性图,关于数据结构的静态污染漏洞检测技术已经越来越完善。其核心是通过检测用户输入是否达到安全敏感功能,检查用户输入并跟踪数据流以触发敏感操作。然而,由于广泛使用了面向对象的代码、封装和动态特性,现代多层web应用程序使得这些方法很难准确获取污染传播路径或执行完整的过程间分析。虽然动态分析或动态和静态分析的混合方法可以避免上述问题,但由于需要代码运行环境和动态测试所需的较长时间,它无法实现完全自动化的检测。我们基于代码属性图原型Michael Backes等人。实现并通过别名分析将方法调用边添加到调用图中。我们建议通过可变传播路径构建污点传播路径来生成漏洞路径。一方面,我们构建了一个完整的调用图,允许安全分析师基于这个代码属性图对进程间的数据流进行更准确的分析。另一方面,我们解决了由于封装而无法准确获取污染传播路径的问题。
3.背景和动机
在本节中,我们首先介绍代码属性图(CPG)的基本知识。随后,通过几个示例,我们展示了现代PHP应用程序中用于漏洞检测的现有CPG原型实现中的不足,启发我们重新设计我们的解决方案。
3.1. Joern-PHP概述
我们的研究基于代码属性图的概念,它是程序语法、控制流和数据流的集成表示。这一概念首先由山口等人提出。并应用于检测C代码中的漏洞[26]. 该方法的关键思想是将传统的程序表示合并到代码属性图中,从而通过图遍历技术实现代码模式挖掘。抽象语法树(AST)清楚地展示了程序的嵌套结构,而控制流图(CFG)允许对语句之间的交互进行推理,尤其是它们的执行顺序,而程序依赖图(PDG)揭示了语句和谓词之间的依赖关系。这些依赖性支持程序内的静态数据流分析,尤其是可攻击控制数据的传播。虽然代码属性图中AST、CFG和PDG的组合为分析程序控制和数据流提供了强大的结构,但CFG和PD仅限于功能级别。将调用图并入代码属性图允许我们在过程间级别执行控制和数据流分析。 2017年,Michael等人。将其引入到PHP应用程序漏洞检测中,并使用调用图来丰富代码属性图[6]. 他们开发了Joern-PHP,这是一个为PHP应用程序构建代码属性图的原型工具,并演示了如何使用图遍历技术进行跨过程漏洞分析。尽管Michael等人。将调用图引入到代码属性图的原型实现中,方法调用的边是不完整的。对于动态方法调用,只有当方法名称在项目中唯一时,才会构造从调用节点到相应方法声明的边。如果没有类型推理,就无法获得动态方法调用和类方法之间的映射关系,这使得该工具不适合在广泛使用封装和方法调用的现代应用程序中进行漏洞检测。因此,我们通过使用别名分析,将方法调用边添加到调用图中,并跟踪变量或字段之间的数据传播,进一步丰富了此结构,以更好地促进跨过程分析。 3.2. 别名分析
作为静态分析的基础,指针分析主要检查指针可能引用的所有可能对象[27,28,29]. 面向对象语言主要用于确定变量或字段可能指向的潜在对象。指针分析在面向对象编程的程序分析中起着至关重要的作用,结果通常表示为指针和内存位置之间的点对关系,或者表示为每个指针的可能目标对象集。它提供程序内的基本数据流信息。指针分析被公认为最基本的静态分析技术之一,其研究已有40多年的历史,主要集中在Java和C/C++等语言上[30,31,32]. 指针分析是一种静态代码分析技术,用于确定程序中指针或引用变量可能指向的对象。这种分析在许多高级程序分析任务中是不可或缺的,例如程序切片、数据流分析、程序理解等。 别名分析[33]是指针分析的一个重要分支,其重点是确定在程序执行期间可能引用同一内存位置的两个或多个指针变量,也称为别名。这个问题存在于许多编程语言中,尤其是那些允许显式指针操作(如C和C++)的语言。别名分析的重要性源于它的多种应用场景。例如,编译器可以使用别名信息来优化程序,在确认没有别名冲突时更自由地重新排列指令,并提高程序执行效率。此外,别名分析是许多高级程序分析和转换的基础,如程序切片、数据流分析、线程分析等。 别名分析面临的挑战之一是,它需要解决的问题是不可判定的,这意味着没有任何算法能够在所有情况下精确地确定所有别名关系。因此,现有的别名分析技术通常需要平衡精度和效率。共同战略[28,31]在实践中包括: 流敏感分析:这种别名分析考虑程序的执行顺序,提供更精确的结果,但计算复杂度更高。
流敏感分析:与流敏感分析相反,这种别名分析忽略程序的执行顺序,产生的结果不太精确,但计算复杂度较低。
上下文敏感分析:这种类型的别名分析考虑函数调用的上下文,能够处理函数之间的别名关系,但计算复杂度较高。
上下文相关分析:与上下文相关分析相比,这种类型的别名分析忽略了函数调用的上下文,导致结果不太精确,但计算复杂度较低。
尽管别名分析面临众多挑战,但通过选择适合特定应用程序需求的策略,它仍然是一个非常有用的工具。
3.3. 污点跟踪分析技术
着色分析[34]是一种跟踪和分析程序中受污染信息流的技术。在漏洞分析中,污点分析用于标记感兴趣的数据(来源(例如,不受信任的用户提供的数据)。可以通过跟踪受污染数据流并检查其是否影响关键项目操作来发现漏洞(水槽). 这将识别程序漏洞的问题转化为确定受污染信息是否到达执行关键操作的汇点。 着色分析通常涉及以下组件:
识别产生受污染信息的来源,并标记受污染数据。
通过特定规则跟踪和分析受污染信息的传播。
在汇点检测关键操作是否受到受污染信息的影响。
被篡改的信息不仅可以通过数据相关性传播,还可以通过控制相关性传播。我们将通过数据依赖的信息流称为显式信息流,而通过控制依赖的信息流动称为隐式信息流。
静态污染分析系统[2,4,6,7,35]首先解析程序代码以获得中间表示。他们执行辅助分析,如控制流分析,以获得控制流图、调用图和其他必要信息。在辅助分析过程中,系统可以使用污点分析规则来识别中间表示中的源点和汇点。最后,检测系统利用基于污点分析规则的静态污点分析来检查程序中与污点相关类型的漏洞。 3.4. 运行示例
对于使用新实例创建类实例的语句,获取实例化变量的类类型相对容易。如今,越来越多的PHP应用程序是基于框架开发的。这些框架使用类封装了常见的业务功能,并广泛利用了动态数组和反射功能。这使得通过静态分析获取类型信息变得非常困难。静态分析无法检索与方法调用对应的类方法,导致调用图不完整,并且难以进行过程间数据流分析。
为了解释研究问题和动机,我们从两个实际应用程序中提取了相关代码,并将它们组合成示例代码片段[36,37],如清单1和2所示:清单1。MVC应用程序中简单代码片段的第一部分。 |
|
清单1定义了一个名为Push的控制器类,它扩展了controller类(第3-13行)。在Push类的index()方法中,使用post()方法调用类属性请求,并将其返回值赋给变量$cf名称。请求属性源自父类Controller。清单2显示post()方法从全局变量检索用户输入$_邮政数组。
在清单1中,属性$此->请求在Push类的父类Controller中初始化。在Controller类中,$此->请求初始化为的实例通过构造函数中的动态数组赋值。我们无法获取的类类型$此->请求通过静态或别名分析。然而,我们注意到,我们可以从所请求属性的注释(第15-17行)推断出它是类。除了实例创建语句之外,标准化的开发实践还为我们提供了额外的静态信息。我们可以通过注释解析获得相应参数或类字段的类型信息。清单2。MVC应用程序中的简单代码片段的第二部分。 |
|
在清单1(第6-8行)中,$cf名称直接连接到SQL语句中,并在非状态方法调用中用作参数,$SQL->WHERE_and().在第10行,实例化$博客_结果通过调用Results类的构造函数执行。随后,在第11行运行查询Results类的方法被调用$博客_结果检查Results类定义(清单1,第24-32行)可以发现,在类方法中运行查询(_query)(清单1,第28-31行),class属性$这个->sql作为参数传递给非状态方法,$数据库->查询()根据清单1第2行,$数据库是一个全局变量,是DB类的一个实例(清单2,第6-15行)。
在清单2中查询方法(第11-14行)表示$查询_SQL非状态方法调用的参数$this->dbhandle.query()(清单2,第12行)。根据DB类的构造函数推断(__construct()),$this->dbhandle是mysqli类的一个实例$this->dbhandle.query()一个原始的、安全敏感的方法调用。
最后,$this->request.post()从全局变量中提取用户输入数据。将结果值赋给变量$cf名称,然后将其合并到SQL语句中,并通过$SQL->鉴于和()到SQL类属性$this->其中.然后,$SQL->获取()指导的价值$这个->在哪里作为的参数$博客_结果实例属性$sql语言.$博客_结果通过调用安全敏感方法执行包含用户输入的SQL语句,Mysqli->query(),通过运行查询(_query)方法。
3.5. 动机
总结一下提供的实例,对象封装应用程序中存在的动态特性使得直接检索实例对象的类具有挑战性。然而,这些应用程序具有统一的体系结构和相对标准的语言约定,使我们能够通过解析注释中的变量或类字段声明类型来间接确定其对应的类,从而构造方法调用边。此外,此类应用程序通过实例属性封装数据,通过数据流图遍历来掩盖潜在的漏洞。
以这个例子为例,我们综合了现有的挑战,并提出了在检测当代web应用程序中的漏洞时进行静态分析的解决方案。
要发现上述SQL注入漏洞,我们必须:
实现过程间数据流跟踪,因为许多关键方法调用在多个调用点之间发生,从而创建准确的调用图。
确保分析将控制流图中的字段变量和上下文临时变量映射到相同的对象或值(例如。,$SQL->SQL==$_t2时间).
将程序依赖图与过程间污点分析结合起来,以跟踪可变访问路径。
总之,现代多层web应用程序大量使用面向对象代码及其封装、动态和附加功能,使对象类型不明确,因此需要现有工具来帮助构建基于方法调用的完整调用图,并执行全面的过程间分析。受污染的信息被封装在大量的类代码中,由于传统数据流分析无法发现隐藏的易受攻击的数据流,因此导致误报。代码属性图的现有实现旨在构建一个完整的图结构,该结构表示代码语法和语义,并通过图遍历技术执行过程间数据流分析。然而,构建代码属性图并不能推断对象类型,因此无法执行完整的过程间分析。图遍历技术使用代码属性图来基于通用污点跟踪方法构建漏洞路径,该方法无法发现封装在对象属性中的污点信息,并可能导致误报。此外,这种基于安全敏感节点回溯数据流图的图遍历方法容易导致路径爆炸和效率低下。因此,有必要改进现有的代码属性图构建过程,优化图遍历算法,以缓解现有静态分析工具中的误报和漏洞检测效率低的问题。具体而言,我们确定了以下挑战:
3.6. 挑战
面向对象。多层Web应用程序广泛采用面向对象编程(OOP),通过方法调用执行功能。特别是,非状态方法是通过从相应类实例化的变量来调用的。我们必须确定这些实例化变量的特定类型,以便在代码属性图中构建全面的调用图。然而,许多应用程序严重依赖于面向对象编程和动态特性,只在运行时显示特定的类型。如清单1(第20-21行)所示,通过静态分析直接获得这些类型显然是一项挑战。另一方面,面向对象编程的封装特性掩盖了数据依赖性,使得我们很难通过追溯数据流来发现缺陷。
性能。在许多现代应用程序中,许多功能需要一系列相互依赖的步骤,通常使用不同的模块完成。如果安全敏感功能位于这些模块的深层,则中间数据流节点的交叉会生成许多数据流路径。此外,为了准确识别从用户输入到安全敏感函数/方法的数据流路径,必须识别安全敏感方法的名称并分析调用该方法的变量的实例化。将这些任务直接集成到漏洞路径发现算法中必然会增加其复杂性并降低其效率。
可扩展性。除了利用安全敏感的功能外,现代应用程序还封装了安全敏感的方法,例如$this->dbhandle清单2中DB类的属性。为所有安全敏感功能/方法设计特定的数据流路径查找算法是一项挑战。为了保持可扩展性,我们根据安全敏感操作的现有形式将其分类为安全敏感函数和方法,并为其设计了统一的漏洞路径遍历算法。通过引入攻击字典,用户可以根据漏洞类型配置相应的安全敏感函数或方法,而无需更改算法。例如,我们可以设置查询()清单2中DB类的方法作为安全敏感的方法并执行遍历。
4.实施概述
考虑到现代多层web应用程序面向对象的封装特性,我们旨在设计和实现一种基于增强的代码属性图的统一、可扩展和高效的漏洞路径发现方法。
基于这种方法,我们开发了一个工具VulPathsFinder。为了解决可伸缩性问题,我们的工具分为三个步骤:(1)从源代码转换为三地址代码;(2) 增强型代码属性图的构造;(3) 识别漏洞路径。VulPathsFinder的体系结构如所示图1. 第一步将给定应用程序的源代码作为输入,将其解析为抽象语法树(AST),然后使用PHPToTAC工具将AST转换为三地址代码形式的源代码,同时保持原始项目文件的目录结构。
第二步涉及构建增强的代码属性图。此阶段以三地址代码形式处理代码文件,解析文件中的语句以构建控制流图和程序依赖图。为了解决面向对象的挑战,我们基于控制流图进行类型推理,以获取实例对象和可变访问路径的类型信息。然后,我们将从调用点到方法定义的调用关系添加到调用图中,以便于后续的过程间分析。此外,在类型推理过程中,我们在函数或方法返回值和调用点之间建立数据依赖边(USE-DEF关系),从而细化程序依赖图。我们引入了一个攻击字典,其中包含有关安全敏感函数的信息,以及从公认的安全敏感方法到类的映射,以解决性能问题和可伸缩性。在类型推理过程中,我们使用攻击字典标记安全敏感的函数和方法调用节点以及用户输入节点,从而避免在代码属性图中查询安全敏感操作和用户输入节点。
第三步涉及构建漏洞路径。通过将安全敏感功能/方法节点作为数据流回溯和进行污点分析的起点,我们可以通过标记的用户输入节点和可变的访问路径跟踪污点的传播路径,从而识别从安全敏感节点到用户输入的漏洞路径。
4.1. PHP解析器
为了分析最新版本的PHP,我们使用PHP-Parser[38]作为从PHP源代码生成解析树的库。此库会随每个PHP版本不断更新,从而方便后续更新和维护。解析器可以用于静态分析、代码操作和任何其他以编程方式处理代码的应用程序。解析器构造代码的抽象语法树(AST),使其能够被抽象和稳健地处理。 还有其他处理源代码的方法。PHP本机支持的一种方法是使用“token_get_all”生成的令牌。令牌流的级别比AST低得多,因此具有不同的应用程序:它还允许分析文件的确切格式。另一方面,对于更复杂的分析,令牌流更难处理。例如,AST抽象出一个事实,即在PHP中,变量可以写为$foo公司,$$酒吧,${“足球”},甚至${!${“}=barfoo()}。您不必担心标识令牌流中的所有不同语法。
除了解析器本身,此包还捆绑了对其他几个相关功能的支持:
4.2. PHPtoTAC公司
除了引入新的PHP解析器之外,我们还修改了中间模型的构造,以适应面向对象的特性和别名分析。由于我们引入了一个新的PHP解析器来构建抽象语法树(AST),我们利用基于该AST的PHP解析器的节点遍历功能来检查每个节点。本模块[39]跟踪各种类型的表达式(赋值、函数调用、方法调用、实际参数、形式参数等),并监视函数定义、类定义、对象引用、方法定义、变量、名称空间和接口。PHP-Parser通过遍历跟踪将这些表达式和语句节点转换为三地址代码格式,这允许我们对转换后的代码执行别名分析和变量数据跟踪。因此,在进行污染分析时,我们可以执行过程间数据流分析。 4.3. 代码属性图
将PHP源代码转换为基于PHP-Parser的三地址代码格式后,我们将其用作Joern-PHP的源代码输入,以构建代码属性图(CPG)。首先,我们将转换后的三地址代码解析为AST,然后遍历AST中的每个文件以构建控制流图。然后遍历此控制流图以分析别名,以获取可变别名信息。基于注释和实例创建语句,我们推断变量的实例类型,解析方法调用点,并创建方法调用边以改进调用图。
在Joern-PHP之上,我们添加了别名分析和变量实例类型推断来创建方法调用边。该过程的伪代码如算法1和2所示:
算法1和2显示了我们基于Joern-PHP添加的类型推理和调用图构建过程。
在算法1中,遍历的过程称为抽象语法树(AST)(第4行)。算法1中的第5–22行显示了遍历控制流图以执行上下文相关别名分析的过程。此过程遍历控制流图并分析语句的赋值、存储和加载操作。通过这个解析过程,一方面,我们可以推断变量的方向信息,即类型信息。另一方面,我们可以为变量构造访问路径。算法1中的第23行显示了基于前两个步骤的结果构建调用图的过程。算法1类型推理与调用图构造(1) |
输入:- 1:
:抽象语法树;:控制流图 输出:- 2:
:点对信息;:调用图 - 3:
- 4:
- 5:
对于 做 - 6:
- 7:
对于 做 - 8:
- 9:
- 10:
如果 然后 - 11:
如果 然后 - 12:
- 13:
结束条件为 - 14:
如果 然后 - 15:
- 16:
结束条件为 - 17:
结束条件为 - 18:
如果 然后 - 19:
- 20:
结束条件为 - 21:
结束 - 22:
结束 - 23:
|
详细信息解析AST如算法2所示(第3-21行)。它主要解析实例创建语句(算法2,第5-9行)、方法调用(算法2、第10-15行)和全局语句(算法2中,第16-19行)。全局语句反映变量的范围,这会影响我们对相应变量的类型推断。这个过程处理调用(算法2,第28-39行)首先解析方法调用中的实例变量和方法,然后通过实例变量名从变量方向信息中获取实例变量对应的类,然后用调用边将调用语句与相应的方法定义节点连接。此外,我们在调用点的实际参数变量和相应方法的形式参数(算法2,第34-36行)之间建立了数据依赖边。如果该方法有返回值,则还将在返回值节点和调用语句的左值之间建立数据依赖边(算法2,第37行)。
需要注意的是,算法1–3具有一些特定代码未显示的功能。这些功能是功能性的,代表一个过程。我们通过在算法的相应位置添加注释来描述它们的功能。
将上述过程应用于示例代码后,我们获得了改进的代码属性图和变量访问路径,如所示图2:算法2类型推理和调用图构造(2) |
输入:- 1:
:抽象语法树;:控制流图 输出:- 2:
:点对信息;:调用图 - 3:
功能 分析AST() - 4:
对于 做 - 5:
如果 然后 - 6:
//获取节点的上下文信息 - 7:
//获取变量名和类 - 8:
- 9:
结束条件为 - 10:
如果 然后 - 11:
- 12:
//获取全局声明的变量名 - 13:
- 14:
- 15:
结束条件为 - 16:
如果 然后 - 17:
- 18:
- 19:
结束条件为 - 20:
结束 - 21:
end函数 - 22:
功能 添加边缘() - 23:
如果 然后 - 24:
- 25:
- 26:
结束条件为 - 27:
end函数 - 28:
功能 处理调用() - 29:
对于 做 - 30:
- 31:
//从方法调用分析对象 - 32:
- 33:
- 34:
对于 做 - 35:
- 36:
结束 - 37:
- 38:
结束 - 39:
end函数
|
如所示图2,我们通过类型推理在调用位置和方法之间构建调用边来改进调用图,并完善了程序依赖图(PDG)[6]通过在方法返回值和调用点的左值之间建立数据依赖关系。同时,通过获取实例的类型信息和类型推理过程中变量之间的数据传播路径,构造了右侧变量访问路径图。它包括以下元素:用户输入标记节点、变量之间的USE-DEF关系、过程间数据传播和安全敏感调用标记。此外,我们使用虚线连接表示相同实例封装的数据字段节点。尽管它们处于不同的上下文或过程中,但它们表示相同的数据,并且它们之间确实没有USE-DEF定义的程序依赖性。因此,我们使用虚线连接它们。这样,我们就获得了一个完整的变量访问路径,可以指导我们构建一个完整漏洞路径。 4.4. 图的遍历
在构建代码属性图时,我们根据攻击字典标记用户输入和安全敏感调用。这样,我们就避免了在图遍历期间基于图遍历检查用户输入和查询安全敏感调用。由于基于安全敏感调用的图遍历技术在递归回溯数据流中容易发生路径爆炸,因此我们修改了通过递归回溯的方法来构造易受攻击的路径的过程。更新后的算法如算法3所示:算法3基于传播路径和图遍历的污点分析 |
- 1:
//从CPG获取汇聚节点 - 2:
所有路径=[] - 3:
对于 做 - 4:
//遍历可变访问路径 - 5:
//从变量访问路径检索语句节点 - 6:
- 7:
结束
|
算法3基于可变访问路径和汇标记构建漏洞路径,这仍然是一个图遍历过程,但不再基于程序依赖关系图中的数据流回溯。首先,我们从代码属性图中查询汇聚标记以获得汇聚节点(第1行)。基于获得的汇聚点,我们获得受污染的变量,在可变访问路径中定位变量节点,然后以汇聚点为起始节点对可变访问路径进行回溯。如果我们遇到用户输入标记,我们将停止回溯(第3-4行)。此时,我们已经提取了用户输入到安全敏感调用的可变访问路径。最后,我们将这些可变访问路径中的可变节点恢复到相应CPG中的语句节点,从而获得漏洞路径(第5-6行)。与Joern-PHP的漏洞路径发现的图遍历算法相比,算法3大大简化了图遍历过程。然而,这并不意味着我们的工具简化了漏洞路径发现的整个过程。如所示图2,我们在遍历控制流图时构造可变访问路径,标记用户输入节点,并标记安全敏感操作。由于遍历控制流图是必要的,因此我们在此过程中执行一些附加操作以简化最终的图遍历过程。 5.评估
5.1. 数据集
我们在基于开源框架或MVC结构开发的十个应用程序上评估VulPathsFinder,如表1我们对应用程序的选择标准如下:(1)我们评估了具有统一框架结构的流行、大规模应用程序,无论它们是独立开发的还是基于开源框架开发的复杂应用程序,并且包括了具有报告漏洞的最新版本;(2) 我们比较了静态漏洞检测工具使用的相同测试应用程序。 5.2. 安装程序
我们实施了PHPtoTAC[39]使用PHP-Parser将源代码转换为三种地址码格式[38]并基于Joern-PHP实现了静态分析工具VulPathsFinder[40]. 我们在Ubuntu 22.04.2 LTS上部署了VulPathsFinder,每个内核2.6 GHz,内存50 GB。为了评估VulPathsFinder,我们将其精度和召回率与四个PHP静态分析工具进行了比较:Joern-PHP[6],ooPIXY(哇)[三]和RIPS[2]. 我们使用真实世界的开源PHP应用程序进行了实验。对VulPathsFinder和Joern-PHP进行比较,以评估基于Joern-HPP的增强带来的改进。由于RIPS和ooPixy支持OOP功能,因此与VulPathsFinder的比较可以深入了解OOP支持。然而,RIPS的最新版本是商业的、非开源的,并且不提供学术许可。因此,我们在评估中使用了最新的开源版本0.55。 在整个评估过程中,我们使用了以下定义:精度(对),召回(R(右))、和(F类) [三]. 精度是真阳性数的比率(TP(转移定价))报告的错误数,包括报告的真阳性和假阳性(FP公司): 召回是真阳性数与实际错误数的比率,包括报告的真阳性数和假阴性数(FN公司,我们未能检测到的)。 提供了结合精度和召回率的综合测量标准。这个给定工具的范围介于0和1之间。我们将使用对,R(右)和为所研究的工具提供准确度排名。 5.3. 结果摘要
我们从数据集中选择了10个基于MVC架构的应用程序作为测试集,评估VulPathsFinder和Joern PHP在构建代码属性图方面的差异,主要体现在两个方面:(1)改进前后代码属性图中节点和边类型的变化;(2) 二者在构建代码属性图时的时间效率比较。
如所示表2,我们对同一数据集进行了比较,该数据集包括十个项目和总共1336649行代码。首先,我们可以看到AST节点和边的数量以及CFG边的数量在两者之间是一致的,因为我们使用php-AST以相同的方式解析相同的数据集。主要区别在于调用数和程序依赖边。然后,VulPathsFinder中的调用边数比Joern-PHP中的要多,因为我们已经将方法调用边添加到调用图中。此外,与Joern-PHP相比,程序依赖边的数量也增加了,因为在处理方法调用时,我们同时处理了调用点处具有左值的函数和方法的返回值的USE-DEF关系,从而增加了程序依赖边数量。 中的最后一行表2显示了两个工具在同一数据集上构造代码属性图所花费的时间。因此,两者的时间相同。这主要是因为整个过程所花费的时间是由于遍历AST节点和控制流图,这两个节点都没有改变。此外,添加程序依赖边和调用边只会增加整个AST和CFG遍历过程的恒定计算负载,因此它们不会显著影响最终的总运行时。 除了由使用中描述的框架的现代应用程序组成的数据集之外表2,我们收集了另一个由不使用统一框架的流行应用程序组成的数据集。该数据集用于比较VulPathsFinder和Joern-PHP对非框架和基于框架的现代应用程序的漏洞检测的影响。实验结果如所示表3. 与OOPixy和RIPS相比,PHPAudit和Joern-PHP可以检测大多数漏洞。OOPixy是一个基于Pixy开发的工具,用于适应PHP的面向对象特性。它只支持检测SQLi和XSS漏洞,并且适用的PHP版本是浅层的(PHP5)。在运行此工具进行漏洞检测时,我们没有获得有效的输出结果。调试时,由于无法解析某些代码,在解析PHP代码以生成中间代码(例如类的访问修饰符)时,我们通常会遇到语法错误。此外,该工具通过基于控制流图识别用户输入和安全敏感功能来执行污点分析。封装用户输入和安全敏感功能会妨碍完整的过程间分析。上述问题导致OOPixy无法输出有效的检测结果。RIPS检测到OOPixy的其他漏洞,目前作为商业项目进行维护。它的开源版本只有5.5。虽然它在PHP中对许多内置函数进行建模,并基于控制流图构建漏洞信息流路径,但它不支持面向对象的代码分析,并且处理复杂的封装应用程序需要太长时间,因此无法输出有效的结果。我们重点关注VulPathsFinder和Joern PHP在两个数据集上的漏洞检测性能。
如所示表3,对于非MVC应用程序,Joern-PHP和VulPathsFinder之间的漏洞检测结果略有不同。两者的漏洞检测逻辑略有不同。主要区别在于,我们对源代码输入执行三地址代码转换,消除了循环逻辑,并大大减少了图所遍历的路径数。此外,我们改进了基于图遍历的漏洞检测算法。VulPathsFinder使用标记和访问路径进行漏洞检测,这也在剪枝图遍历和缓解图遍历技术中的低效问题方面发挥了作用。专栏几何平均值显示了基于MVC架构的应用程序漏洞检测结果的几何平均值。从本专栏中的值可以看出,VulPathsFinder在基于MVC的应用程序漏洞检测的准确性和时间消耗方面优于Joern-PHP。对于基于MVC的应用程序,VulPathsFinder添加了变量类型推断,该推断通过推断对象类型向调用图添加额外的方法调用边。它还改进了程序依赖图,缓解了代码属性图中过程间分析不完整的问题。同时,它还保持了Joern-PHP的原始可扩展性。基于上述改进,VulPathsFinder和Joern-PHP对基于MVC的应用程序的漏洞检测性能进行了比较。Joern-PHP显著提高了准确性并减少了漏洞检测所花费的时间。 6.结论
面向对象代码在多层现代web应用程序中的广泛使用从静态分析的角度对漏洞挖掘提出了挑战,包括封装、继承和多态性。大量面向对象的代码使得无法使用简单的函数名称匹配方法构建完整的调用图,导致无法执行全面的过程间分析。类的封装特性使得数据隐藏在对象属性中,使得无法通过通用数据流分析获得漏洞路径。为了缓解上述问题,我们通过添加别名分析功能来改进代码属性图,为基于代码属性图的完整过程间分析提供基础。此外,为了缓解图遍历技术的效率问题,我们提出了一种基于可变访问路径的漏洞路径构建方法,以提高漏洞发现的效率。然而,我们必须承认,现代PHP应用程序的深度动态特性使得静态分析技术无法完全解决对象类型推断的问题,VulPathsFinder生成的结果仍然需要手动验证。在未来的工作中,我们将根据VulPathsFinder的检测结果进行动态测试研究,以避免手动验证,实现漏洞检测和验证的全自动化。