曹凯,何晶,范文庆,黄玮
(中国传媒大学 理工学部,北京 100024)
PHP语言在网站服务端使用广泛,但由于固有的脆弱性,在编程过程中易产生各种漏洞。其中较为常见的有SQL注入漏洞和跨站脚本漏洞。根据OWASP(Open Web Appliation Security)[1]2017年最新公布的数据显示,在排名前十的Web应用安全漏洞中,注入类攻击排名第一位,跨站脚本攻击排名第三位。这两种漏洞的成因主要是对用户输入数据的有效性未能进行合理验证,因此这种类型的漏洞又被称为污染数据传播漏洞,也可称为污点型漏洞。本文对PHP漏洞检测主要也是针对于SQL注入漏洞和跨站脚本漏洞。
对于Web漏洞的分析,开发人员通常会采用两种分析方法。即动态分析和静态分析。动态分析使用较为容易,用于发现程序运行时出现的错误。而静态分析的检测,则不需要代码的运行。随着技术的不断进步,更高效的算法被研究出来,静态分析方法也变得越来越成熟。
目前业界PHP静态分析工具有:Pixy,RIPS,PHP-Sat,WAP及Foritfy SCA等。Pixy[2]是使用Java语言开发的一款开源的PHP静态检测工具。其通过数据流分析的方法检测漏洞,其机制非常有效,但Pixy只支持PHP4的语法,对于PHP5以后的语法特性并不支持,而且主要针对的漏洞为跨站脚本漏洞,对于其他漏洞检测效果并不理想。RIPS[3]是用PHP语言开发的一款检测PHP的工具,是基于token流的静态分析工具。它通过PHP的内置函数token_get_all()来对PHP代码进行词法分析从而获得token,然后进一步将代码转换为便于分析的中间格式,进而采用污点分析方法检测漏洞。WAP[4],全称Web Application Protection,是一款采用Java语言编写的PHP漏洞检测工具,该工具采用污点分析的方法分析源码,优点是可以自动化修补被确认的漏洞。Balzarotti[5]等人结合字符串分析方法,基于Pixy工具实现了一种动静结合的PHP代码分析方法。Rimsa[6]等人使用e-SSA作为中间表示形式,以此对PHP进行污点分析。Y.Zheng和X.Zhang[7]提出了路径和上下文相关的过程间分析方法来检测漏洞。但以上工具仍存在一些问题,比如中间表示形式不够完备,导致丢失了很多重要信息;对文件包含处理不够完善;对新版本的PHP语法特性不能完全兼容;漏报和误报相对较高。
本文在总结前人的经验的基础上,采用PHP-Parser对PHP代码进行语法和词法分析,可以兼容最新的和应用更为广泛的PHP5和PHP7的新特性,产生信息非常完整的抽象语法树,然后构建控制流图,再在生成的控制流图上进行污点传播分析,进而检测出可能存在的漏洞。通过测试,采用本文方法确实可以检测出相应漏洞。
为了进行污点分析,PHP源码必须被转换为一种利于分析的中间表示形式,本文采用控制流图(Control Flow Graph,CFG)作为中间表示形式,但CFG的生成依赖于抽象语法树(Abstract Syntax Tree,AST),抽象语法树反映了程序的结构,因此需要先对PHP源码进行词法和语法分析来生成抽象语法树。
对于生成抽象语法树的方式有多种。有的采用HHVM[8],一种用来执行PHP语言的PHP虚拟机来生成抽象语法树;有的基于ANTLR[9],一款根据输入自动生成语法树的语法解析器。本文对PHP的词法和语法分析采用PHP语法处理器PHP-Parser[10],PHP-Parser是一个由PHP编写的支持PHP5.2到PHP7.1的语法解析器。主要用来产生抽象语法树,对于PHP代码的静态分析具有很大的帮助。例如,将以下代码传递给解析器:
echo 'Hi','World';
?>
将会产生一个数组格式的抽象语法树:
array(
0:Stmt_Echo(
exprs:array(
0:Scalar_String(
value:Hi
)
1:Scalar_String(
value:World
)
)
)
以上输出的抽象语法树包含一个输出语句节点,节点内包含一个数组,数组内容为两个常量字符串。 PHP的语法繁多,大概包含140种不同的节点,为了便于解析将其分为以下几类:
(1)PHPParserNodeStmt,即语句节点。没有任何返回值的结构,如赋值语句,函数定义等。
(2)PHPParserNodeExpr,即表达式节点。有返回值的结构,如单个变量,函数调用等。
(3)PHPParserNodeScalar,即常量节点。用来表示任何常量,如字符串,整型,常量表达式等。
(4)还包括一些不属于以上三种类型的节点,如参数节点等。
当获得PHP源代码后,首先使用PHP-Parser将源码转换为一个数组形式抽象语法树,若直接进行数据流分析,由于编程语言中会有分支、循环、跳转以及条件表达式等结构,当中隐含了不连续的控制流,所以抽象语法树与数据流分析并不能完全兼容。因此本文将抽象语法树转换为控制流图,然后再进行污点分析。
成果表包括界桩登记表、三交点界桩登记表、界桩成果表、界址点成果表、三交点成果表和界线协议书附图备考表。参考1998年陕西省各乡镇联合勘界相关成果,对边界线上的界线名称、边界点名称、编号、坐标及行政归属等内容形成不同制式表格模板,方便信息录入、管理与查询。
本文通过递归的方法来构造CFG。首先遍历AST中的所有节点,将节点集合作为输入,遍历过程中对集合中的节点进行判断处理,比如是否为跳转,分支,结束等语句,要按照节点的类型来构造CFG。此处如果遇到循环语句和分支语句的跳转条件,则将其存储在CFG的边上,以便后续的数据流处理。本文中对于CFG边的处理要包含以下信息:边的来源,边的目的,边上携带的条件,边上携带的净化信息和编码信息。此外对于部分节点还要生成基本块摘要,以便在后续污点分析中使用。基本块摘要中包含一些关键信息(主要包含常量,全局变量,返回值,全局变量的注册以及数据流信息等)。
具体的CFG生成算法如下:
1.首先创建一个输入基本块,并为其构造一个输出边,连接到当前基本块,并作为当前基本块的输入边。
2.获取AST中的节点,若是只有一个节点,则将其加入基本块,生成相应的基本块摘要。如果包含多个节点,则对其进行遍历处理。
3.如果遇到函数定义类型节点类型则不对其进行分析。
4.如果节点是跳转类型的语句,则生成当前基本块摘要,并对每个分支建立其对应的基本块。首先创建一个新的基本块,然后获取分支节点进行遍历处理,通过递归处理构造分支节点的CFG。并以新基本块作为当前基本块。
5.如果节点类型是循环语句,则加入循环体构建基本块摘要。首先将循环条件加入到基本块中,接下来处理循环体,创建新的基本块,然后递归处理构造CFG。并以新基本块作为当前基本块。
6.如果节点是return语句,则将节点加入当前基本块,并构造基本块摘要,返回当前基本块。
7.如果节点是结束语句,则跳出循环,构造基本块摘要。
8.如果节点是其他类型的语句,则统一处理,将节点加入当前基本块。
9.如果当前基本块不是结束语句,则为当前基本块构造一条输出边,作为下一基本块的输入边,直至遍历完所有节点后,构造一个输出基本块。
运用该算法生成CFG控制流图,将AST生成便于数据流分析的中间表示,用于后续的污点分析。
污点分析是数据流分析技术的一种实践方法,在过去的几十年中数据流分析技术一直是信息安全领域的重要研究方向,其中有大量的工作研究制定数据流策略。
本文的污点分析是始于生成CFG的过程中。如果在生成CFG时发现了敏感函数的调用,则获取其中包含的危险参数,通过变量回溯的方法进行向上追踪,判断该参数是否来源于污点源中,并追踪其是否经过了净化处理来判断是否会产生漏洞。
污点源source,代表系统直接引入不可信的数据,多数时候是由用户输入获得的,用户的直接输入可以由超全局变量获取,超全局变量包括$_GET、$_POST、$_COOKIE等。当程序的敏感函数获取了用户输入的不可信的数据,就可能会导致污点型漏洞的出现。
污点汇聚点表示产生安全敏感操作或者泄露隐私数据到外界,也就是漏洞最终被利用的结果。如XSS漏洞泄漏了COOKIE,SQL注入漏洞泄露了数据库信息等。这些信息泄漏往往都是由于一些敏感函数的操作引起的,因此要对PHP敏感函数进行建模,敏感函数是导致漏洞的关键之处。本文针对PHP的漏洞检测所设置的污点汇聚点即是一些可能导致漏洞的敏感函数。其中跨站脚本漏洞的敏感函数点有‘echo’,‘print’,‘print_r’,‘exit’,‘die’,‘printf’,‘vprintf’等。SQL语句执行函数点包含‘dba_open’,‘odbc_do’,‘fbsql_query’,‘mysql_query’,‘pg_query’,‘sqlite_query’等,本文共统计并配置了五十余个函数,在此不一一赘述。
此外,在PHP代码审计过程中,若是发现了可控的危险参数,我们会立即去查看开发者是否对该变量进行了有效的处理,如过滤、转义或者编码等。如果没有处理,我们认为该处存在漏洞,如果经过了有效处理,则认为该处是安全的。在本文的静态检测方法中,也是遵循上述思路。为了降低系统的误报率,在设计过程中除了污点源和污点汇聚点外,我们还统计并配置了PHP中的安全函数。本文对PHP内置的安全函数进行了归类,如防止XSS的函数htmlspecialchars等,防止SQL注入的函数addslashes等。此外还有一些通用的防止漏洞的函数如intval等。如果危险参数在污点分析的过程中经过了安全的函数处理,就被视为经过了有效的净化。
采用PHP语言编写的各种应用程序中,其源代码会分成许多的源文件,程序运行时,通过文件包含方法来组合这些源文件。PHP的文件包含方式主要通过以下四个函数实现:include();require();include_once();require_once()。使用上述函数包含其他文件时,会获取到指定文件中包含的文本,代码和标记等,并会复制到使用include或require的文件中,包含的文件会作为PHP代码运行。因此在进行数据流分析的时候我们要考虑到文件包含的问题,进行多文件间的处理。我们在进行多文件间分析之前还要收集文件的信息生成文件摘要,文件摘要主要包含赋值语句的信息,以及相关的净化和编码信息等数据流信息。
本文对于文件包含处理的大致思路如下:
1.首先获取当前文件包含的所有文件名,获取其路径。
2.遍历包含的这些文件的文件摘要,检测是否有相关的数据流信息,如果有获取其变量名。
3.判断该变量是否是污点变量。
4.以此文件为当前文件,继续进行文件包含的处理。
本文的污点分析流程如图1所示,若在程序分析的过程中发现了敏感函数的调用,即通过回溯方法获得危险参数节点,由此进行污点分析。简单来说,就是判断该危险参数是否会导致触发漏洞。获得危险参数后,分析整体步骤如下:
图1 污点分析流程
1.首先检查该危险参数在当前基本块中的赋值情况,查询数据流信息中右节点是否有用户的输入的污点源,例如$_GET,$_POST等超全局变量。然后通过判断不同类型漏洞的插件类确认该节点是否安全。
2.若在当前基本块中未能检测到用户输入源,则进行多基本块之间的分析。首先对当前基本块的前驱基本块进行查找,在获取了前驱基本块后开始危险变量的分析。同步骤1),判断危险参数是否经过了净化处理,并判断其是否来源于污点源,如果是则报告漏洞。若当前基本块没有前驱基本块,则结束算法。
3.若在上述基本块间分析过程中未能发现漏洞,则进入多文件间分析。获取当前基本块之前的文件摘要的集合,然后对这些文件摘要进行遍历,并由此做出判断。
4.在执行以上过程中,若发现漏洞,则通过漏洞报告模块报告漏洞。若没有发现漏洞,则系统继续往下分析代码。
本文的测试集采用DVWA(Damm Vulnerable Web App)[11],DVWA是基于PHP和MySQL开发的Web应用程序,是一个漏洞实验平台,包含SQL注入,跨站脚本等,其漏洞数量是确定的,所以可以精准的确定误报和漏报。本文专对包含SQL注入和跨站脚本的12个程序进行检测,共分为三组,一组包含XSS漏洞,一组包含普通的SQL注入漏洞,一组包含SQL盲注类型的漏洞,每组四个程序,根据安全防护级别不同将其分为low、medium、high、impossible四个等级,其中low防护级别最低,medium次之,high防护级别较高但仍包含漏洞,impossible防护级别最高,不包含漏洞。实际检测效果如表1所示,其中Y代表检出漏洞,N代表未检出漏洞。
表1 实验结果
从上述结果可以看出,本文设计的工具对于SQL注入类型的漏洞检测效果较好,在包含SQL注入的8个文件中检测出6个确定的漏洞。但是对于XSS漏洞只检测出一个,产生了两个漏报。根据分析,对于Medium程序中使用了str_replace()函数直接将获得的