0×01 前沿
9 a1 C: }1 K+ R( M f" D$ q9 f* e6 x$ I. O( `0 I5 ~/ \' L
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。
4 F0 r. \8 O7 N( D3 c G, E( W' S S1 z" ^
0×02 写在前面的话( @/ D0 S S& A7 k2 e
9 m- W. u+ y7 ^/ w* A8 y: S/ K- H phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题: i5 ~2 O$ I, x) g% _: B+ a, ^, K
2 |; N& `+ D# S' X- d) |这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
* s. i. c6 b6 m" F% D0 z8 m
0 ?( w5 m _$ b |" f这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论5 U7 e$ s7 t2 i ]0 Y9 s
7 t5 G/ G! T+ z1 d+ ^
0×03 路径? ? ?
) N( g2 ^* F4 u5 O/ q }5 S: f. w, O: M7 Y) ?
在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件! @& q: x5 e9 y6 q* q
, f Z5 ?, H2 \2 c+ Z( q$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])); } . ]$ g3 P# }5 L* q+ a; [
1 l( z8 i# U1 ^ [1 I1 b1 i: S这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的6 V/ n% P; R' \% p* r
1 c* K, ~. B% i0 Z1 P然后就是将我们传进来的参数进行变量化* y, ?; h3 M* U( I
. Y, j' A; I0 @这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量- n, X- p# y d- o* u* q. S
2 v, w9 p2 k& X* E7 B! k5 E但是接下来这行呢?
, z3 P) l9 t0 I; \4 X
% {( h+ a) }# }4 Z
% T# n8 u' p3 L( X, M# P: i
5 ^7 t O; J! o+ d9 ?$ r9 rif(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } 0 m' J& i# |( L/ A- L# u# L; e
, ~. y# _: [$ {2 x" {' ~
5 `# f& J' w( F
9 L5 t! {: I2 ?5 E看看这里?
5 J- i6 ]3 s$ T; R# F
3 D% P; n- \' p2 T; ], W1 p p这里的QUERY_STRING来自前面
# D2 y% Z% A8 \0 R7 n9 K" B, @% F' f) Z3 P( @, o
8 L' f8 J8 D7 y' K& [( ~4 C9 u) H! c
4 {0 Q }8 c; T! U. ?4 \
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']));
! p1 w5 a& ^# T# y' \这里有个过滤,但是不影响
& n6 }- X6 f/ K5 D5 `: ]( y
' D& L `9 p. Y$ D, A. B% e* E如果我们在这里进行覆盖这个db变量呢7 g+ t5 t. |9 K, m. @& j! F
7 r8 A1 x6 C: }' W% u
因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));
4 H; z1 t; b( ` L% B2 U( l$ [3 R% M1 z1 p1 D6 m
可以将我们传进去的/ - 进行替换, ~6 g$ w) ^: Q% S2 V- }( l( N( j
" R: `# ?/ L% `5 N0 @
所以我们如果提交如下字符( F1 F. `6 P7 V/ n( }+ ]* T4 ^
. M' V$ R" q: q) H/ J
http://localhost/phpcms/index.php?db-5/gid-xd.html
' t, C+ n$ L1 h& d" B2 G1 s0 \6 ^. g I, p% }0 B+ n
他由于这个db被覆盖就会出错,所以物理路径就爆出来了# `8 r; C9 b# V* J
7 y5 Q6 X1 o5 e; t5 ^- f; A* s
0×04 SQL注入!!!
6 J+ t! {1 s" j) |2 l. ^* G4 `( h2 G/ e& y o& h& p
在c.php中5 N+ T t H" X) b: ?
- l# r$ ?- n) h
. \+ s) K) M. C
8 |! \5 a! V% u. W0 _<?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']; }
5 W) C( P. |1 D* x. C, F0 H0 c$ c- T" ~$ a
0 f, F+ e( R$ Z, B& r% s
8 I: z$ C* Q1 N+ f- z! o0 j注意这里的HTTP_REFERER这个常量
) X+ x- l, Q! w; U% I: |. I( U7 l0 g; S$ B s; v
这里的常量是通过前面的common.inc.php定义好的, P! z8 S% e1 t) a* I
* ~/ B- Q/ K" `# ydefine(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);+ o3 e( `, |0 @4 v
: e n2 `- D3 u7 u, p& H
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我' W( G+ @% f- Z( P9 N9 C
! H5 u5 [: m+ z
然后% j: k! T% k' \7 Q( E
- M L* O! W E/ e' I4 ]
$db->insert($table, $info);
- _! o9 \4 V% a9 o1 O# x3 z5 ^我们来看一下它这里的操作
3 K4 J ` Q) l) n9 ^( i
% v# l) j9 Z7 N. jfunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
# P' o* \0 i/ K# r: [7 }" n! D
# m& U% N! ~' h8 a; T& J所以你懂的
7 @+ s3 i N1 _) L } U2 G. @. w
2 G9 L2 j6 J* N; h5 A2 U2 r, a3 q o
% A, K- C; @$ P) a" e
1 g5 X, x. \' L$ V$ n$ V附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=40456377374 h* {! N7 ~. j* Z) \! y" z( Q. r+ f
/ i ~; o, O; M# c
^: E7 X; R. w5 ]
# }( G2 Y5 Z8 V: X |