SEACMS变量覆盖漏洞分析与防御教学
1. 漏洞概述
SEACMS曾存在一系列变量覆盖漏洞,攻击者可以通过精心构造的请求覆盖系统关键变量,可能导致安全防护失效、敏感信息泄露甚至远程代码执行。
2. 漏洞原理分析
2.1 初始漏洞版本
初始版本的SEACMS存在以下关键代码:
// 检查和注册外部提交的变量
foreach($_REQUEST as $_k=>$_v) {
if(strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS)',$_k) && !isset($_COOKIE[$_k])) {
exit('Request var not allow!');
}
}
foreach(Array('_GET','_POST','_COOKIE') as $_request) {
foreach(
$$
_request as $_k => $_v) ${$_k} = _RunMagicQuotes($_v);
}
漏洞点分析:
- 仅过滤
cfg_和GLOBALS开头的变量 - 未过滤
_POST等超全局变量 - 存在
!isset($_COOKIE[$_k])条件,可通过COOKIE绕过
利用方法:
构造请求:?_POST[GLOBALS]=1
- 第一次循环GET时,
_POST会被设置为Array(GLOBALS=>1) - 第二次循环POST时,
GLOBALS会被覆盖
2.2 第一次修复版本(9.91)
修复代码:
foreach($_REQUEST as $_k=>$_v) {
if(strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS|_)',$_k) && !isset($_COOKIE[$_k])) {
exit('Request var not allow!');
}
}
变化:
- 新增过滤
_开头的变量
2.3 第二次修复版本(9.93)
修复代码:
foreach($_REQUEST as $_k=>$_v) {
if(strlen($_k)>0 &&
m_eregi('^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_REQUEST|_SERVER|_FILES|_SESSION)',$_k) &&
!isset($_COOKIE[$_k])) {
exit('Request var not allow!');
}
}
问题:
- 仍然存在
!isset($_COOKIE[$_k])条件,可通过COOKIE绕过
2.4 第三次修复版本(9.95)
修复代码:
foreach($_REQUEST as $_k=>$_v) {
if(strlen($_k)>0 && m_eregi('^(cfg_|GLOBALS|_GET|_POST|_COOKIE|_REQUEST|_SERVER|_FILES|_SESSION)',$_k)) {
Header("Location:$jpurl");
exit('err');
}
}
改进:
- 移除了
!isset($_COOKIE[$_k])条件 - 但使用了
$_REQUEST检测,而PHP 5.3+默认request_order为"GP"(GET和POST),不包含COOKIE
2.5 最终修复版本
开发者最终采用了更严格的过滤方式,几乎过滤了所有可能的危险变量。
3. 变量覆盖的利用方法
3.1 通过_FILES变量利用
当程序未过滤_FILES时,可以构造虚假的文件上传信息:
// 示例漏洞代码
foreach(array('_GET','_POST') as $_request) {
foreach(
$$
_request as $_k => $_v) {
if(strlen($_k)>0 && preg_match('#^(GLOBALS|_GET|_POST|_SESSION|_COOKIE)#',$_k)) {
exit('不允许请求的变量名!');
}
${$_k} = _RunMagicQuotes($_v);
}
}
利用方式:
构造请求:?_FILES[file][tmp_name]=test.txt&_FILES[file][name]=1.php
可用于:
- 删除指定文件(如安装文件)
- 绕过文件上传检查
3.2 通过GLOBALS变量利用
如果能够覆盖GLOBALS,可以:
- 覆盖数据库连接信息,使服务器连接到攻击者控制的数据库
- 修改系统配置参数
- 禁用安全功能
4. 防御措施
4.1 最佳防御实践
-
严格过滤:
foreach($_REQUEST as $_k=>$_v) { if(preg_match('/^(GLOBALS|_GET|_POST|_COOKIE|_REQUEST|_SERVER|_FILES|_SESSION|cfg_)/i', $_k)) { exit('非法请求'); } } -
禁用危险变量:
if(isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) { exit('Request Denied'); } -
使用extract的安全模式:
if($_POST) extract($_POST, EXTR_SKIP); if($_GET) extract($_GET, EXTR_SKIP); -
过滤下划线开头的变量:
foreach(array('_POST', '_GET') as $__R) { if(
\[__R) { foreach( \]
__R as \(__k => \)__v) {
if(substr(\(__k, 0, 1) == '_') { if(\)__R == '_POST') { unset(\(_POST[\)__k]); }
else { unset(\(_GET[\)__k]); }
}
if(isset(
\[__k) && \]
__k == $__v) unset(
\[__k); } } } ``` ### 4.2 其他防御建议 1. 避免使用`register_globals`(PHP 5.4+已移除) 2. 对用户输入进行严格类型检查 3. 使用白名单而非黑名单过滤变量 4. 最小权限原则,限制变量的可修改范围 5. 定期进行安全审计和代码审查 ## 5. 相关案例 1. **Discuz! 6.x/7.x全局变量防御绕过导致命令执行** - 通过特定方式绕过全局变量过滤 - 导致命令执行漏洞 2. **2015通达OA-从前台注入到后台getshell** - 利用变量覆盖漏洞 - 结合其他漏洞实现从注入到getshell的攻击链 ## 6. 总结 变量覆盖漏洞是PHP应用中常见的安全问题,其危害程度取决于被覆盖变量的用途。防御此类漏洞需要: 1. 全面了解PHP变量处理机制 2. 严格过滤所有用户输入 3. 避免使用不安全的变量注册方式 4. 采用最小权限原则 5. 定期更新和修补已知漏洞 通过分析SEACMS的漏洞演变过程,我们可以看到安全防护是一个持续的过程,需要开发者不断提高安全意识,采用更安全的编码实践。\]