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

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

缺陷编号:wooyun-2014-077405

漏洞标题:PHP云人才系统任意刷钱(附演示)

相关厂商:php云人才系统

漏洞作者: xiaoL

提交时间:2014-09-26 14:23

修复时间:2014-12-25 14:24

公开时间:2014-12-25 14:24

漏洞类型:设计缺陷/逻辑错误

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-09-26: 细节已通知厂商并且等待厂商处理中
2014-09-26: 厂商已经确认,细节仅向厂商公开
2014-09-29: 细节向第三方安全合作伙伴开放
2014-11-20: 细节向核心白帽子及相关领域专家公开
2014-11-30: 细节向普通白帽子公开
2014-12-10: 细节向实习白帽子公开
2014-12-25: 细节向公众公开

简要描述:

PHP云人才系统任意刷钱漏洞,演示详细过程,利用难度低0-0!

详细说明:

起因在member\model\com.class.php文件中:

function dingdan_action(){
if($_POST['price']){
if($_POST['comvip']){
$comvip=(int)$_POST['comvip'];
$ratinginfo = $this->obj->DB_select_once("company_rating","`id`='".$comvip."'");
$price = $ratinginfo['service_price'];
$data['type']='1';
}elseif($_POST['price_int']){
$price = $_POST['price_int']/$this->config['integral_proportion']; //integral_proportion = 20 只是简单的相除,没有判断正负。
$data['type']='2';
}elseif($_POST['price_msg']){
$price = $_POST['price_msg']/$this->config['integral_msg_proportion'];
$data['type']='5';
}else{
$this->obj->ACT_layer_msg("参数不正确,请正确填写!",8,$_SERVER['HTTP_REFERER']);
}
$dingdan=mktime().rand(10000,99999); //订单生产的订单号,使用时间戳加上随机数。
$data['order_id']=$dingdan;
$data['order_price']=$price;
$data['order_time']=mktime();
$data['order_state']="1";
$data['order_remark']=trim($_POST['remark']);
$data['uid']=$this->uid;
$data['rating']=$_POST['comvip'];
$data['integral']=$_POST['price_int'];
$id=$this->obj->insert_into("company_order",$data); //成功插入了数据库
if($id){
$this->obj->ACT_layer_msg("下单成功,请付款!",9,"index.php?c=payment&id=".$id);
}else{
$this->obj->ACT_layer_msg("提交失败,请重新提交订单!",8,$_SERVER['HTTP_REFERER']);
}
}else{
$this->obj->ACT_layer_msg("参数不正确,请正确填写!",8,$_SERVER['HTTP_REFERER']);
}
}


此处可以插入$_POST['price_int']=-20000 相当于 -1000元
接下来看api\tenpay\index.php文件中的逻辑:

if(!is_numeric($_POST['dingdan']))  //判断了是否为数字
{
die;
}
$userid=(int)$_COOKIE['uid'];
$_POST['is_invoice']=(int)$_POST['is_invoice']; //无用
$_POST['balance']=(int)$_POST['balance']; //化为整数了,此参数只要存在就行了,随便提交
$member_sql=$db->query("SELECT * FROM `".$db_config["def"]."member` WHERE `uid`='".$userid."' limit 1");
$member=mysql_fetch_array($member_sql);
if($member['username'] != $_COOKIE['username'] || $member['usertype'] != $_COOKIE['usertype']||md5($member['username'].$member['password'].$member['salt'])!=$_COOKIE['shell']){
echo '登录信息验证错误,请重新登录!';die;
}
$sql=$db->query("select * from `".$db_config["def"]."company_order` where `order_id`='$_POST[dingdan]'"); //根据订单号查询order
$row=mysql_fetch_array($sql);
if($_POST['balance']&&$userid){ //正常登陆用户,随便提交balance参数即可
$c_sql=$db->query("select `pay` from `".$db_config["def"]."company_statis` where `uid`='".$userid."'");
$company_statis=mysql_fetch_array($c_sql);
if($company_statis['pay']>=$row['order_price']){ //关键来了,判断用户余额是否大于订单,因为order_price 是负数,一定为true
$up_sql=$db->query("update `".$db_config["def"]."company_statis` set `pay`=`pay`-'".$row['order_price']."' where `uid`='".$userid."'"); //此处直接相减了,负负得正!金钱增加。漏洞触发。
mysql_fetch_array($up_sql);
$up_order=$db->query("update `".$db_config["def"]."company_order` set `order_price`='0'".$invoice_title." where `order_id`='".$row['order_id']."'"); //这里不影响,后面都不影响。
mysql_fetch_array($up_order);
$price=$row['order_price'];
}else{
$price=$company_statis['pay'];
$up_sql=$db->query("update `".$db_config["def"]."company_statis` set `pay`='0' where `uid`='".$userid."'");
$up_sql_status=mysql_fetch_array($up_sql);
$up_order=$db->query("update `".$db_config["def"]."company_order` set `order_price`=`order_price`-'".$price."'".$invoice_title." where `order_id`='".$row['order_id']."'");
mysql_fetch_array($up_order);
}
$insert_company_pay=$db->query("insert into `".$db_config["def"]."company_pay`(order_id,order_price,pay_time,pay_state,com_id,pay_remark,type) values('".$row['order_id']."','-".$price."','".time()."','2','".$userid."','".$row['order_remark']."','2')");
mysql_fetch_array($insert_company_pay);
$new_sql=$db->query("select * from `".$db_config["def"]."company_order` where `order_id`='".$row['order_id']."'");
$row=mysql_fetch_array($new_sql);
}


大致成因是这样的,利用起来也相当的简单。

在文件member\model\com.class.php中:
function paylog_action(){
include(CONFIG_PATH."db.data.php");
$this->yunset("arr_data",$arr_data);
$this->public_action();
/*
省略
*/
}else{
$urlarr=array("c"=>"paylog","page"=>"{{page}}");
$pageurl=$this->url("index","index",$urlarr);
$where="`uid`='".$this->uid."'";
$where.=" and `order_price`>0 order by order_time desc"; //根据这个逻辑只显示了订单额大于0的项目,因此订单号需要我们去猜测。
$this->get_page("company_order",$where,$pageurl,"10");
}
/*
省略
*/
}


1111.png


默认只显示正数订单,但是其实订单都是存在在数据库中的。

漏洞证明:

利用方法:
只要在短时间多次重放订单数据包,就能在一秒内拥有最多的订单数,然后跑一遍10000-99999的后缀即可了。
重发使用burpsuite,可以设置大线程。这里有个技巧就是第一个提交一定是一个正常的数据,这样就可以找到mktime前缀了。
演示一遍。
1、多线程提交订单

2222.png


2、只会显示第一个正常的订单

3333.png


3、数据库中显示订单存在

4444.png


开始遍历1411709332这个段的订单。订单前缀是在列表中直接显示的- -。
4、其中blance字段一定要有,值随意

6666.png


坐等跑完

7777.png


查看余额

9999.png


试过这样就可以使用了,可以买会员,比如上图的铜牌会员。

修复方案:

逻辑- -

版权声明:转载请注明来源 xiaoL@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2014-09-26 14:26

厂商回复:

感谢提供,我们会尽快修复!

最新状态:

暂无