来源:自学PHP网 时间:2015-04-17 12:00 作者: 阅读:次
[导读] FineCMS是一款基于PHP+MySql开发的内容管理系统,采用MVC设计模式实现业务逻辑与表现层的适当分离,使网页设计师能够轻松设计出理想的模板,插件化方式开发功能易用便于扩展,支持自...
FineCMS是一款基于PHP+MySql开发的内容管理系统,采用MVC设计模式实现业务逻辑与表现层的适当分离,使网页设计师能够轻松设计出理想的模板,插件化方式开发功能易用便于扩展,支持自定义内容模型和会员模型,并且可以自定义字段,系统内置文章、图片、下载、房产、商品内容模型,系统表单功能可轻松扩展出留言、报名、书籍等功能,实现与内容模型、会员模型相关联,FineCMS可面向中小型站点提供重量级网站建设解决方案 本人看程序代码,只是为了学习,不断学习中… 这是最新1.73版,比之前1.72版在安全方面改进很大,加了不少过滤,也修复了几个公布了的漏洞,不过貌似看更新记录上没说,哈哈。我也是第一次看这套程序,只是最近看到好几个文章爆的它的漏洞,俺也来插一脚。
作者:Seay 用到的工具:Seay PHP代码审计工具 下载地址:http://www.2cto.com/soft/201211/35390.html 目录: 一、前台(两处)+后台任意目录浏览+任意文件删除漏洞二、后台任意文件读取漏洞三、前台任意文件删除漏洞四、后台遍地鸡肋注入五、对找回密码功能代码的看法载入工具扫描一遍 先看看过滤函数: 1、Core\\Model.php文件 /** * 字符串转义函数 * * SQL语句指令安全过滤,用于字符转义 * @access public * @param mixed $value 所要转义的字符或字符串,注:参数支持数组 * @return string|string */ public static function quote_into($value) { if (is_array($value)) { foreach ($value as $key=>$string) { $value[$key] = self::quote_into($string); } } else { //当参数为字符串或字符时 if (is_string($value)) { $value = ’\” . addslashes($value) . ’\”; } } return $value; }
2、 Extensions\\function.php文件 /** * 安全过滤函数 * @param $string * @return string */ function safe_replace($string) { $string = str_replace(‘%20′,”,$string); $string = str_replace(‘%27′,”,$string); $string = str_replace(‘%2527′,”,$string); $string = str_replace(‘*’,”,$string); $string = str_replace(‘”‘,’”‘,$string); $string = str_replace(“‘”,”,$string); $string = str_replace(‘”‘,”,$string); $string = str_replace(‘;’,”,$string); $string = str_replace(‘<’,'<’,$string); $string = str_replace(‘>’,'>’,$string); $string = str_replace(“{“,”,$string); $string = str_replace(‘}’,”,$string); return $string; }
3、 config\attackcode.ini.php文件
/** * GET和POST非法字符过滤配置(防非法字符攻击) */
return array( /* * GET参数非法字符过滤 */
’get’ => array( ‘select ’, ‘insert ’, ‘\”, ‘/*’, ‘*’, ‘../’, ‘union ’, ‘into ’, ‘load_file(‘, ‘outfile ’, ‘script’, ),
/* * POST值非法字符过滤 */
‘post’ => array( ‘<script’, ‘<frame’, ‘<iframe’, ‘<style’, ),
4、 core\\Controller.php文件 可以看到 $_COOKIE没过滤 /** * 用于初始化本类的运行环境,或对基本变量进行赋值 */ public function __construct() { if (get_magic_quotes_runtime()) set_magic_quotes_runtime(0); if (get_magic_quotes_gpc()) { !isset($_COOKIE) or $_COOKIE = $this->strip_slashes($_COOKIE); } else { !isset($_POST) or $_POST = $this->add_slashes($_POST); !isset($_GET) or $_GET = $this->add_slashes($_GET); !isset($_SESSION) or $_SESSION = $this->add_slashes($_SESSION); } $this->view = View::getInstance(); }
过滤函数挺多的,就是过滤的不严谨, 一、前台(两处)+后台任意目录浏览+任意文件删除漏洞我们看到config\attackcode.ini.php文件的GET和POST的过滤函数,很明显的,过滤了../没过滤\\这是返回上一级目录的,不过作者忘记了在windows下有时候斜杠\\和反斜杠/是一样的,
第一处:在前台有个会员图片附件和文件附件浏览,我们利用这里就可以任意目录浏览了。
Controllers\\member\\\ContentController.php 文件
/** * 附件管理 */ public function attachmentAction() { $type = $this->get(‘type’); $mdir = ’uploadfiles/member/’ . $this->memberinfo['id'] . ’/'; //会员附件目录 if (!file_exists($mdir)) mkdir($mdir); $mdir = $type == 1 ? $mdir . ’file/’ : $mdir . ’image/’; if (!file_exists($mdir)) mkdir($mdir); $dir = urldecode($this->get(‘dir’)); if (strpos($dir, ’../’) !== false) $this->memberMsg(lang(‘m-con-20′), url(‘member/content/attachment’, array(‘type’=>$type))); $dir = substr($dir, 0, 1) == ’/' ? substr($dir, 1) : $dir; $data = file_list::get_file_list($mdir . $dir . ’/'); $list = array(); if ($data) { foreach ($data as $t) {
$dir可控
http://www.cnseay.com/index.php?s=member&c=content&a=attachment&dir=..\\..\\..\\..\\&type=0
第二处: 我们在前台发布的时候,点击附件,浏览,抓下包就可以看到GET地址 http://www.2cto.com /index.php?c=attachment&a=album&dir=Li5cLi5cLi5cLw==&iframe=0&admin=0 Li5cLi5cLi5cLw== Base64解密后为..\..\..\ 3、后台任意目录浏览同理。
http://www.cnseay.com/index.php?s=admin&c=attachment&dir=XC4u&iframe=0
XC4u base64解密后是\.. 4、后台任意文件删除 同道理,不说了
/** * 删除文件夹 * * @param string $file_dir 所要删除文件的路径 * @return boolean */ public static function delete_dir($file_dir) { if (!$file_dir) return false; $parse_dir = self::parse_dir($file_dir); $file_list = self::get_file_list($parse_dir); foreach ($file_list as $file) { if (is_dir($parse_dir . ’/' . $file)) { self::delete_dir($parse_dir . ’/' . $file); rmdir($parse_dir . ’/' . $file); } else { unlink($parse_dir . ’/' . $file); } } return true; }
修复:过滤完整 二、后台任意文件读取漏洞:同理,还是斜杠和反斜杠的问题,
Controllers\\admin\\ThemeController.php 文件
public function editAction() { $dir = base64_decode($this->get(‘dir’)); $dir = substr($dir, -1) == DIRECTORY_SEPARATOR ? substr($dir, 0, -1) : $dir; if (strpos($dir, ’../’) !== false) $this->adminMsg(lang(‘m-con-20′)); $name = $this->dir . $dir; if (!is_file($name)) $this->adminMsg(lang(‘a-con-123′, array(’1′=>$name))); if ($this->isPostForm()) { $Pdir = $this->dir == dirname($name) . DIRECTORY_SEPARATOR ? ” : str_replace($this->dir, ”, dirname($name)); file_put_contents($name, stripslashes($_POST['file_content']), LOCK_EX); $this->adminMsg(lang(‘success’), url(‘admin/theme/index’, array(‘dir’=>base64_encode($Pdir . DIRECTORY_SEPARATOR))), 3, 1, 1); } $file = file_get_contents($name); $this->view->assign(array( ’name’ => str_replace($this->dir, ”, $name), ’file’ => $file, ‘syntax’ => strtolower(trim(substr(strrchr($name, ’.'), 1, 10))), ‘action’ => ’edit’, ‘iswrite’=> is_writable($this->dir), )); $this->view->display(‘admin/theme_add’); }
$dir可控
http://www.cnseay.com/index.php?s=admin&c=theme&a=edit&dir=XC4uXC4uXGNvbmZpZ1xkYXRhYmFzZS5pbmkucGhw
XC4uXDEudHh0 base64解密后是\..\..\config\database.ini.php
修复:过滤完整 三、前台任意文件删除漏洞看工具的提示: 265 /** 266 * 删除附件 267 */ 268 public function delattachmentAction() { 269 $type = $this->get(‘type’); 270 $mdir = ’uploadfiles/member/’ . $this->memberinfo['id'] . ’/'; //会员附件目录 271 if (!file_exists($mdir)) mkdir($mdir); //可能存在畸形目录创建漏洞 272 $mdir = $type == 1 ? $mdir . ’file/’ : $mdir . ’image/’; 273 if (!file_exists($mdir)) mkdir($mdir); //可能存在畸形目录创建漏洞 274 $dir = urldecode($this->get(‘dir’)); 275 $dir = substr($dir, 0, 1) == ’/' ? substr($dir, 1) : $dir; 276 if (realpath($mdir . $dir) == false || strpos($dir, ’../’) !== false) $this->memberMsg(lang(‘m-con-21′)); 277 if (file_exists($mdir . $dir)) { 278 if (is_dir($mdir . $dir)) { 279 $this->delDir($mdir . $dir); 280 $this->memberMsg(lang(‘success’), url(‘member/content/attachment’, array(‘type’=>$type)), 1); 281 } else { 282 unlink($mdir . $dir); //可能存在任意文件删除漏洞 283 $this->memberMsg(lang(‘success’), url(‘member/content/attachment’, array(‘type’=>$type, ’dir’=>urlencode(dirname($dir)))), 1); 284 } 285 } else { 286 $this->memberMsg(lang(‘m-con-22′, array(’1′=>$dir))); 287 } 288 }
很明显的,$dir我们可控,就是任意文件删除了,其实也是会员的一个删除附件的功能 http://www.cnseay.com/finecms/index.php?s=member&c=content&a=delattachment&dir=..%5C%5C..%5C%5C..%5C%5C..%5C%5Ccache..%5C%5C%2Finstall.lock&type=
删除安装锁文件,可重装程序,后台拿shell就很简单了 修复:过滤完整
四、后台遍地鸡肋注入后台注入很多很多,不过要在后台关闭 “禁止非法字符提交”的时候才能用, 可能作者做这么一个开关,是考虑到用户体验吧,只是说明有这么一个缺陷,没有什么价值。
修复:intval()一下,或者其他
五、对找回密码功能代码的看法在controllers\\member\\Common.php文件中有一个找回密码的函数。
86 /** 87 * 密码找回邮件通知 88 */ 89 protected function passEmail($username, $email) { 90 if (empty($username) || empty($email)) return false; 91 $rand = md5(rand(1000, 9999)); //随机数 92 $link = $this->get_server_name() . url(‘member/repass/find’, array(‘id’=>base64_encode(time() . ’|' . $rand . ’|' . md5($username))), 1); 93 $this->member->update(array(‘randcode’=>$rand), ”username=’” . $username . ”‘”); //可能存在SQL语句,请注意是否过滤 94 mail::set($this->site); 95 $content = $this->memberconfig['pass_tpl'] ? $this->memberconfig['pass_tpl'] : lang(‘m-com-6′, array(’1′=>$username, ’2′=>$link)); 96 $content = str_replace(array(‘{username}’, ’{link}’), array($username, $link), $content); 97 return mail::sendmail($email, lang(‘m-com-7′, array(’1′=>$this->site['SITE_NAME'])), htmlspecialchars_decode($content)); 98 }
它的功能就是给生成一个找回密码的链接发送的用户邮箱,同时修改用户randcode字段为生成的随机数的md5。
我们分析下找回密码链接: $link = $this->get_server_name() . url(‘member/repass/find’, array(‘id’=>base64_encode(time() . ’|' . $rand . ’|' . md5($username))), 1);
就是这句代码拼接的链接, get_server_name() 获得网站域名,后面加上member/repass/find,然后再加上时间戳time()和1000到9999之间的一个随机数和用户名的md5 的Base64编码,可以看出,时间戳可碰撞,随机数可碰撞,用户名md5可知,那么我们写一个程序,两个线程同时提交不同用户找回密码的请求,那时间戳相差就很小很小了,现在我们能大概确定时间戳的范围,用户名MD5知道,现在我们写一个自动提交的程序,当然要能判断链接是否正确,记得前两天我写了一个,可以到我博客去下载,我们改下程序,加一个自动生成1000-9999之间的数,不断递增并MD5加密,拼接链接,然后自动访问生成的链接,当出现成功特征字符,就说明成功了。如此看来,这个找回密码的方法还是有一定的危险性,当然这里只是对这个方法来讨论下。
修复:找回密码链接最好类似 md5(username+password+other) 这种形式,个人感觉会好一点。
之前说的cooki没过滤,我们来看下设置cookie的地方, cookie::set(‘member_id’, $member['id'], $time); cookie::set(‘member_code’, substr(md5(SITE_MEMBER_COOKIE . $member['id']), 5, 20), $time); 后面用到cookie的地方,比如 /** * 获取会员信息 */ protected function getMember() { if (cookie::is_set(‘member_id’) && cookie::is_set(‘member_code’)) { $uid = cookie::get(‘member_id’); $code = cookie::get(‘member_code’); if (!empty($uid) && $code == substr(md5(SITE_MEMBER_COOKIE . $uid), 5, 20)) { $_memberinfo = $this->member->find($uid); $member_table = $this->membermodel[$_memberinfo['modelid']]['tablename']; if ($_memberinfo && $member_table) { $_member = $this->model($member_table); $memberdata = $_member->find($uid); if ($memberdata) { $_memberinfo = array_merge($_memberinfo, $memberdata); $this->memberedit = 1; //不需要完善会员资料 } if ($this->memberconfig['uc_use'] == 1 && function_exists(‘uc_api_mysql’)) { $uc = uc_api_mysql(‘user’, ’get_user’, array(‘username’=> $_memberinfo['username'])); if ($uc != 0) $_memberinfo['uid'] = $uc[0]; } return $_memberinfo; } } } return false; }
这个验证用的比较好。
不看了,大半夜的,先看到这,以后有时间再把这套程序看完,这个文章写的比较急,将就着看吧,这几天天天忙着找工作。蛋疼啊 |
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习
京ICP备14009008号-1@版权所有www.zixuephp.com
网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com