0×01 前沿
1 F W2 Q7 V7 x6 ]. a& P. { c! S! F/ I2 B3 J* _
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。
8 Y7 f) |: L, [2 d, M' s
# r, I [$ \! S3 D! C8 ^3 W0×02 写在前面的话
' _: I6 I8 D! B2 r" {. k6 l8 ^- C
$ E. Y6 I2 }& D0 N phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题3 W; Y, u& y L
) l" l Z) z; D& ^" p这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强( M _3 O; f* Q" D( g4 z0 Q
0 d4 {4 v* ?* |% `* L: y/ s1 z
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
* Y" x. N R% _/ N. ]- D" T. L5 ]/ Z
0×03 路径? ? ?# A4 S" J6 C* I% m
. P- c! `/ _; Y; X* S6 E! _- {" x) x
在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件( [+ b5 t9 y, c T& g f
, `8 _" ]. m8 X/ Q7 V& n0 g$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])); }
1 [! K. u0 {% l1 X/ F& K
; Q$ v) |( D- s8 [6 }5 ~) `% P E3 [这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的
* ]- B+ P9 t7 r3 T. v/ u: T; _ k1 v* ?1 S7 E" F' J) _, W* F$ c4 M
然后就是将我们传进来的参数进行变量化
$ A* b; W' `" B% u/ F8 W% ?4 ~' {& T% U n" w* [5 C" Y, j# g
这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量) N* C- _9 ]& j. ?/ O+ i( m
7 ~* }- i; Z# y* X1 D( q# p. x9 F! ]但是接下来这行呢?
4 _, Y2 f3 ^$ p& ~$ d# S- U
4 O" Y8 ~# _( N0 i$ q" O
& P- A- {' l( z. ~# X g, M
. u$ T- {3 B2 S: K3 L2 S" Wif(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } ! K& L+ o4 O& R& G6 l
( I+ Q; o5 `' x5 m$ L3 h8 I
- y, q0 P9 r; d
5 a ~4 }0 ~. g5 K8 w, X2 R3 [' Z& C
看看这里?
* Y/ n% a1 A( K% W
/ l; B2 P: z9 A; k x" C7 d这里的QUERY_STRING来自前面5 r7 O% W7 ^1 u+ t. S+ ^
/ G; S- | `$ U$ i' q
% L q& r/ x. ^
+ c" _6 H9 `! V/ j9 C6 w& r: gdefine('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']));
8 b, q, \) _5 L, \这里有个过滤,但是不影响& [8 W4 s7 J: f$ _4 k# Y. w6 P0 \
0 K/ d2 ^! E1 Q
如果我们在这里进行覆盖这个db变量呢
0 N1 g7 v! d: S1 }5 r8 N0 a) v- H
( k" ?* f( t: v; Y4 Z因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));) m K5 |0 E' @+ V; a* W
4 o" f) i. i8 O4 W/ z
可以将我们传进去的/ - 进行替换8 g" V& Q; j, T1 a
: l- E/ Z- r( ^2 j h/ R9 J; N
所以我们如果提交如下字符
2 P5 J, ^4 q( Z2 U7 d+ w- Y* c' \5 c, k$ A4 x; G7 e
http://localhost/phpcms/index.php?db-5/gid-xd.html
4 W n0 \1 [& P/ D$ c5 e. y
. r6 _( `1 i) t0 @2 d他由于这个db被覆盖就会出错,所以物理路径就爆出来了
' k9 h' s% J+ t: @6 z( n, N
' e/ j, P. d3 s) r2 A F1 y0×04 SQL注入!!!
' |; ]$ s$ Y( B7 u! a. f- ~# i/ Y2 E* H6 u2 p+ t
在c.php中
/ e: X) m/ j; {( v2 w
1 L) k9 L+ w$ r; V
2 W) v' O6 K/ D: h8 P* j
% Y7 w% P& H! l: u) O* S; E5 `) v<?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']; }
( H( e' O0 [$ X# f& q* {9 F
8 P1 Z6 K& y8 m. q' ?/ l " s, y8 G0 t) \2 }+ `
y3 B/ q# I8 j7 b3 D* p
注意这里的HTTP_REFERER这个常量
7 ~% A J9 c8 m) w. {7 R" ~5 k+ d& {! d) @4 ]) \
这里的常量是通过前面的common.inc.php定义好的& ^9 ]3 {# `- r) ]8 T9 J( T
6 {: t' |& l7 b U8 [4 \define(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);
/ B. q$ h1 s0 q1 T" F9 d# s4 ]+ T' k' f
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我
8 W, ?0 T" {% t/ ^5 S$ j* w& x
$ G; J2 ?1 \- W8 T' p0 t4 Y* _然后
7 g Z9 }. Z A3 N, Q3 ^" j7 f9 B
$ o6 s* c! S) O( G8 w F( g$db->insert($table, $info);
! Q; Q8 d" B/ V3 j* R0 w我们来看一下它这里的操作# w7 j1 N& X+ y/ ]' O
( w, O) h. c* r0 `1 k9 jfunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); } " ?/ |, M% ~# K2 u: ` I U
( f( L8 X' W' Q3 c
所以你懂的) d- X8 J! Z" v. v9 v( l4 y9 t
9 S2 r, D: T, X# c7 A
" k/ }2 ^ \5 g9 I( D
# ]( A( Y+ H7 N( \7 p附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737
% R7 c: U% h+ @; z+ x
( o6 f9 V" Q) Q5 s o , x" `& p7 {0 }% ^
( `7 V+ P# W! _7 i: _" U# V5 j" ~, c |