0×01 前沿
! x7 v) ?* U/ u7 o0 ~8 k; l2 f6 a" `) ?8 C
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。" z+ _2 @; _- F( \9 _0 D& ]* Z9 _% A
& D, r8 p* B6 Q7 Z7 H( }0 \
0×02 写在前面的话
6 Y4 ?3 v- j9 y; E$ X- w- K! a; |* z0 y, c8 r
phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题* f- j C" N4 j! d+ m, K4 v5 ^! r' u
" i* P4 G z( _0 C6 d这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强4 O% p9 F% }( y" P2 G
) L. w! [- p G: A$ m$ { \
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
$ ` P! F: n$ U: f5 d: x7 A
, g7 p0 P" T8 o9 I; G0×03 路径? ? ?- [: t+ n6 V# F& K6 s* ~7 f9 G
. M/ s5 [1 S9 Q# i1 S
在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件( _# _" e9 S) H, P
$ {: m+ r8 ?3 y& \$ L) d$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])); } 5 Y# f+ X4 L* V! A, s
9 |5 g( V( s% v& j这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的7 O; v' j( M4 y# ^$ q7 n' }
1 }7 H$ A: W: }/ _
然后就是将我们传进来的参数进行变量化" S+ \9 t) D2 e6 [' ~
- m8 A" v3 R' _! K
这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
" w, I) u- z2 z/ q% j5 I/ v1 A; O" S! a4 e! j: x' u2 Z
但是接下来这行呢?: ^7 @7 s% q& Y, J2 C* e6 S
: @9 }/ A7 J! v4 G) N, {
% R" s" v2 M5 O' {% x% b" K1 I* B2 V- P' n
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } % ^4 z2 X6 X# E! Z3 q6 ^, p2 K5 n
1 a& H# t: ~9 e# W
2 [# l7 s6 i1 N; q) O$ q# q" \' z# d' e. V) Q0 z/ l
看看这里?2 ]& }/ i) g2 b1 I! |
$ p; S; \; q' K. `这里的QUERY_STRING来自前面4 v# i: x3 u# [- \, O: s
2 k" t& |( b& d; j) j
3 ?% x! A( p2 A, a6 ]
/ G, F$ z; \; Z# {3 ]5 R7 N) tdefine('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']));
# t; K9 [7 i1 w7 L; q/ b) G3 G5 y- ^3 [* E这里有个过滤,但是不影响( d$ n" b$ R7 k' V7 I$ m' K
9 q T& m; Z2 ~6 B* {' k" v
如果我们在这里进行覆盖这个db变量呢: ^' A' Z2 }" l5 ^/ ? q
) e2 z; W1 [/ G& T9 U7 c
因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));
; ~/ B7 ~/ q$ D) c, ~6 m9 L( Y* R1 B. A" `, p0 K# L
可以将我们传进去的/ - 进行替换
4 K9 C; L1 _0 l% @1 W" y& y8 L) t4 J w' _- s5 o( x! ?
所以我们如果提交如下字符) d1 X9 B2 x0 c2 h$ E6 T5 d
2 D. r" r; o' `6 i7 ~# S+ n
http://localhost/phpcms/index.php?db-5/gid-xd.html
+ ]0 d! i) N% f. x( U* G O2 l5 N* L3 j. }7 p6 g
他由于这个db被覆盖就会出错,所以物理路径就爆出来了
/ a$ v& n7 ~* {( c1 ]2 @+ Q# D* x9 U. G4 s: J; `
0×04 SQL注入!!!
+ v& r' A: B# C$ Z2 P
) s3 z8 c$ r' ?& F7 D 在c.php中
8 S2 a4 e) n$ N7 y( ?6 {4 f# q
& b ^& h$ \- B! S6 @
2 V2 [; w0 |: A/ u* h6 l) \+ {: X$ c4 y$ L) L, G5 h2 U
<?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']; } $ i/ |+ z! R8 v8 ~7 O
& H. [$ [0 f2 X; z0 h J 4 X+ p4 D! }: h, k
a0 B# K" ^' u! b/ ~# t注意这里的HTTP_REFERER这个常量1 v0 L, V( z, D) ` I4 i& K
* f# u# M {! M; J0 N
这里的常量是通过前面的common.inc.php定义好的 I3 D; z3 p$ I
5 ?2 {' y+ I. U; X; pdefine(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);( ? J$ S: D0 }) U1 }4 t" |
. R. v, k8 g K. @" p3 h) i没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我
6 B+ P r9 L! Z( z3 g0 z; s$ s! P: O
' ?6 w/ j! \$ z$ Z2 @然后$ V: n y; Z( U5 S3 s6 \
# N. y* Y- n/ D/ s l7 c" g2 _! g8 o
$db->insert($table, $info);9 E) o+ U% e! _& V5 E
我们来看一下它这里的操作
/ C8 }: y0 D1 N! \8 h2 F& i+ |( c& Y
7 v& ~/ f5 D4 U, R# }4 M; Ufunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); } " u* F& T2 e' Y# z9 h
8 m4 S _& q1 W: z% D( K5 f' @所以你懂的- Z$ J' M) m. L5 d
) P8 G3 A1 A0 t: Q 0 ]9 f# l. ^: j" c7 |& T
6 p1 I8 m/ O4 L7 l# f5 `0 b6 _附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737
) m3 w7 K% |) h9 ^3 K, v: m9 w4 L5 G5 k2 H8 {
, W9 R, ^0 @6 ]7 ^4 `! t% v$ X. S. F5 A7 r3 X
|