0×01 前沿
; I2 _; W; G7 T3 Y* X# W, Y$ u- g
/ o$ \! O- f: l" C. ~# M Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。% P& Y, x& v/ Q5 W$ k
1 V+ q1 D: g8 Y5 ^ m- i. X& l
0×02 写在前面的话2 M! Z3 Q3 _0 i0 C+ v: e& ? L
( ^( E d, @3 F6 t phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题1 h' R Z" [- ~1 y9 Q- T
1 x2 T1 F- y6 Y" o9 T+ d) I. {
这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
- z! s3 {/ m) o' B8 m0 a
, Q3 [$ D1 G. Z* D4 ?, w9 @0 u5 y这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
+ J$ q* ~- _+ w- {8 p* F6 @1 Y5 Q# c! |% b& y/ l6 I: a2 z
0×03 路径? ? ? O8 q6 b- l( m# b% ~) y
- u& q; G8 E3 b, B6 V3 y 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件
, F( T0 {% h$ B: l% t
0 L3 H x* \* |/ H, z$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])); } 8 N3 z( K5 }. W* M. J3 q, C- x& x% g; e
W" I0 {; E" E" F4 ]这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的4 y9 R6 _. h* j0 T. s
& v5 H- Q$ w$ o9 A$ A然后就是将我们传进来的参数进行变量化
% U/ ~, a/ N1 F6 q/ ~5 Y
2 i: k2 M7 o* p9 W$ S2 L这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
! s0 y" X2 v2 _3 `) _
; Q) t. p4 `. _, A/ A0 e但是接下来这行呢?
( c6 |6 C& ~: r' e+ h( ~) g1 z
5 n; v: z) j* U- D
' ~$ X9 K4 u) \; F1 B8 l) U/ U* L3 o7 t% k" `- ]/ H
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } ' l# \. z" @/ a7 ~
9 ~7 l- e+ K6 o1 N4 |; k: U$ o: A 9 z- Q0 u& {, e/ E; x3 K0 n) ?( q
5 B& a4 y" _6 N# G1 S
看看这里?) y/ Q3 j8 i) z
/ S8 |; l4 c9 ]4 g/ Q: H这里的QUERY_STRING来自前面
2 |1 {( p3 S2 Q' U
9 I9 E2 ~5 X4 F" z9 M7 t P3 ?: J* `3 K ~
5 A$ I! m7 _- `2 ^. l7 S- ?9 r
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']));+ R2 v9 L7 P; U* D# a
这里有个过滤,但是不影响
. T8 ]- y$ W7 s& |5 k. q( X' ]
: b+ L( d. D4 Z5 A如果我们在这里进行覆盖这个db变量呢" E8 m4 l; o, m6 J
9 v0 c+ p5 K3 w; M8 W
因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));; t9 j! L% e9 Z) e9 R0 g) F
6 h* ]8 f& C p7 D8 N
可以将我们传进去的/ - 进行替换2 V" H2 `3 u% l ?5 {* w2 j
7 g' u# v& N3 f所以我们如果提交如下字符1 V$ w6 l" a N: M" }$ L2 t5 o: C( i/ N
' a# z7 u+ [) b# I1 C1 F& O' a
http://localhost/phpcms/index.php?db-5/gid-xd.html1 a8 P+ V" t; C( ^& M0 X
) F) c3 @ K3 }5 J4 {+ l( U
他由于这个db被覆盖就会出错,所以物理路径就爆出来了/ f' {( G1 ]* z3 i7 Q# X
' F/ c5 K) Y1 Y4 V+ X4 O2 I" E0×04 SQL注入!!!7 G; }% s. T- [. Y/ z- l/ h
- J* P( H8 v c+ E! ^" x! M
在c.php中
; V5 D7 I) I; N g7 {# j* l: |' G6 ^& o
q* p, K& J% K* O, j
9 x& \* P. E0 x. U. g<?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']; } * e7 M- c% ~% @* B
& U1 e0 T& Y& J2 }1 C
1 }$ G' Z& {& c# g% B) x+ h
5 r( Q- w, w& R! M1 {6 q注意这里的HTTP_REFERER这个常量
0 Z4 u' d+ n8 T+ r& `
C# Y' U( C! i6 |这里的常量是通过前面的common.inc.php定义好的
% E# e9 m% x+ N8 h6 y+ o, x
4 [! j5 ~1 M9 C$ e' k% g: ?define(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);
( a% l6 ~ u5 I& f$ P1 J0 l: F' C" W G1 w( f5 x* a
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我; ^$ u' e1 K" ]% B, E- Z
+ d$ l! \, j/ d% k8 r$ q2 _7 C
然后' I; w. ^0 o/ o+ x3 t ]
# W2 c9 a S @5 t
$db->insert($table, $info);
5 v3 P1 {0 ]6 [/ V7 J! T我们来看一下它这里的操作
0 `4 X+ ~. t \+ D5 i6 _
1 g# c# L. B; r2 z! x0 ^; ufunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
" e6 O2 Q B* b) h K
6 w! n# G$ d5 k9 B所以你懂的! t, C" V/ k, P$ m% ?
( y% V) T; ^6 n
s7 N0 l# X( C9 ]) |1 R) C5 Q7 c" m8 g
附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737" ^9 Z. X) L( e) \( r
1 E& H8 `" x8 m& _; n# g5 R
8 H. f% ~0 X6 t x/ q O0 E: R
' B! a+ h) P7 h# L- b |