一篇文章带你了解PHP静态分析工具RIPS
字数 2766 2025-08-24 23:51:09
PHP静态分析工具RIPS深入解析
一、RIPS工具概述
RIPS是一款用于PHP代码静态分析的开源工具,主要用于检测PHP应用程序中的安全漏洞。其核心功能包括:
- 静态分析能力:通过解析PHP代码的token流来检测潜在漏洞
- 漏洞检测范围:支持15种预配置的漏洞类型(3种客户端+12种服务端)
- 开源版本:本文基于RIPS v0.55开源版本进行分析
二、核心架构与处理流程
1. 整体处理流程
RIPS的静态分析过程主要分为以下几个阶段:
- Token流解析:使用PHP内置函数
token_get_all()将源代码转换为token数组 - Token流重构:对原始token流进行标准化处理
- Source识别:识别用户输入点
- Sink识别:识别危险函数调用
- 污点分析:追踪数据从source到sink的传播路径
2. Token流解析与重构
RIPS使用PHP的Tokenizer类(位于lib/scanner.php)进行token处理,主要包含以下重构步骤:
(1) prepare_tokens()
function prepare_tokens() {
// 删除空白和无关token
// 重写特殊token(如将<?=重写为echo)
// 处理@错误抑制符
// 将$array{index}重写为$array[index]
}
关键处理:
- 删除PHP开始标签
<?php和空格 - 将闭合标签
?>替换为分号; - 将
<?=标签替换为echo - 删除错误抑制符
@ - 将数组花括号语法
$array{index}转换为方括号语法$array[index]
(2) array_reconstruct_tokens()
function array_reconstruct_tokens() {
// 处理多维数组
// 将数组键名信息存储在token数组的第4个元素中
}
处理示例:
- 对于
$a[$b][][],将所有维度的键名存储在$atoken的第四个数组元素中
(3) fix_tokens()
function fix_tokens() {
// 处理反引号`xxx`转换为backticks()
// 重构控制结构(if/for/foreach/while等)的花括号
// 函数名小写处理
// 处理do-while结构
}
关键处理:
- 将反引号
`command`转换为backticks(command) - 为没有花括号的控制结构添加花括号
- 统一函数名为小写(PHP不区分大小写)
- 将do-while结构转换为while结构
(4) fix_ternary()
function fix_ternary() {
// 处理三元操作符
// 删除?前面的判断条件,只保留两种取值情况
}
3. Source与Sink识别
(1) Source点(用户输入)
RIPS定义的source点主要包括三类:
- Other Input:HTTP头部、超全局数组等
$_GET,$_POST,$_COOKIE,$_REQUEST$_SERVER中的特定参数
- 文件输入:从文件中读取的数据
- 数据库输入:从数据库查询获取的数据
(2) Sink点(危险函数)
RIPS预定义了15种漏洞类型的sink函数:
客户端漏洞(3种):
- XSS:
echo,print,printf,die,exit等输出函数- 过滤函数:
htmlentities(),htmlspecialchars()等
- 过滤函数:
- HTTP头注入:
header(),setcookie()等 - 会话固定:
session_start(),session_id()等
服务端漏洞(12种):
- 代码执行:
eval(),assert(),preg_replace()(带/e修饰符)等- 过滤函数:
preg_quote()
- 过滤函数:
- 反射注入:
include,require等 - 文件读取:
file_get_contents(),readfile()等- 过滤函数:
basename(),realpath()
- 过滤函数:
- 文件系统操作:
unlink(),mkdir()等 - 文件包含:
include,require等 - 命令执行:
exec(),system(),passthru()等- 过滤函数:
escapeshellarg(),escapeshellcmd()
- 过滤函数:
- SQL注入:
mysql_query(),mysqli_query()等 - XPath注入:
xpath_eval()等 - 反序列化:
unserialize() - LDAP注入:
ldap_search()等 - XXE:
simplexml_load_string()等 - 其他危险函数:
extract(),parse_str()等
三、污点分析实现
1. 变量追踪
RIPS通过variable_add()函数跟踪变量赋值:
function variable_add($var_name, $tokens, $comment='', $tokenscanstart, $tokenscanstop, $linenr, $id, $array_keys=array(), $additional_keys=array()) {
// 创建VarDeclare对象存储变量声明信息
// 根据变量作用域(全局/局部)存储变量声明
}
处理逻辑:
- 创建
VarDeclare对象存储变量信息(tokens子集、行号、token索引等) - 根据变量作用域(函数内/外)将变量声明存入相应列表
- 处理全局变量
$GLOBALS['x']转换为$x
2. 函数分析
当扫描到函数定义时:
else if($token_name === T_FUNCTION) {
// 处理函数定义
// 记录函数名、参数、位置等信息
// 检查是否为POP gadget(反序列化利用链)
}
关键处理:
- 创建
FunctionDeclare对象存储函数信息 - 记录函数参数(用于参数追踪)
- 检查是否为POP gadget(反序列化利用链中的方法)
3. 动态函数调用检测
RIPS通过variable_scan()检测动态函数调用:
function variable_scan($i, $offset, $category, $title) {
// 检测变量作为函数名调用的情况
// 如$func = $_GET['f']; $func();
}
处理逻辑:
- 创建
VulnTreeNode记录漏洞信息 - 追踪变量值来源,检查是否包含用户输入
- 如果发现用户输入作为函数名,标记为代码执行漏洞
四、实际案例分析
1. 动态函数调用漏洞检测
示例代码:
$a = $_GET['tr1ple'];
function test() {
$a();
}
RIPS检测流程:
- 扫描到
$_GET['tr1ple']标记为source点 - 扫描到
$a()函数调用,进入variable_scan() - 追踪
$a的值来源,发现来自$_GET - 标记为代码执行漏洞
2. 数组键名处理
示例代码:
$a = array("key" => "value");
echo $a["key"];
处理流程:
array_reconstruct_tokens()将数组键名"key"存储在$atoken的第四个元素中- 访问
$a["key"]时可以直接获取键名信息
五、工具局限性
- PHP版本:开源版本较老(v0.55),不支持新版本PHP特性
- 漏洞覆盖:
- 缺少CSRF、SSRF、XXE等漏洞检测
- 无法检测越权等逻辑漏洞
- 反序列化仅检测
unserialize(),不检测phar反序列化
- 误报/漏报:静态分析固有的问题
六、扩展建议
- 添加新漏洞检测:
- 实现SSRF检测(
file_get_contents()带URL参数等) - 增强反序列化检测(支持phar)
- 实现SSRF检测(
- 改进分析算法:
- 实现更精确的跨文件分析
- 添加过程间分析能力
- 支持新PHP特性:
- 命名空间
- 匿名函数
- 类型声明等
七、总结
RIPS作为PHP静态分析工具,其核心价值在于:
- 完整的token流解析与重构流程
- 精心设计的source与sink点定义
- 实用的污点分析实现
- 对PHP语言特性的深入理解
通过研究RIPS的实现,可以学习到:
- PHP静态分析的基本方法
- 如何设计一个实用的漏洞检测工具
- PHP语言特性与安全漏洞的关系
- 静态分析工具的常见挑战与解决方案