shopex 接口设计问题导致某一类用户名密码重置

2015-02-05T00:00:00
ID SSV:93553
Type seebug
Reporter Root
Modified 2015-02-05T00:00:00

Description

简要描述:

shopex 接口设计问题导致某一类用户名密码重置

详细说明:

看到 shopex 有一个云登录机制,看代码:

``` // 云登陆回调地址 function ecopen_login_verify(){ // 签名验证 $token = $this->system->getConf('certificate.token'); ($_GET['sign'] && $this->get_ce_sign($_GET, $token) == $_GET['sign']) || exit("签名错误,云登陆无法完成"); // 为登陆者创建账户 $accountMdl = $this->system->loadModel('member/account'); $mem = $accountMdl->createotherlogin($_GET);

    if(!$mem){
        $this->splash('failed',$this->system->base_url(),__('登陆失败,请检查!'));
        exit;
    }

```

跟进去看看get_ce_sign

``` function get_ce_sign($params,$token){ $arg=""; ksort($params); reset($params); while (list ($key, $val) = each ($params)) { if ( 'sign' == $key ) continue;

        $arg.=$key."=".urlencode($val)."&";
    }
    return md5(substr($arg,0,count($arg)-2).$token);//去掉最后一个问号
}

```

这里默认安装时候token是个空值 所以之后md5是可以计算出来的,根据他的函数我们计算一个url http://localhost/shopex/?passport-ecopen_login_verify.html&open_type=xxxxxxx&open_id=yyyyy&nickname=xxxxx&email=test@163.com&password=mmmm&sign=76753b58491c5baa4c7885780c753e6a 跟进去$mem = $accountMdl->createotherlogin($_GET);

public function createotherlogin( $row ) { $user['member_refer'] = $row['open_type']; $toolsMdl = $this->system->loadModel( "utility/tools" ); $user['uname'] = $row['open_type']."_".$row['open_id']; $user['name'] = $row['realname'] ? $row['realname'] : $row['nickname']; $defcur = $this->db->selectrow( "SELECT cur_code FROM sdb_currency WHERE def_cur=\"true\"" ); $user['cur'] = $defcur['cur_code']; $user['member_lv_id'] = $this->system->loadModel( "member/level" )->getDefauleLv( ); $user['password'] = $this->encrypt_passwd_enhanced( $user['uname'].$Var_528.STORE_KEY ); $user['lang'] = "123"; $user['email'] = $row['email'] ? $row['email'] : "*@*.com"; if ( $user['email'] != "*@*.com" && !$toolsMdl->is_email( $user['email'] ) ) { return false; } $user['province'] = $row['province']; $user['city'] = $row['city']; $rs = $this->db->exec( "SELECT * FROM sdb_members WHERE uname=\"".$user['uname']."\" LIMIT 1" ); if ( $mem = $this->db->getRows( $rs, 1 ) ) { $user['member_id'] = $mem[0]['member_id']; if ( $sql = $this->db->getUpdateSQL( $rs, $user ) ) { $this->db->exec( $sql ); } } else { $user['regtime'] = NOW; $user['reg_ip'] = $this->db; $this->db->exec( $this->db->getInsertSQL( $rs, $user ) ); $user['member_id'] = $this->db->lastInsertId( ); } $user['secstr'] = $this->cookieValue( $user['member_id'] ); $user['open_type'] = $row['open_type']; return $user; }

这一段代码的意思就是,如果通过uname去查询的用户不存在的话,说明是个新用户 做插入操作,也就是云注册的新用户,如果这个用户存在的话就做更新资料操作 问题卡在了这里: $user['uname'] = $row['open_type']."_".$row['open_id']; 也就是说这个用户名必须中间有下划线 通过这一番描述可见,如果是通过云注册的用户,资料可以通过单一的用户名修改这个用户的资料,如果是非云注册的用户,那么如果该用户注册的时候,用户名里面有下划线,就可以操纵修改这个用户的相关资料,包括密码 我们来测试一下 发送url: http://localhost/shopex/?passport-ecopen_login_verify.html&open_type=xxxxxxx&open_id=yyyyy&nickname=xxxxx&email=test@163.com&password=mmmm&sign=76753b58491c5baa4c7885780c753e6a 后台抓取的第一个sql是:

<img src="https://images.seebug.org/upload/201502/041933394061eda9f032266a847d0b750459eac0.png" alt="1.png" width="600" onerror="javascript:errimg(this);">

在发送一次 抓看第二个sql:

<img src="https://images.seebug.org/upload/201502/041934281e136f6d33c4437d9c905919d93c97ea.png" alt="2.png" width="600" onerror="javascript:errimg(this);">

正好和猜想的逻辑一样,在分一下密码这里 $user['password'] = $this->encrypt_passwd_enhanced( $user['uname'].$Var_528.STORE_KEY );

public function encrypt_passwd_enhanced( $pwd, $uname, $regtime ) { if ( !$pwd || !$uname || !$regtime ) { return false; } $pwd = ( ( ( $pwd ) ).( $uname ).$regtime ); return "s".( $pwd, 0, 31 ); }

如果get传递过来的pwd 和 uname 和regtime都不为空的话 就会计算一个密码,这个密码我们也是可以控制的 唯一遗憾的就是只能重置云登录用户和用户uname里面有下划线的用户

漏洞证明: