0×01 前沿# f+ ^$ z' [( n9 V" X: `
5 [1 M# D/ Z7 c. d% H+ L Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。. p! Y. Y6 @1 w, M& X. H6 z
6 ?% m$ y+ U, H2 g. y6 ^0×02 写在前面的话& W0 D9 T+ R* W, j. U4 {
+ d; V& @$ b) P8 T5 b* I phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题6 x6 c6 X6 Q* Y4 ~1 ^, E% y
a# D$ b* I: |# N+ M
这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
( F L9 N/ x* s) S7 \' q% I/ N% p+ f' A
这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
\1 n- D# }# Z1 \1 r4 ~- s, a1 z' D! H; @( H0 ~! x$ h# j
0×03 路径? ? ?! Y t6 m' X& L% c
) X& ], A% {: A. Y0 S9 p# i 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件
) Y& P6 ~5 B0 W6 c" Y) d% u6 Q* Y. F/ u, y8 x+ R+ H. i
$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])); } 7 ~; H q8 t+ N& W4 y
! E1 n- {8 a% R- C* d% g; m3 z
这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的
; X2 k! C% h& h% A
6 Q) X+ M3 G! w7 `9 \然后就是将我们传进来的参数进行变量化, A, o8 i8 U* ?5 S6 n; D+ [& P1 o$ v* t! K
1 b! p# m6 G" {2 ~6 A
这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
0 k# b9 A! e }1 z" y0 |& r ]# J# w s" L4 D" s
但是接下来这行呢?
8 q$ u9 e6 W% X8 f) a$ |4 X3 t6 }: |) D/ _! i; M3 Y# @
- t3 ~5 L+ c% d
" N5 J3 t; T' y3 g0 `) o' Yif(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); } : {* `/ }. |: Q$ D
- s& M3 o( J- X0 E# Y0 d
M/ q- o. z" I# k& r
6 k$ X0 W) g7 E: i; {/ Z$ ~2 \/ A
看看这里?
; p) M" P- ]* g" I/ M- |9 n) x3 \, C3 r# P B
这里的QUERY_STRING来自前面
5 v. J1 l6 w/ j* B4 F s. B; C J6 c0 V7 _ \" T
+ B# A, K$ B6 b r1 ]- ~# q5 K' L3 ~: s: G
& V) W- e! W6 _2 Z. {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']));& I5 Y9 p1 q% ~) [2 O
这里有个过滤,但是不影响0 {7 W5 ^: `; a. f/ I. i
1 _; s. R. m. e5 w- {
如果我们在这里进行覆盖这个db变量呢
: \2 }* ~3 R. T
6 v0 X4 S7 G; K, |因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));
0 W" J) g( q r8 K% \3 ]6 |3 ]+ U% C$ K' Q
可以将我们传进去的/ - 进行替换
/ c) h: {9 ~& M' w+ v7 x! x; ~! |6 v# f ^
所以我们如果提交如下字符
9 G3 L, D; n5 w: Z
2 n( T2 C, W; Whttp://localhost/phpcms/index.php?db-5/gid-xd.html9 K0 c; F8 A! m) f' I. Z* D
( ^" P7 A+ C/ x* S他由于这个db被覆盖就会出错,所以物理路径就爆出来了3 W8 b7 c* L7 Q/ \, X/ j- |6 T/ o
/ M, T3 O1 P7 Y: K' p; d7 h# e0×04 SQL注入!!!+ y1 ~ Y3 s4 y* K/ l
% W ^6 o# U" g+ ?- J; m 在c.php中- S- T+ @0 }- [8 R0 |
& L- N- \0 @7 w
3 _ c" R3 O2 L K1 @$ Y7 i5 K' e! u+ _1 f- P
<?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 S& C0 H) `; ?! `: J% [( \+ S
) a2 H3 g v m+ I8 r# }! E r! F+ S+ }5 G8 }6 w }, ~: ~
+ {: O( ^3 `7 I! U! ]! [注意这里的HTTP_REFERER这个常量2 X( R. A& u( x, H
" B$ u4 w/ m( L这里的常量是通过前面的common.inc.php定义好的
) l6 u( B% U, y# ~
$ s0 K- W, C6 Q: M+ L3 t3 Ndefine(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);% q/ v% o4 t6 N& o( Q1 m5 U7 M) ?+ Y
7 E+ c/ y F2 S% K( F" M6 z, g没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我- g; ], W: X* B5 M6 w: Z
, D, O4 p; o0 c5 O, Z然后1 g7 c* P$ k4 \7 G1 Q/ i5 p
5 L: I# a2 G# ~2 j3 A/ u6 L- s) Z' E
$db->insert($table, $info);
) V5 L* k2 b5 b7 @我们来看一下它这里的操作
8 i) O% e' p2 e7 ]% `& e7 J3 e
+ S6 ]& \, A* P% u: Jfunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); } - {$ }& d/ y+ x$ B. e, Y
% H6 o6 O, ?1 z/ f, Q
所以你懂的
/ N* a$ j+ ~) b8 a3 d* \0 h, L. ~6 M- \
}* O# F+ L4 P { u0 T. k( d
X5 m) N: `7 |; N! f4 D/ J0 Y6 ?附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737- [2 x* i& \6 X+ {+ r" w' O
, K; A; S5 o2 a- ~4 ^8 K1 `. I
& j1 z2 U0 |' _% F( @) A6 `2 v9 ]! }( B. ]4 s& f1 O
|