此漏洞已在PR #137中修复。
CodeFever Community是由蒲公英团队完整自主研发并基于MIT协议进行完整开源的Git代码托管仓库,其官方网址为https://codefever.pgyer.com/community,Github项目地址为https://github.com/PGYER/codefever。
CodeFever Community在用户请求找回密码时,会以电子邮箱地址为输入,使用TOTP算法生成找回密码需要的邮箱验证码。在默认配置的情况下,TOTP算法使用公开的默认密钥。这使得攻击者可以使用默认密钥计算任意一个账户找回密码需要的邮箱验证码,进而获取任意一个用户的登录权限。
所有版本。
master分支2023.2.7提交之前的版本。
在/user/resetPassword找回密码页面点击“获取验证码”后,后端服务器调用了application/controllers/user.php中的User::getResetPasswordCode函数向用户注册邮箱发送验证码。此处生成验证码使用的是TOTP算法,生成过程在application/libraries/service/Utility/TOTP.php中的TOTP::generate函数中实现。TOTP验证码生成与验证函数如下:
<?php
// this function use to generated uuid
namespace service\Utility;
class TOTP {
const SALT = 'codefever_salt';
const TOTP_REFRESH_INTERVAL = 30;
const TOTP_CHECK_WINDOW_MIN = -10;
const TOTP_CHECK_WINDOW_MAX = 10;
const PASSWORD_LENGTH = 6;
static private function hashInput (string $input) {
$salt = self::SALT;
if (TOTP_SALT) {
$salt = TOTP_SALT;
}
$input = $input ? $input : self::SALT;
return hash('sha256', md5($input) . md5($salt), FALSE);
}
static private function genTotp (string $hashedInput, int $timestamp) {
$sequence = floor($timestamp / 30);
$code = hash_hmac('sha256', $hashedInput . md5($sequence), md5($sequence), TRUE);
$finalValue = 0;
$index = 0;
do {
$finalValue += ord($code[$index]);
$finalValue = $finalValue << 2;
$index++;
} while (isset($code[$index]));
return $finalValue;
}
static private function trimTotp (int $sourceTotp) {
$trimedTotp = $sourceTotp % pow(10, self::PASSWORD_LENGTH);
$format = "%'.0". self::PASSWORD_LENGTH ."u";
return sprintf($format, abs($trimedTotp));
}
static function generate(string $input) {
return self::trimTotp(self::genTotp(self::hashInput($input), time()));
}
static function check(string $input, string $code) {
$hashedInput = self::hashInput($input);
$currentTime = time();
for (
$windowIndex = self::TOTP_CHECK_WINDOW_MIN;
$windowIndex <= self::TOTP_CHECK_WINDOW_MAX;
$windowIndex++
) {
if (
$code === self::trimTotp(
self::genTotp(
$hashedInput,
$currentTime + ($windowIndex * self::TOTP_REFRESH_INTERVAL)
)
)
) {
return TRUE;
}
}
return FALSE;
}
}
TOTP::generate函数由三者计算得到邮箱验证码:电子邮箱地址($input)、当前时间戳(time())、以及预先设置的密钥($salt)。其中,时间戳默认以30秒为时间窗口,同一个时间窗口内产生的验证码相同。在验证函数TOTP::check函数中额外验证前后各十个时间窗口产生的邮箱验证码,因此使用前后5分钟内产生的邮箱验证码均可通过验证。密钥($salt)默认定义在application/config/constants.php文件中:
// salt for totp generator
define('TOTP_SALT', 'codefever-salt');
因此在默认配置的情况下,攻击者可以使用上述函数以及默认密钥'codefever-salt'生成任意账号的邮箱验证码,进而修改密码获取账户登录权限。
详见exp.php文件。