0×01 前沿
* r8 w% C+ \8 D! F6 R& J* u$ c, U+ K# \5 ^4 G; Z9 ?
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。
4 G4 m# Y! ?2 t9 t3 ]8 L: |+ V% P& i! h% P
0×02 写在前面的话
h2 U, v9 y4 o, I
% `1 n. I& @+ y I& ]) ` phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题
! G: y6 z6 W" Y, B. |/ j' D! z0 O: U" N$ t, g5 y
这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强1 W- V' Y; s/ H( G1 E
* o% s7 ]9 c/ l- f3 G6 C0 `2 j E
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论% J- u' g8 s) L: t
& ?/ l. K: @4 K. |! P/ u1 m- _% r
0×03 路径? ? ?- p# J5 D+ R! O
; a, e3 M G, `. M0 u" U; k) h 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件: ? F3 J- c0 o7 n4 l) `! V
& A1 l& I8 n/ m7 G: f$ F% p$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])); }
9 A$ v/ P( }( |# C. e6 P, X( c* `8 L, ?( V5 ^+ I
这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的
8 [# M! T1 G4 p- o; g6 Y8 I0 I w7 {& T: d
然后就是将我们传进来的参数进行变量化, }2 n3 s2 P- o
$ ]5 O6 m- S! {# ^- h& T H* C
这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
3 ^3 x0 x0 j4 R& I6 d% s0 V8 F) n+ K ?: b
但是接下来这行呢?
0 s6 k% U: j8 {2 a/ l
# c* P/ y) M& `* G9 ` 0 A) T" T& m: e
) [& z5 |1 x; G1 d
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } $ J5 n# I! R' t$ g) X- W8 u& i
* z3 L% }# o7 v+ v7 r % K B: s$ s |; I# H3 B% t' `7 Z
& K/ j( @0 \: ^' Y
看看这里?# }- h" v: ^. G% Y% E; R& o1 f
) u2 a2 V" w `* T$ H
这里的QUERY_STRING来自前面
. B% k8 D3 J5 K* ~ K2 a
5 O/ F5 x" b+ a2 A ?5 W % B% \# C+ t: u E* z# r0 I5 Y I
) K, J- Y% T- {: r# H B
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']));& A; W% }& |8 a7 v. H
这里有个过滤,但是不影响* V' x/ m; z+ B5 W
+ ^8 a+ B8 f( R1 d
如果我们在这里进行覆盖这个db变量呢8 a/ k% B3 m( [' f
. e u% t- h8 ~' y8 {$ q9 u
因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));
' P: L3 g' E; C0 w3 X% j' ~7 ~+ k7 \5 i6 p; w+ Z v
可以将我们传进去的/ - 进行替换% m; `- v/ A% \9 v0 |$ H
+ @' s- i6 C& j [) E0 B% J) ~; n所以我们如果提交如下字符
4 \, @ J0 D1 s5 J, L9 n
; n6 W0 \- p$ F8 `0 {0 Mhttp://localhost/phpcms/index.php?db-5/gid-xd.html
, c& Q$ U0 a4 }' }) B6 B \
8 k9 a) H/ p. {3 }' @) R) L5 a他由于这个db被覆盖就会出错,所以物理路径就爆出来了
) ?# C$ |5 l P1 n7 O9 q6 K) G
% }: Y5 E) V/ K5 i+ r! z1 m1 y0×04 SQL注入!!!
, Q/ ]7 Z% m; R. Z. y2 o9 i$ W" Z( I# E& m2 F
在c.php中2 o+ ]8 z8 F+ J. W$ f! T
' f1 v) V1 h; Y: c) {
3 t( T) b9 h+ J* S. q1 {% a0 Z! t! @; Y; w' ]+ s5 H* i6 S
<?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']; } 3 s' J1 Q! k$ I6 v
, W- o3 C. }6 m2 T) k/ a
$ Q8 }7 g" O6 {* z% n. ~- s* H$ t* Z1 u1 \& a- R
注意这里的HTTP_REFERER这个常量! o. N9 D. w6 O8 M, n
; f3 [0 v. t# ~# q- [# N9 X这里的常量是通过前面的common.inc.php定义好的6 @$ `) e3 U. Q4 U; b8 @
# v& }5 d: {; L5 n$ y$ H8 T
define(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);
; {( X+ l7 I& g; e4 R! Z# g9 O2 u5 }: t. {. j
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我9 O- h1 o! I+ l j: A X
. `" x2 p0 j7 g! C, y$ |' c然后' v/ `3 x& D! X0 A8 Q
3 l, y8 D" C/ O# A
$db->insert($table, $info);8 S: G" G7 w6 y$ T9 Q: h4 v
我们来看一下它这里的操作
. B. |( `- n1 g/ y) E4 y( N) w: `/ W0 v7 N7 F8 |
function insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
7 {( @0 q/ k! R! q( M v( W
- a% k# o1 F! Y* f1 L s所以你懂的
% P4 {/ g+ D- c+ Q; }6 K1 a% K3 j8 S- |" z! R
) L% `( f6 n: u
7 i0 |' s) ~8 A6 g" J- `; d
附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=40456377372 l6 @8 m3 U8 X
/ P9 S& H1 Z9 d( ~/ H: m C9 R2 k4 F/ Q' d) P8 q# Q8 H9 s
) e2 P. F E. V: ?7 y b% b |