继加入购物车时没有判断购买数量为负的情况之后,方维又暴了个严重的支付漏洞。出现了用户可以0元购买任何服务的情况。触目惊心,一下损失了上百万~

原因如下:
在/system/libs/cart.php 文件大约150行的地方,即按用户组取折扣的时候。

下面这段代码的第二行中的SQL语句有问题,也就是left join的错误使用 因为此时user表里用户信息是一定存在的,而user表中的group_id无论在user_group存不存在时,使用left join时,都会返回一条记录,$group_info是一个数组,而不会出现false的情况,于是 if($group_info&&$total_price>0)
一定会被执行,而当user表中的group_id在user_group不存在时,$group_info数组元素的值都为空,此时floatval($group_info[‘discount’]) 为0,于是$user_discount(用户折扣的价格)就等于需要支付的价格了,也就是应付钱为0!

//先计算用户等级折扣
$user_id = intval($GLOBALS['user_info']['id']);
$group_info = $GLOBALS['db']->getRow("select g.* from ".DB_PREFIX."user as u left join ".DB_PREFIX."user_group as g on u.group_id = g.id where u.id = ".$user_id);
if($group_info&&$total_price>0)
$user_discount = $total_price * (1-floatval($group_info['discount']));
else
$user_discount = 0;
$pay_price = $pay_price - $user_discount; //扣除用户折扣

修改很简单,也就是把left join改为 innner join ,但为什么会出现用户组不存在(该group_id在user_group表不存在)的情况,老实说我也还没有完全弄明白,但我发现在用户注册的时候有问题。
$user_data是直接从用户

在用户注册提交表单之后,可以看到提交的group_id字段(表单没有这个字段,但可以通过工具或者手工构造表单来进行提交)没有经过验证直接交给save_user 处理了。
在/app/Lib/shop/userModule.class.php155行,左右的地方。

require_once APP_ROOT_PATH . "system/libs/user.php";
$user_data = $_POST;
...
$res = save_user ( $user_data );

继续跟踪save_user,可以在system/libs/user.php 139行左右的地方看到这段处理,

//自动获取会员分组
if(intval($user_data['group_id'])!=0)
$user['group_id'] = $user_data['group_id'];
else
{
if($mode=='INSERT')
{
//获取默认会员组, 即升级积分最小的会员组
$user['group_id'] = $GLOBALS['db']->getOne("select id from ".DB_PREFIX."user_group order by score asc limit 1");
}
}

此处估计可以有两种方式被利用,
1. 当$_POST[‘group_id’] 设置为大于0的数时,就能随意设置自己的用户组了。
2. 当$_POST[‘group_id’] 为0时,如果执行的是UPDATE操作而非INSERT, 此时用户的用户组就可以设置成0了。比如可能用户修改帐户信息被这样调用的话。具体场景仍待观察。

所以为了防止用户注册时随意设置自己的用户组,可以在/app/Lib/shop/userModule.class.php执行save_user 即在执行 $res = save_user ( $user_data ); 前指定用户组,增加这行代码:

$user_data['group_id'] = $GLOBALS['db']->getOne("select id from ".DB_PREFIX."user_group order by score asc limit 1");

数据表的信息的处理:
===============================================

删除订单商品信息

delete from fanwe_deal_order_item where order_id in(select id from fanwe_deal_order where user_id =非法用户的id)

删除服务验证码

delete from fanwe_deal_order_vcode where order_id in(select id from fanwe_deal_order where user_id =非法用户的id)

对每个服务进行迭代,重置被购买数量

foreach( $GLOBALS['db']->getAll('select id from fanwe_deal') as $deal) {
$deal_id = $deal['id'];
$GLOBLAS['db']->query(" update fanwe_deal set buy_count=(SELECT sum( number ) FROM `fanwe_deal_order_item` WHERE deal_id =$deal_id) where id = $deal_id");

}

删除订单信息

delete from fanwe_deal_order where user_id=非法用户的id

将该用户的余额清零,用户组变为普通用户,一个由高富帅变成屌丝的节奏。-_|||

UPDATE `fanwe_user` SET `group_id` = '1',
`money` = '0.00' WHERE `fanwe_user`.`id` =非法用户的id;
- EOF -