0×01 前沿
4 g. K, o f, ]3 W. u/ Z5 r/ A% I( `7 o& A; N: d+ h( N" o
Phpcms2008 是一款基于 PHP+Mysql 架构的网站内容管理系统,也是一个开源的 PHP 开发平台。Phpcms 采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。3年来,凭借 Phpcms 团队长期积累的丰富的Web开发及数据库经验和勇于创新追求完美的设计理念,使得 Phpcms 得到了近10万网站的认可,并且越来越多地被应用到大中型商业网站。( |% H6 x8 Z$ ]
2 o+ N! k [* a! L" A. Z
0×02 写在前面的话! l6 ~8 M# T5 J) W+ H
* ?8 X* _4 A0 ^; u# {1 _9 T phpcms 2008 这是我看第二次代码了,之前已经发现了一些问题,只是没放出来,这次稍微仔细看了看,又发现了一些问题 m0 B) d% S. l
5 a* _- i1 n. ^. _3 D
这次就放2个吧,其中啥啥的getshell暂时就不会放了,比起v9来说,2008的安全性能确实差很多,模块化以及代码严谨程度也没有v9强
+ Q8 j; d0 y+ q
1 x- ^2 y7 M/ h- T这次还没把代码看完,只看完几个页面,就先放2个有问题的地方,如果有更好的方式,到时候一起讨论) ]( {7 e& C+ r* Y5 H8 d& b
7 W0 s2 O/ _5 S
0×03 路径? ? ?
5 u- |7 A' ~2 [
4 ?: Z2 ?! T9 G6 q% L3 }6 b! t: m 在include/common.inc.php中 ,这是phpcms的全局要加载的配置文件) x# x5 ?2 D" H% x" @
* |4 m1 M7 h' V6 B
$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])); }
9 {& T/ o. e2 y/ O$ [8 R+ m- i3 v3 {. @
这里的话首先实例化了这个数据库,产生了一个$db资源句柄,他是用来操作数据库的) W- L8 ^/ F) I/ {* I" n5 z i3 e9 Y
! O! f. Y* z- O, v
然后就是将我们传进来的参数进行变量化
0 ~9 A t7 B7 ]2 d3 w0 G
0 w- M: X6 q3 V" ]这里有一些小过滤,自己可以看,所以这里传进来的参数就作为了变量
~. l; u3 b A5 o. b" s1 i$ }8 d- A8 i7 h
但是接下来这行呢?
( a$ ]5 q9 Y4 S- _. t) `' n, V, w1 L' I8 {! M5 o
3 e: S2 o. A5 K) u8 Q1 o; {
4 v# E6 W! A7 m2 R6 Z5 [
if(QUERY_STRING && strpos(QUERY_STRING, '=') === false && preg_match("/^(.*)\.(htm|html|shtm|shtml)$/", QUERY_STRING, $urlvar)) { parse_str(str_replace(array('/', '-', ' '), array('&', '=', ''), $urlvar[1])); }
0 N3 X* ]5 E& `+ s
8 Z% U% @/ a( p5 p: V6 b+ g
1 O) V: C( F( P- T+ F( b
# }3 |" o. T# ]3 N8 ]" o l5 e看看这里?
8 {! f( C: `9 P+ S
: \. O$ r- h( n1 N# {) Z这里的QUERY_STRING来自前面
( h4 Q/ y7 z* V I/ i% Y" o& u1 _' z+ M, P
- W& b5 A0 H4 Z6 n3 S0 B( Q0 f
& F0 w$ z2 f* a* f& ]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']));
# k( v4 I6 v& J- {) ]( x- p这里有个过滤,但是不影响; I5 [. P) Z/ T5 O; o. @1 p
' r$ A$ y' ?2 J& `, r/ C: j
如果我们在这里进行覆盖这个db变量呢
, t; y- U( ?8 q- `) { v) b
: }% X$ [6 u4 n% |2 a* D& x因为这里 parse_str(str_replace(array(‘/’, ’-', ’ ’), array(‘&’, ’=', ”), $urlvar[1]));
" A* o3 x4 F) S9 [) Y# ^) `: }/ c) j( y( T( I0 T5 i& h
可以将我们传进去的/ - 进行替换
4 d) ]& J" n$ i, n# N' U+ X( d3 ]' d$ K8 i5 W3 W- i! P% y
所以我们如果提交如下字符8 [$ P' Y1 f3 }/ j& @) N
6 G7 x' z$ I+ L% z* f5 lhttp://localhost/phpcms/index.php?db-5/gid-xd.html/ N+ T. d4 r$ y1 G+ R- |, d
u. S9 h3 U L2 ~# L O0 z" z他由于这个db被覆盖就会出错,所以物理路径就爆出来了3 c6 Y0 V7 [. P9 d
4 U9 P1 d# O: B- Q; b# S9 E
0×04 SQL注入!!!, C* J0 Q! {7 {3 i# L
5 t2 ]; D$ {% R- B7 I0 w
在c.php中
+ U! j; s2 O) z, T, A" p7 a9 ?5 Z/ ?, [/ P( Q& Z2 V" E' e x& ^& q! A8 p
- s* d- J) F* F0 ?$ o/ q
' t0 b+ _3 H! X4 q7 a- f4 U& {<?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']; }
! p2 r$ ]+ X P0 N- K2 `6 \& S4 @# l* M: u: t6 ]( O
, {' C8 G$ y+ h$ w2 ?& L
! I2 u, M) C2 W注意这里的HTTP_REFERER这个常量
* |# T& l. p. x+ Q3 r6 J! U
0 h6 Y' F& U0 z这里的常量是通过前面的common.inc.php定义好的6 Q8 Y, R1 j8 F! C6 w
4 X: g+ I x! {" h4 `; R
define(‘HTTP_REFERER’, isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ”);
% h' i t% |' L8 ~! w/ o1 Z% ^5 d8 D
没有经过任何过滤操作,所以你懂的,我估计很多同学已经发现了,只是没去公布了,所以俺就替你们xxoo了,哈哈…别骂我) ?5 Z9 g/ X. t3 j( B2 @
$ f0 [0 {% E. G& m, H7 W
然后
: A+ q. \7 B# h, o0 o5 D9 I
1 T* E! @+ S% u0 k8 V* C/ Z$db->insert($table, $info);
; O0 G; f& t* X8 o我们来看一下它这里的操作& n x+ n( b# y+ W& H Y
$ T3 G, s5 Y/ D
function insert($tablename, $array) { $this->check_fields($tablename, $array); return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')"); }
* U! k2 T, {9 I% f/ B$ j/ f1 Q/ l. u/ T7 b7 ^$ o5 y( F( [
所以你懂的% k; u g, t: F
/ Q* c \" a( M4 j$ Q$ X4 [
1 s2 j/ n# x. o7 \# X" W* p3 v7 O J" F2 ]" }2 n) Y
附EXP:http://pan.baidu.com/share/link?shareid=468231&uk=4045637737
$ K5 v. {$ l! q8 F$ j
9 Q I) Q# a) K3 s" _7 E& X( ]/ {
l3 o9 M* ]3 F5 d5 {, s, o9 q. \% v# v/ U! _
|