BlueCMS——国产CMS建站系统

发布时间:2023-05-19

BlueCMS 安装与安全分析

一、BlueCMS的安装

1、下载BlueCMS的安装包并解压,将解压后的文件上传至web服务器上。 2、使用浏览器打开安装文件install.php,出现欢迎页面后点击“下一步”按钮。

<?php
/**
 * BlueCMS v1.6 安装程序
 *
 * Author: switer
 * Time  : 2020.12.22
 * Email : switer@qq.com
 */
if (!function_exists('mysqli_connect')):
    die('PHP环境中没有安装mysqli扩展!');
endif;
if (!function_exists('session_start')):
    die('PHP环境中没有安装session扩展!');
endif;
if (file_exists('./install.lock')):
    die('已经安装过BlueCMS,如果需要重新安装,请手动删除install.lock文件!');
endif;
$errors = array();
if (!empty($_POST)):
    $database_host = $_POST['database_host'];
    $database_username = $_POST['database_username'];
    $database_password = $_POST['database_password'];
    $database_name = $_POST['database_name'];
    $database_table_prefix = trim($_POST['database_table_prefix']);
    if (empty($database_host)):
        $errors[] = "请输入MySQL数据库服务器地址!";
    endif;
    if (empty($database_username)):
        $errors[] = "请输入MySQL数据库登录帐号!";
    endif;
    if (empty($database_name)):
        $errors[] = "请输入MySQL数据库名称!";
    endif;
    if (empty($database_table_prefix)):
        $errors[] = "请输入数据库表前缀!";
    endif;
    if (empty($errors)):
        $link = mysqli_connect($database_host, $database_username, $database_password);
        if (!$link):
            $errors[] = "连接MySQL服务器失败,请确认数据库登录信息是否正确!";
        endif;
        if (!mysqli_select_db($link, $database_name)):
            $errors[] = "选择数据库失败,请确认您输入的数据库名称是否正确!";
        endif;
        if (empty($errors)):
            foreach (glob("sql/*.sql") as $filename):
                $sql = file_get_contents($filename);
                $sql = str_replace("`cms_", "`" . $database_table_prefix, $sql);
                $sqls = preg_split("/;\s*\n/", $sql);
                foreach ($sqls as $sql):
                    if (!empty($sql)):
                        mysqli_query($link, $sql);
                    endif;
                endforeach;
            endforeach;
            $config_file = './var/config.php';
            $config_content = file_get_contents($config_file);
            $config_content = str_replace('{database_host}', addslashes($database_host), $config_content);
            $config_content = str_replace('{database_username}', addslashes($database_username), $config_content);
            $config_content = str_replace('{database_password}', addslashes($database_password), $config_content);
            $config_content = str_replace('{database_name}', addslashes($database_name), $config_content);
            $config_content = str_replace('{database_table_prefix}', $database_table_prefix, $config_content);
            file_put_contents('./var/config.php', $config_content);
            touch('./install.lock');
            echo '<p class="success-message">BlueCMS安装成功!</p>';
            echo '<p>请手动删除install.php文件,确保系统安全!</p>';
        endif;
    endif;
endif;
?>

3、填写MySQL数据库的相关信息,包括数据库服务器地址、用户名、密码、数据库名称以及数据表前缀等,然后点击“下一步”按钮。 4、按照页面提示依次填写网站相关信息,包括网站名称、管理员帐号、管理员密码等,最后点击“完成安装”按钮即可。

二、BlueCMS v1.6审计

BlueCMS v1.6是一款国产CMS建站系统,但是在安全方面存在多个漏洞。

  1. 信息泄露:BlueCMS的安装文件install.php中没有对数据库连接相关信息进行保护,攻击者可以轻易地获取到数据库的用户名和密码等敏感信息。
<label>数据库服务器地址:</label>
<input type="text" name="database_host" value="localhost" /><br/>
<label>MySQL登录帐号:</label>
<input type="text" name="database_username" value="root" /><br/>
<label>MySQL登录密码:</label>
<input type="password" name="database_password" value="" /><br/>
<label>MySQL数据库名称:</label>
<input type="text" name="database_name" value="bluecms" /><br/>
<label>数据表前缀:</label>
<input type="text" name="database_table_prefix" value="cms_" /><br/>
  1. SQL注入漏洞:在搜索功能中没有对用户输入的内容进行充分的过滤,导致攻击者可以通过构造SQL语句获取到用户数据或者进行数据库的恶意操作。
public function search()
{
    $keyword = isset($_GET['keyword']) ? $_GET['keyword'] : '';
    $page = isset($_GET['page']) ? intval($_GET['page']) : 1;
    if (strlen($keyword) < 1) {
        $this->redirect('/', array('q' => $keyword));
    }
    $keyword = $this->db->escape_string($keyword);
    $conditions = "status=1 AND (title like '%$keyword%' OR body like '%$keyword%')";
    $order_by = 'id DESC';
    $posts_per_page = $this->config->get('posts_per_page');
    $offset = ($page - 1) * $posts_per_page;
    $total_posts = $this->db->query("SELECT COUNT(*) FROM `" . $this->db->prefix . "posts` WHERE $conditions")->fetch_row()[0];
    $total_pages = ceil($total_posts / $posts_per_page);
    $query = $this->db->query("SELECT * FROM `" . $this->db->prefix . "posts` WHERE $conditions ORDER BY $order_by LIMIT $offset, $posts_per_page");
    $found_posts = array();
    while ($row = $query->fetch_assoc()) {
        $row['url'] = $this->permalink($row['slug']);
        $row['excerpt'] = $this->excerpt($row['body']);
        $found_posts[] = $row;
    }
    $this->render('search', array(
        'found_posts' => $found_posts,
        'keyword' => $keyword,
        'pagination' => array(
            'total_pages' => $total_pages,
            'current_page' => $page
        )
    ));
}

三、BlueCMS找漏洞

  1. 上传头像功能存在文件上传漏洞:上传头像功能没有对文件类型进行校验,攻击者可以上传带有恶意脚本的文件,从而实现对网站的攻击。
public function save_avatar()
{
    // 初始化
    $error_code = 0;
    $upload_dir = getcwd() . '/uploads/avatar/';
    if (!file_exists($upload_dir)) {
        mkdir($upload_dir, 0777, true);
        chmod($upload_dir, 0777);
    }
    $user_id = $this->current_user_id();
    // 上传新头像
    $filename = $this->generate_hashed_filename();
    $full_path = $upload_dir . $filename;
    if (move_uploaded_file($_FILES['file']['tmp_name'], $full_path)) {
        $this->db->query("UPDATE `" . $this->db->prefix . "users` SET avatar = '$filename' WHERE id = $user_id");
    } else {
        $error_code = 1;
    }
    // 响应请求
    $response = array();
    if ($error_code == 0) {
        $response['status'] = 'success';
        $response['avatar_url'] = '/uploads/avatar/' . $filename;
    } else {
        $response['status'] = 'error';
        $response['message'] = '上传头像失败,请重试!';
    }
    header('Content-Type: application/json; charset=UTF-8');
    echo json_encode($response);
}
  1. 代码设计缺陷:BlueCMS的代码结构存在缺陷,在代码审计过程中发现缺少对用户输入内容的完整校验及过滤,需要对部分模块进行重构,以确保脆弱性攻击的安全性。

四、BlueCMS v1.6安装失败

安装过程中,有一些常见错误需要注意:

  1. 文件权限问题:请确认您的服务器是否具有创建文件和目录的权限,否则会导致安装失败。
  2. MySQL版本问题:BlueCMS需要使用 MySQL 5.6 或更高版本。
  3. 服务器环境问题:请确保您的服务器环境符合 BlueCMS 的要求,包括 PHP 5.4.0 或更高版本、MySQL数据库、Apache 或 Nginx 等 web 服务器。

五、BlueCMS v1.6代码审计

  1. 获取当前用户信息的代码
public function current_user()
{
    if (isset($_SESSION['user_id'])) {
        return $this->db->query("SELECT * FROM `" . $this->db->prefix . "users` WHERE id = " . intval($_SESSION['user_id']))->fetch_assoc();
    } else {
        return null;
    }
}
  1. 登录验证的代码
public function do_login()
{
    $username = isset($_POST['username']) ? trim($_POST['username']) : '';
    $password = isset($_POST['password']) ? trim($_POST['password']) : '';
    $user = $this->db->query("SELECT * FROM `" . $this->db->prefix . "users` WHERE username = '" . $this->db->escape_string($username) . "' AND password = MD5(CONCAT('" . $this->db->escape_string($password) . "', salt))")->fetch_assoc();
    if ($user) {
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['user_name'] = $user['username'];
        header('Location: /admin');
    } else {
        header('Location: /admin/login.php?msg=登录失败,请检查您的用户名和密码!');
    }
}
  1. 对文章进行保存的代码
public function save_post()
{
    $title = isset($_POST['title']) ? trim($_POST['title']) : '';
    $slug = isset($_POST['slug']) ? trim($_POST['slug']) : $title;
    $body = isset($_POST['body']) ? $_POST['body'] : '';
    $status = isset($_POST['status']) ? intval($_POST['status']) : 0;
    $user_id = $this->current_user_id();
    $post_id = isset($_POST['id']) ? intval($_POST['id']) : 0;
    if (empty($title)) {
        header('Location: /admin/new.php?msg=文章标题不能为空!');
        return;
    }
    if (empty($body)) {
        header('Location: /admin/new.php?msg=文章内容不能为空!');
        return;
    }
    if (!empty($slug) && !$this->is_slug_valid($slug)) {
        header('Location: /admin/new.php?msg=文章别名已经被使用,请输入其他别名!');
        return;
    }
    if ($post_id) {
        $this->db->query("UPDATE `" . $this->db->prefix . "posts` SET title = '" . $this->db->escape_string($title) . "', slug = '" . $this->db->escape_string($slug) . "',body = '" . $this->db->escape_string($body) . "', status = " . $status . " WHERE id = " . intval($post_id));
    } else {
        $this->db->query("INSERT INTO `" . $this->db->prefix . "posts` (title, slug, body, status, user_id) VALUES ('" . $this->db->escape_string($title) . "', '" . $this->db->escape_string($slug) . "', '" . $this->db->escape_string($body) . "', " . $status . ", " . intval($user_id) . ")");
    }
}