代码审计 | DedeCMS v 5.7 sp2 RemoveXSS bypass
字数 1278 2025-08-18 11:37:33

DedeCMS v5.7 SP2 RemoveXSS函数绕过分析与防御

漏洞概述

DedeCMS(织梦CMS)v5.7 SP2版本中的XSS过滤函数RemoveXSS存在设计缺陷,攻击者可以通过多种方式绕过其过滤机制,导致反射型XSS漏洞。该漏洞位于/include/helpers/filter.helper.php文件中。

漏洞分析

RemoveXSS函数工作原理

  1. 解码阶段:函数首先将十进制和十六进制编码(如&#xxxxxxxxxx;)转换回原始字符
  2. 过滤阶段:使用$ra1$ra2中的黑名单进行过滤替换
    • 例如:javascript:alert(1)会被过滤为ja<x>vasc<x>ript:alert(1)

绕过方法一:双重编码

  1. 输入:javascrip%26%2338%3B%26%2335%3B%26%2349%3B%26%2349%3B%26%2354%3B%26%2359%3B:alert(1);
  2. URL解码后:javascrip&#38;&#35;&#49;&#49;&#54;&#59;:alert(1);
  3. RemoveXSS第一次处理:将&#xxxxxxxxxx;转换后得到javascrip&#116;:alert(1);
  4. 黑名单过滤:javascrip&#116;不在黑名单内,不被过滤
  5. 最终HTML输出:&#116;被解析为字母t,形成javascript:alert(1);

绕过方法二:省略分号

  1. 正则表达式匹配&#xxxxxx;需要分号结尾
  2. &#x0a;等于换行符,不需要分号结尾也能被浏览器解析
  3. 例如:j&#x0aavascript(无分号)可绕过正则匹配但仍能执行

绕过方法三:超长十六进制编码

  1. 正则表达式匹配&#[xX]0{0,8}([9ab]);,限制在0-8个字符
  2. 十六进制格式可包含多个前导零,超过8位则无法匹配
    • 例如:&#x00000000074;(超过8个前导零)

漏洞总结

RemoveXSS函数存在三个主要问题:

  1. 双重编码绕过:对双重编码的输入处理不当,导致黑名单失效
  2. 分号依赖问题:正则表达式依赖分号结尾,但某些HTML实体可不使用分号
  3. 长度限制问题:对十六进制实体长度限制不足,允许超长编码绕过

防御建议

  1. 输入规范化:在处理前先统一解码所有编码形式的输入
  2. 严格实体解析:要求所有HTML实体必须包含分号
  3. 白名单替代黑名单:使用允许的安全模式而非过滤危险模式
  4. 输出编码:在输出时根据上下文进行适当的编码
  5. 更新正则表达式:修正长度限制和分号要求的问题

测试验证

测试Payload示例:

javascrip%26%2338%3B%26%2335%3B%26%2349%3B%26%2349%3B%26%2354%3B%26%2359%3B:alert(1);
j&#x0aavascript:alert(1);
javascrip&#x00000000074;:alert(1);

修复方案

  1. 升级到官方最新版本
  2. 手动修改filter.helper.php文件:
    • 加强编码处理逻辑
    • 修正正则表达式限制
    • 增加对双重编码的防护

参考

  • 漏洞发现者:q601333824
  • 原始文章发布时间:2018-08-30
  • 相关CVE:无公开CVE编号
  • 影响版本:DedeCMS-V5.7-UTF8-SP2及之前版本
DedeCMS v5.7 SP2 RemoveXSS函数绕过分析与防御 漏洞概述 DedeCMS(织梦CMS)v5.7 SP2版本中的XSS过滤函数 RemoveXSS 存在设计缺陷,攻击者可以通过多种方式绕过其过滤机制,导致反射型XSS漏洞。该漏洞位于 /include/helpers/filter.helper.php 文件中。 漏洞分析 RemoveXSS函数工作原理 解码阶段 :函数首先将十进制和十六进制编码(如 &#xxxxxxxxxx; )转换回原始字符 过滤阶段 :使用 $ra1 和 $ra2 中的黑名单进行过滤替换 例如: javascript:alert(1) 会被过滤为 ja<x>vasc<x>ript:alert(1) 绕过方法一:双重编码 输入: javascrip%26%2338%3B%26%2335%3B%26%2349%3B%26%2349%3B%26%2354%3B%26%2359%3B:alert(1); URL解码后: javascrip&#38;&#35;&#49;&#49;&#54;&#59;:alert(1); RemoveXSS第一次处理:将 &#xxxxxxxxxx; 转换后得到 javascrip&#116;:alert(1); 黑名单过滤: javascrip&#116; 不在黑名单内,不被过滤 最终HTML输出: &#116; 被解析为字母 t ,形成 javascript:alert(1); 绕过方法二:省略分号 正则表达式匹配 &#xxxxxx; 需要分号结尾 但 &#x0a; 等于换行符,不需要分号结尾也能被浏览器解析 例如: j&#x0aavascript (无分号)可绕过正则匹配但仍能执行 绕过方法三:超长十六进制编码 正则表达式匹配 &#[xX]0{0,8}([9ab]); ,限制在0-8个字符 十六进制格式可包含多个前导零,超过8位则无法匹配 例如: &#x00000000074; (超过8个前导零) 漏洞总结 RemoveXSS函数存在三个主要问题: 双重编码绕过 :对双重编码的输入处理不当,导致黑名单失效 分号依赖问题 :正则表达式依赖分号结尾,但某些HTML实体可不使用分号 长度限制问题 :对十六进制实体长度限制不足,允许超长编码绕过 防御建议 输入规范化 :在处理前先统一解码所有编码形式的输入 严格实体解析 :要求所有HTML实体必须包含分号 白名单替代黑名单 :使用允许的安全模式而非过滤危险模式 输出编码 :在输出时根据上下文进行适当的编码 更新正则表达式 :修正长度限制和分号要求的问题 测试验证 测试Payload示例: 修复方案 升级到官方最新版本 手动修改 filter.helper.php 文件: 加强编码处理逻辑 修正正则表达式限制 增加对双重编码的防护 参考 漏洞发现者:q601333824 原始文章发布时间:2018-08-30 相关CVE:无公开CVE编号 影响版本:DedeCMS-V5.7-UTF8-SP2及之前版本