0×01 前沿
( l8 Y! m7 P- Y4 b- ~ p5 e. Q* `1 k, F0 y- i
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。
6 g0 u4 l5 S! O8 w: N/ }1 r- |# K$ v4 z
0×02 写在前面的话
: {, ]+ K' v* W! e$ C* {6 \
d, O# a' c1 _+ B2 w phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题7 Q }2 N& R2 M! J) I0 J9 q+ \
5 }$ K6 ?9 L. i. e0 x! j' i/ g3 g这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
* L2 b' Z% S; A/ z, U
" S4 Q4 T, _/ c( L: l: h/ h' H( c$ p. |这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论
: q: t/ k; @; }- K! k% U" q8 N, k- D8 D) I2 c6 ?; C
0×03 路径? ? ?3 y' j( C% H; b) N* F
8 \9 G: \1 ]8 F# y 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件 [, X7 Y8 @( ^1 e3 `
+ H$ @8 q7 J( A/ n# f6 [/ e$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])); }
* Z% X2 }& m7 E. m: R/ r6 w4 `
1 `! T6 F4 `% Y( P- w: B这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的: p5 J( V ^. h3 }
1 @, P* H, f y1 |0 E8 |然后就是将我们传进来的参数进行变量化
7 o! }) i7 ~9 f D& L S
, N& o0 a& J7 G) i0 r( E( J这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
6 S+ n% v- t8 k# F. u
6 D) o3 {' f% q# q2 x但是接下来这行呢?' t, U+ W% A; ^9 Q$ l
# V' b4 Y' M" e% g 7 M2 |0 {3 [' |' R! q; v9 e7 C7 G! i
# I' d9 V: t% j/ ~' A6 wif(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); }
* [$ [- q4 E; |' v. ]; e
5 z( A+ f n2 C7 r/ }; q
+ @% ]' \: c9 m( A) x( c( ~. d- k' }% ?
看看这里?
3 t% ^2 E7 d' [7 T' G- v
0 Z8 |. O8 }- a0 v6 i5 _+ p* N这里的QUERY_STRING来自前面# j: F. Q$ E4 t0 c- O
- N6 g! A& |7 I# q/ S
: s4 w+ j% J: P! Q7 T& g) a& x7 h$ p6 S7 i* g0 c
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']));
6 @8 M3 {' l3 \# ?' r( N这里有个过滤,但是不影响0 V; Q2 l% i( \/ m4 E
) A- d" }2 T$ r) A V+ _如果我们在这里进行覆盖这个db变量呢
# w) n, H; j) T
2 [! O% @( n: p) n- Q因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));! R; @7 f- s2 `
6 p4 f% Q3 o# s) g9 X8 u可以将我们传进去的/ - 进行替换' E& f$ s- D; g0 _
; l4 n% V( A. ~: e1 i& h; B. ~
所以我们如果提交如下字符
9 R0 |' r I; x; d2 j3 K
0 |% w3 k4 r5 zhttp://localhost/phpcms/index.php?db-5/gid-xd.html
) a1 Y) X. N8 g/ M& i9 W! w3 S" ~. ^% \1 u8 a E. N8 }
他由于这个db被覆盖就会出错,所以物理路径就爆出来了: b. y$ y2 c0 r; l$ H' w; ?
- a0 H8 |7 u8 z8 V7 f- c
0×04 SQL注入!!!7 {& y; E, h- A3 S' x8 H
' i; W# `+ g+ A
在c.php中
/ T# u' V! a0 n" t( [( |- X- X4 l4 T! t& n
, W* b9 W. U% {* K3 d1 `
' }% ]* K5 Y# A1 z* j% ^<?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']; }
4 l# E! y8 R. t5 C- K9 Q6 @/ f% Z7 K S4 c/ r
9 m! j' a7 S2 o! Z3 x# Y+ `# t3 ~9 F+ J7 ` h- u
注意这里的HTTP_REFERER这个常量7 f: ?' Q* U1 i7 H1 ^+ u& g- ?
8 g0 p: v# M% _7 q/ N9 D
这里的常量是通过前面的common.inc.php定义好的& @3 U7 V4 r |
$ \" u! ^! V n6 H- a2 d
define(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);$ m6 _ ^4 l/ f) B( _/ v V
: e/ M0 V9 V0 Q
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我
4 X @$ i* d% ` A4 m. V' k \: k/ N4 g+ P! }* o
然后
$ J: J: U* l( F5 H" g# A2 I
* i8 L1 b3 ^3 L) |4 g3 g$db->insert($table, $info);
4 E5 T9 N- X- B我们来看一下它这里的操作
1 _$ A) z7 h$ o( b% x! O
2 v1 w1 O* F1 H. tfunction insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); } 7 {/ D# U: P# W3 O M! v/ C
2 y- q: @1 c+ R" W4 Y# u1 \所以你懂的: o3 h! b, f; Q
r8 v% `$ ]1 l' O3 ?
9 k; c6 h1 `5 C; w+ { B+ E: k4 Y; m7 b/ [0 s# i- i
附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737/ ?% @( D7 ]7 u5 ]% z, T
/ C& z+ I" h3 J" r5 u5 k
6 h9 I( D5 e; B9 ?2 B8 d q# ~
. s: s- E* O& }3 v9 R |