web渗透者习惯采用黑盒或灰盒的方面来检测一款web应用是否存在漏洞,这种检测方法可以屏蔽不少漏洞,特别是程序逻辑中的漏洞。但如果能配合白盒的源码审计(也可以叫漏洞挖掘),效果将会更好,当然人力成本也会增加,其中,对于源码审计工作将交给谁做,是比较争议的话题,是开发、测试还是安全人员呢?
个人觉得,开发若能做一下粗略的源码自查,然后安全(弱没有安全人员,就交给白盒测试人员)负责做整体的源码审查,将是极好的安排。
除了人力成本,还有一个信任的问题,是否愿意将源码开放给安全人员?这比较敏感,但从技术角度来看,掌握源码审计的技巧是非常棒的加分点。
本篇文章将介绍两种开源的PHP源码审计工具,其中Taint适合开发源码自查,RIPS适合安全源码审查。
1、介绍
可用于php源码审计,对快速定位漏洞有帮助
2、安装
第一步:下载安装taint
wget http://pecl.php.net/get/taint-1.2.2.tgz (下载最新的taint) tar zxvf taint-1.2.2.tgz cd taint-1.2.2 phpize(如果找不到该命令,需要apt-get install php5-dev) ./configure make make install
第二步:修改php.ini配置文件,使其支持taint模块
vim /etc/php5/apache2/php.ini
增加
extension=/usr/lib/php5/20090626+lfs/taint.so taint.enable=1 display_errors = On error_reporting = E_ALL & ~E_DEPRECATED apache2ctl restart
注意:只能在开发环境开启该扩展
第三步:测试该模块是否开启
vim phpinfo.php
<?php phpinfo(); ?>
如上图所示,则表示成功开启该扩展
3、测试(以DVWA 为主要测试对象)
实例1:sql注入漏洞
$user = $_GET['username']; $pass = $_GET['password']; $pass = md5($pass); $qry = "SELECT * FROM `users` WHERE user='$user' AND password='$pass';"; $result = mysql_query( $qry ) or die( '<pre>' . mysql_error() . '</pre>' );
运行页面,警告信息如下所示
Warning: mysql_query(): SQL statement contains data that might be tainted in /var/www/dvwa/vulnerabilities/brute/source/low.php on line 11
如果PHP源码使用以下函数,则不会发出警告
mysql_real_escape_string (不转义%与_) stripslashes is_numeric
实例2:命令执行漏洞
<?php if( isset( $_POST[ 'submit' ] ) ) { $target = $_REQUEST[ 'ip' ]; // Determine OS and execute the ping command. if (stristr(php_uname('s'), 'Windows NT')) { $cmd = shell_exec( 'ping ' . $target ); echo '<pre>'.$cmd.'</pre>'; } else { $cmd = shell_exec( 'ping -c 3 ' . $target ); echo '<pre>'.$cmd.'</pre>'; } } ?>
运行页面,警告信息如下所示
Warning: shell_exec(): CMD statement contains data that might be tainted in /var/www/dvwa/vulnerabilities/exec/source/low.php on line 15
实例3:文件包含漏洞(常伴随着目录遍历漏洞)
<?php $file=$_GET['file']; include($file); ?>
运行页面,警告信息如下所示
Warning: include(): File path contains data that might be tainted in /var/www/dvwa/vulnerabilities/fi/index.php on line 35
实例4:xss漏洞
<?php if(!array_key_exists ("name", $_GET) || $_GET['name'] == NULL || $_GET['name'] == ''){ $isempty = true; } else { echo '<pre>'; echo 'Hello ' . $_GET['name']; echo '</pre>'; } ?>
<?php $cmd=$_GET['cmd']; eval("$cmd;"); ?>
实例6:文件读取操作
<?php print "<h2>Number 3: file() functions: </h2>"; $path=$_GET['path']; $contents=file($path); foreach ($contents as $line_num => $line){ echo "Line #<b>{$line_num}</b> : ".htmlspecialchars($line). "<br>\n"; } ?>
ps:检查某些关键函数(是否直接使用(没有经过过滤或转义处理)了来自$_GET,$_POST,$_COOKIE的数据,如使用则给出提示。”
代码编写安全准则
1.不轻易随意使用eval等危险函数
2.不得直接GET POST COOKIE 调用参数操作参数
3.任何接口均以使用随机加密算法或是 dz的KEY对等加密
所以从某种意义上来说只要遵守以上准则 Taint未必能检测到2阶利用问题
防御角度:可以理解为 主动(代码审计) 和 被动(Taint检测提交)的防御方式 任然有缺陷
xxx角度:但从利用挖掘上来说最好 debug插件(变量跟踪) 结合RIPS 代码审计 就比较清晰了
附录:
A. Tainted String
所有来自$_GET, $_POST, $_COOKIE的变量, 都被认为是Tainted String
B. taint检测的函数/语句列表, 当这些函数使用tainted string参数的时候, taint会给出警告:
1. 输出函数/语句系列
- echo
- printf
- file_put_contents
2. 文件系统函数
- fopen
- opendir
- basename
- dirname
- file
- pathinfo
3. 数据库系列函数/方法
- mysql_query
- mysqli_query
- sqlite_query
- sqlite_single_query
- oci_parse
- Mysqli::query
- SqliteDataBase::query
- SqliteDataBase::SingleQuery
- PDO::query
- PDO::prepare
4. 命令行系列
- system
- exec
- proc_open
- passthru
- shell_exec
5. 语法结构
- eval
- include(_once)
- require(_once)
C. 消除tainted信息的函数, 调用这些函数以后, tainted string就会变成合法的string:
- escapeshellcmd
- htmlspecialchars
- escapeshellcmd
- addcslashes
- addslashes
- mysqli_escape_string
- mysql_real_escape_string
- mysql_escape_string
- sqlite_escape_string
- PDO::quote
- Mysqli::escape_string
- Mysql::real_escape_string
D. 调用中保持tainted信息的函数/语句, 调用这些函数/语句时, 如果输入是tainted string, 则输出也为tainted string:
- = (assign)
- . (concat)
- “{$var}” (variable substitution)
- .= (assign concat)
- strval
- explode
- implode
- sprintf
- vsprintf
- trim(as of 0.4.0)
- rtrim(as of 0.4.0)
- ltrim(as of 0.4.0)
E. 链接:
- RFC:Taint (想法主要来自这个RFC)