漏洞原因
弱类型问题
类型转换是无法避免的问题。例如需要将GET或者是POST的参数转换为int类型,或者是两个变量不匹配的时候,PHP会自动地进行变量转换。但是PHP是一个弱类型的语言,导致在进行类型转换的时候会存在很多意想不到的问题。
如果在用于密码比对,身份验证中没有对类型进行强处理,往往会导致对比成功,身份伪造等等。
常见的弱类型对比
- 数字型与其对应的字符串
- 0 与 不包含任何数字字符串
- 数字型与其在前缀的字符串
数学计算运算
- '1e0'=='1e2' => true
- "10" == "1e1" => true
- ‘0e10’ == '0e1000' => true
- '0x001'=='1' => true
- md5('s878926199a') == 0 => true
- empty
- empty('0') == empty('0.0') false
- empty('0') == empty(0.0) true
- empty 返回 TRUE的情况:
- 若变量不存在则返回 TRUE
- 若变量存在且其值为""、0、"0"、NULL、、FALSE、array()、var $var; 以及没有任何属性的对象,则返回 TURE
产生弱类型的函数
- strcmp
- In_array
- array_search
- ....
漏洞分析
使用安全问题重置密码存在弱类型
if(empty($safequestion)) $safequestion = '';
if(empty($safeanswer)) $safeanswer = '';
if($row['safequestion'] == $safequestion && $row['safeanswer'] == $safeanswer)
{
sn($mid, $row['userid'], $row['email'], 'N');
exit();
}
- dedecms/member/resetpassword.php //78
- $safequestion 用户输入的安全问题
- $row['safequestion'] 数据库保存的安全问题
- $safeanswer 用户输入的安全问题回答
- $row['safeanswer'] 数据库保存的安全问题回答
如果该用户没有设置过任何安全问题。那么,
- $row['safequestion'] = 0
- 当 $safequestion = '0.0' 的时候
- 第一个 if(empty($safequestion)) 不成立
- 最后 if $row['safequestion'] == $safequestion 0 = '0.0' 成立
- 而 $row['safeanswer'] 原本就为空 导致第二个条件 $row['safeanswer'] == $safeanswer
- 从而进入SN函数,SN函数最后一个参数 Y 发送邮件,N不发送邮件
SN函数:
- SN函数主要负责发验证和发送邮件。
- 如果通过安全问题召回密码,那么直接构造修改URL的地址返回客户端直接修改
漏洞验证
- 安装DEDE
- 打开系统 系统基本参数 会员设置 开启会员功能
- POST /dede/member/resetpassword.php
- 参数 dopost=safequestion&gourl=&id=2&safequestion=0.0
- id 换成 对应的用户ID
- 返回的包
利用前提条件
- DEDE开启了会员功能
- 修改密码的会员没有设置安全问题
修复建议
- 把用户重制部分所有验证的部分替换成 '==' 替换成 '==='
漏洞原文
【漏洞分析】 织梦前台任意用户密码修改锦行 - 信息安全