0×01 前沿9 H2 Q9 X2 T' \& A
+ q% m, G5 P2 o4 f- G Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。' [1 ?& Z! n* c3 ?& T7 j, f8 p& C# ?
1 C+ v+ c; y1 D6 k0 M8 N5 V
0×02 写在前面的话
0 `9 G# V( a9 D6 A, S" }' W% p! C' i/ J
phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题9 q2 Y, t' K; ]1 t
$ @9 Q8 f1 g! i
这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
" I1 k* j; S3 t: v( I J5 d& k* h2 S- C, X- t4 ?( F6 a2 d
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
& I0 c" f3 _$ D: Q* Y {3 c$ U6 E( P! Y
0×03 路径? ? ?
# R) n% u! Q: k- w8 R4 T
& K6 F- Z/ ~, B& `6 a$ n 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件1 W* l2 ]; _4 q( f4 _
1 c$ z7 B% U0 {6 E
$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])); } " t3 u. e! N' A
4 u. L4 @; Q% J' a& I' q这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的/ L7 k0 Y w" ~
1 F) }2 R- c# `/ x然后就是将我们传进来的参数进行变量化- L3 o% V! Z; H* T/ P
: q' M0 a9 n( K: E. W这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量' w& l% J# r% j3 a; q1 W+ i
" H3 P; T1 _( _9 O! e) P
但是接下来这行呢?
, `: h9 B5 \1 O4 B7 a7 r7 h
0 S1 T d T& J
( Y3 @; K G/ s# ]+ y% s0 j. e4 V9 o7 Q) O! s
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } # @. [! i! P+ a- W
% [- ^6 x6 J0 y" ~' r
3 | B. L& g5 c2 o+ r* e% x" B; ?1 o% j
( \: j* n8 l$ x3 Y' F5 A看看这里?
: V5 {2 m+ `/ W( j! o5 z0 e- M) \0 I- k* n2 c9 T# Z
这里的QUERY_STRING来自前面( D+ g# L3 P! C
9 h1 ?& [/ O3 i! r$ S0 l8 t
# P1 I5 I1 u# M& s6 _
8 o- z6 |+ U, M# x7 y5 Z
define('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']));
, k5 `2 X) j; Z5 K+ j1 d0 c这里有个过滤,但是不影响
0 [& ~5 m8 U0 ?5 f9 K4 y4 p; o- B6 z& P: E$ W$ K
如果我们在这里进行覆盖这个db变量呢
% Q7 R/ _' S4 ^3 P! ?
3 A1 g: x2 s( ?- M: ~( \因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));% O4 j0 f+ d1 v8 b
; P7 }$ f+ T3 z. d( z$ c可以将我们传进去的/ - 进行替换6 j4 A S: ?3 J" O
. i+ C7 p5 j1 \9 P# _; k# R9 f所以我们如果提交如下字符. T* f% p' M* f2 X2 M, D: [
9 f2 _& Y6 g. `1 Chttp://localhost/phpcms/index.php?db-5/gid-xd.html$ M# M/ k$ ]+ E/ w8 C! |. \3 k- R# L- f
+ U2 j+ m- ^! m" e; T! i c7 P3 X" \
他由于这个db被覆盖就会出错,所以物理路径就爆出来了. _+ O( C: A7 @6 H3 q# m
0 s, a. @6 d/ ~6 k9 \; _) z
0×04 SQL注入!!!
6 N, s% S2 w% T( w# L4 P) v3 p: e: \; O+ f5 b( f/ M, p/ I1 q
在c.php中2 F0 x6 z( R7 [9 J
8 G4 B- ~' T' I( |$ d
: R' }& A$ ^! K6 u
: F4 ]1 I A! |3 R& a2 C$ ^9 m" Z<?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']; }
! x8 l, Z" H M+ q; c1 d
8 g' d+ N8 q' c ' {7 c: Q* B$ W I- I
* _1 y, {6 B1 p' @+ y. w, g2 M4 k注意这里的HTTP_REFERER这个常量
: G" S/ _6 D7 S! | F3 f! S% R0 [1 b2 E; N& ?4 {; z" ^
这里的常量是通过前面的common.inc.php定义好的
* G2 I) g& g! Q W8 d$ _/ W: \
0 z, ]+ s0 ]& i2 A9 O: |& z% `- xdefine(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);0 w* R4 s( i% ]% a5 L9 N
0 O" ?$ S& j! V没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我) V; }/ O0 ?. G$ u; e; @% u
6 g- B( m, T* D3 Q
然后* @- A+ Z& q- u/ y# Y& a
6 h: p( w1 T0 ]0 P$db->insert($table, $info);
4 K; E2 `" S8 w/ z9 T0 Q8 N我们来看一下它这里的操作, |5 A# {0 k- F' n& X1 i9 ]/ L
: x. f. l3 E" {1 Y+ N7 X$ w9 jfunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
" V3 ~* [. _( W6 @; V5 F
L( o3 c `" z$ I. h0 ~所以你懂的$ ~# I2 u2 P" S# E: Q8 @
) a9 \$ B0 r8 j* ^! R, \
! q/ L' M( l$ F a& K' u
* u( v. Y) [. a, L- M* {- @附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737! ], o* i/ d1 l- |
3 r- _$ {3 e4 `9 P: e
1 q0 @0 E. M: |# C" [0 n& P7 t3 l: W9 ]+ z
|