0×01 前沿) Q& X) r# @9 z. Y, s, E+ h; G. g
; q& ~3 G' a- F Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。
7 _+ h1 T6 v* w* {) U$ D2 g# w- q- R+ X1 Q) P9 S- }
0×02 写在前面的话
* G# G) n; c) g/ |3 e* a1 H0 K. E% B. m9 z, h
phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题
! u' o5 m' y$ b7 C8 v, k; y8 w
) x* K9 r: D* L9 q0 C4 P5 `7 f$ u这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
4 b, @: O! y+ s/ _) r. D. S+ K5 M8 |6 w
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论& ? }( W! i W4 V9 c
3 K# o2 J5 Q4 E0 c& G0×03 路径? ? ?. ?5 U6 B8 [* y5 G6 o& Y' N
) C( `9 }3 k8 g2 g3 P 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件6 _+ ?4 c; G/ _0 r% V7 E7 m
* @: t4 ^# S9 [9 d D) U0 [0 ^$dbclass = 'db_'.DB_DATABASE; require $dbclass.'.class.php'; $db = new $dbclass; $db->connect(DB_HOST, DB_USER, DB_PW, DB_NAME, DB_PCONNECT, DB_CHARSET); require 'session_'.SESSION_STORAGE.'.class.php'; $session = new session(); session_set_cookie_params(0, COOKIE_PATH, COOKIE_DOMAIN); if($_REQUEST) { if(MAGIC_QUOTES_GPC) { $_REQUEST = new_stripslashes($_REQUEST); if($_COOKIE) $_COOKIE = new_stripslashes($_COOKIE); extract($db->escape($_REQUEST), EXTR_SKIP); } else { $_POST = $db->escape($_POST); $_GET = $db->escape($_GET); $_COOKIE = $db->escape($_COOKIE); @extract($_POST,EXTR_SKIP); @extract($_GET,EXTR_SKIP); @extract($_COOKIE,EXTR_SKIP); } if(!defined('IN_ADMIN')) $_REQUEST = filter_xss($_REQUEST, ALLOWED_HTMLTAGS); if($_COOKIE) $db->escape($_COOKIE); } if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } " D& e2 @5 B, W" S
' E! i6 v; }6 K这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的
7 a7 i' N5 b: m. h
- u; ]/ N" |' r6 P2 I4 |8 Z5 w然后就是将我们传进来的参数进行变量化
+ Y4 U9 ]0 e) [9 ?$ a
# y7 m, W' s2 K* F3 q这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
5 r9 B/ W) r; v
+ ]% ~) F/ v( g* M, s Y8 u1 Y但是接下来这行呢?
9 B4 a& R) P9 Z& |% b
5 O1 j) ?$ @3 L+ b# j 6 ^ j/ x9 p, q6 P6 K
( H2 j2 e- H# g' ]# D& P
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } : b; f1 D: p2 |9 l( @% ]
/ ^/ o+ Q0 k8 F" }) w Z
, j7 T. ~, y0 V" D$ D
) k, \# ?# |0 \ G4 o: m) I
看看这里?, G+ @# A0 L/ a' S' G6 d* R
+ B/ [' m7 z, s1 s这里的QUERY_STRING来自前面
1 s8 a1 ]: L- r! f3 T0 }
8 j7 c4 \0 I6 B- d* o+ v6 ]
: l, K4 N8 d0 l w9 D
& e7 F2 t2 k8 M+ _ Odefine('IP', ip()); define('HTTP_REFERER', isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''); define('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : preg_replace("/(.*)\.php(.*)/i", "\\1.php", $_SERVER['PHP_SELF'])); define('QUERY_STRING', safe_replace($_SERVER['QUERY_STRING']));( f. ]! f- U4 Y3 j& I
这里有个过滤,但是不影响/ ?' U/ n/ d+ ]6 Q! e. k4 U% w k, h
X* q! `! p9 v" N" n; S
如果我们在这里进行覆盖这个db变量呢
5 R7 M$ @$ R3 k2 f
z; G: Q2 n! v' o# `因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));$ W$ o' W4 D/ L3 L+ c2 U3 q0 g' g
* _' S) }; E1 X/ w6 y可以将我们传进去的/ - 进行替换
7 [$ @5 t4 t$ |$ G3 V9 t* r5 B H# Z8 F! N% J) c* d6 o
所以我们如果提交如下字符
) E3 }$ I* ~1 C7 g* i
. d* x, q3 M+ E q- ehttp://localhost/phpcms/index.php?db-5/gid-xd.html6 J3 B6 S9 u4 g* ]) u+ O& m
1 x3 \9 @1 ] A N1 j- Z) f2 b
他由于这个db被覆盖就会出错,所以物理路径就爆出来了% \+ \& }# p6 z% d0 I0 a
: t/ x& F f/ }2 n# U. l8 ~) p
0×04 SQL注入!!!
/ J& c# y N9 K, @# m) S
) E0 n: p+ z3 C7 G0 @ 在c.php中
1 M+ ^; f0 w3 g5 X. p1 L7 w7 l) o+ ~4 L8 W: p" f* ^! [# K
8 o, |) x6 ~, v
9 o" U# p7 R3 x5 ~& w t3 H
<?php require './ads/include/common.inc.php'; $id = intval($id); $ads = $c_ads->get_info($id); if($ads) { $db->query("UPDATE ".DB_PRE."ads SET `clicks`=clicks+1 WHERE adsid=".$ads['adsid']); $info['username'] = $_username; $info['clicktime'] = time(); $info['ip'] = IP; $info['adsid'] = $id; $info['referer'] = HTTP_REFERER; $year = date('ym',TIME); $table = DB_PRE.'ads_'.$year; $table_status = $db->table_status($table); if(!$table_status) { include MOD_ROOT.'include/create.table.php'; } $db->insert($table, $info); $url = strpos($ads['linkurl'], 'http://')===FALSE ? 'http://'.$ads['linkurl'] : $ads['linkurl']; } e" `* a, v$ _' A6 s
; b) \" j! o. Z& ] 9 E+ z* r; m+ z+ I x
$ z. H% ~. Q2 B$ ?- y
注意这里的HTTP_REFERER这个常量
9 Z0 e4 P3 ~; n! s- _3 b. T
7 @" F1 K$ F+ A1 @3 l+ i4 d这里的常量是通过前面的common.inc.php定义好的
) a8 O- |! A! Q' i" l' E
; d/ C* V9 p' idefine(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);
9 Q3 F! |) ]! v9 ]9 P8 c" c B4 q% J3 p+ ?- Z1 `
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我6 \" `& V' ? X3 j) S5 ]
O' d( I1 t0 P1 G: |0 J
然后' g L3 s" o( V* A
5 q9 X4 r1 s: {' O# r* H h* T9 q
$db->insert($table, $info);
/ o6 h/ o L7 k5 S0 h, F我们来看一下它这里的操作
' q6 L' b& K$ f) v$ i" k0 _9 H7 l6 v
function insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
5 i9 T! g% f: o/ h4 E
( D+ I% N. ^4 n& L0 U( g, {所以你懂的
0 ?$ R! E! M$ {/ w3 S1 U( w
I- d7 T: @' t
5 _* P$ Y! c) C* j+ o
. N# [, n- y$ Q" p& y附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737
% X/ n! \" Z* O+ `1 B& w6 p8 I7 v2 i( o7 I3 e
1 t L c3 S; H! }! P. d
* O* n0 y# s3 g9 F- T |