文章题目: Simulation of Built-in PHP Feature for Precise Static Code Analysis.
作者: Johannes Dahse & Toorstem Holz
RIPS研究PHP静态分析几乎绕不开的工具, 一是选择的时间点好,2014年左右PHP还是比较火的。二是工具确实不多。 这篇文章发了14年的NDSS,还是有些东西值得借鉴的。
技术背景
首先, 作者在技术背景部分分析了一些PHP这种highly dynamic lanuage的痛点。
1) 动态类型/弱类型
脚本语言在变量声明时不用声明类型的确给静态分析带来不少麻烦,而动态类型指的是在运行时类型是可以变得(its variables are not bound to a specific data type).
1
2$var1 = 1; $var2 = 'test';
$var2 = $var1 + $var2; //1- variable Variables
这个貌似是PHP独有的,叫$$特性?
1
2
3
4$name = "x";
$x = "test";
echo $$name; //test
$y = ${getVar()}; //变量名可以是一个表达式ZZDynamic Arrays
动态数组,PHP的数组是hash table实现的。可以存任何不同的数据类型,而且在初始化的时候key值可以省略在运行时指定。
注意这里新添加的自动索引了6, 神不神奇?会按照“4”开始算,把"4"改成"664"就是'e'的索引就是666。(还是说脚本语言的不规范性)
Dynamic Constants
通过define()在于形式动态定一个常量, 通过constant()运行时访问。
- Dynamic Function
function动态调用, 这个说的就太多了。
第2行向我们讲述了, 不仅变量名可以是表达式, 方法名也可以是表达式; 第三行是一个回调函数,在动态的时候才知道执行啥。另外,还有fun_get_arg()
和func_get_args()
在运行时动态从call site拿参数; create_function()
动态创建一个方法体org。
Dynamic Code
动态执行代码, 通过
eval
,assert
,小马常用到。这些代码在动态运行时才能知道, 给静态分析增加了难度。
Dynamic includes
这个吐糟也比较多, 大型PHP项目尝尝被分割成若干文件和目录,他们的拼接为静态分析也增加了难度。类似
include
,使用这种操作,将文件中的代码返回到include处。尤其是现在又加了惰性加载机制。autoload()这种在静态分析目前只有猜了。
- Built-in Functinos
如图,第二个位置月份可以是字符型, 这里如果要能探测到XSS就要对list(), printf()进行精确建模。
Superglobals
我们的超全局变量, 需要精确的标明哪些可控。开发者经常忽略FILES和SERVER的安全性。
方法设计
纵览
还是文件为单位, 首相将散乱在文件中的代码解析成main AST(脚本语言通常没有main方法做入口), 然后将user-defined function们收集起来, 将函数名, 参数等信息存入分析环境, 然后将其函数体构建成separate AST独立于main AST。
有了 AST, 下一步构建CFG(控制流图), 分析AST如果发现
conditional jump
, 就开辟一个新的基本块(basic block
);并使用basic edge
相连接。有了CFG, 下一步构建PDG(数据依赖图)咯, 以基本块为单位,每当一个BB产生, 就分析一下他的
adta flow
。实现Intra(过程内)和Inter(过程间)分析,当遇到
call site
就在环境中找到该方法名并进入其AST进行分析,从而实现inter
能力。实现污点分析。
(说的挺复杂,开源版的RIPS的基础分析能力还是以分析tokens流并以各种数据结构辅助追踪为主)
创新点
那么本paper novel在什么地方呢:
- 在污点分析时添加了sanitization tags来表明数据被过滤
- 为952个内建方法建模,从而更精准的把控整个分析流的变化
- 在处理include file时,当作functions来处理,而不是直接加入到当前CFG,防止重复分析, 减少开销
- 根据基本块边来总结他们之间的sanitization影响
- 实现了后向污点分析,每一个基本块的分析结果,cache到一个变量里。
- 使用上下文敏感字符分析(context-sensitive stirng analysis)来精炼污点分析结果,基于当前环境。
CFGBuilder
要构建一个CFG, 先定义statements, 划分基本块。
这里作者定义了几种划分基本块的stmt, 配合算法:
中间的循环AST上的每一个点,如果遇到四种stmt的情况。
JSTMT, 遇到IF, Switch, Try, Ternary, LogicalOr(后两个没见过), 就递归分析每个分支下的基本块。将入口条件加到基本块头。
LSTMT, 生成循环基本块
SSTMT, 停止,基本块下的stmts不可达
RSTMT, return,到达return或者是探测到程序退出,就不和下一个基本块建立连接。
这里增量在
simluate()
方法上,来看。
simulating Basic Blocks
静态分析能干的事,就是编译器或者解释器能干的事。 RIPS为获取基本块内的data flow, 在控制流的基础上进行所谓的simulating,实现simulating:
- 制定symbols: 值-val, 变量名-varibale, 常量-constant, 数组-ArrayDimFetch... 每一个symbol都会有几个状态(type, encoding, sanitization),通过观察状态变化做到对类型,编码以及sanitize的敏感。
2)Block Summary: 此过程就是将制定的符号集在块中使用进行后向追踪。生成一些块属性(block Summary):
* DataFlow - 记录变量/数组的assign
* Constants - 记录常量的assign
* GlobalDefines - 记录名称,加入global scope
* ReturnValue - 记录块中的返回值(每个块一个返回, return和exit后的代码丢弃)
* registerGlobals - 记录使用extract()或者import_request_varibales()注册变量
在每个块的后向data flow分析后记录以上内容, 生成block summary.
Data Flow Analysis
Simulating Includes and Dynamic Code: php 的includes是一个动态表达式,通过路径去找,找到加入,若无正则匹配。eval同理。
Simulating Built-in Functions:
本文重点。 对621个内建函数进行数据流建模, configured name and effected parameters. 分类如下:
- Alphanumeric(284): 返回值只有字母数字组成的,effectively sanitize. 如: md5(), strlen()
- Argument(122): 原样返回实参或部分的, 如: trim(), strrev()
- escape(20): mysql_real_escap_string()这种, 遇到将symbol中的sanitization属性打上SQLI_SQ 和 SQLI_DO标签(如果没遇到就SQLI_NQ)
- Substring(6): substr(), chunk_split()这种,返回实参字串的。
- Encode(18): urlencode(), base64_encode() ...
- Decode(25): urldecode(), base64_decode()...
- Callbacks(51): 回调函数,如果调用函数名事字符串,就调用分析。如果是变量,正则猜测。
Intra-produral Analysis
实现intra
Inter-procedural Analysis
实现inter
Simluating Block Edges
块与块之间的simluating, 考虑validation的情况
- operators(6): isset(), empty()...
- Type checks(21): is_numeric()...
- File checks(11): is_file()...
- Whitelists(3): array_search()
- Regex(8): 正则
(原来validatation的情况可以放到块与块间,这样就和sanitization的情况分开来去了)。
Taint Analysis
污点分析探测漏洞的过程略。:>
后记
之前看这篇觉得没啥东西, 仔细分析来东西还是挺多的, 毕竟顶会。
他几乎把所有语言特性层和面向过程层的东西讲到了, 缺少OO层的分析,也是后来不上人针对发文的。
(为什么看起来这么高大上的东西开源版本用起来和...一样)