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

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

缺陷编号:wooyun-2014-084000

漏洞标题:php云两处SQL二次注入

相关厂商:php云人才系统

漏洞作者: D&G

提交时间:2014-11-21 18:25

修复时间:2015-02-19 18:26

公开时间:2015-02-19 18:26

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2014-11-21: 细节已通知厂商并且等待厂商处理中
2014-11-21: 厂商已经确认,细节仅向厂商公开
2014-11-24: 细节向第三方安全合作伙伴开放
2015-01-15: 细节向核心白帽子及相关领域专家公开
2015-01-25: 细节向普通白帽子公开
2015-02-04: 细节向实习白帽子公开
2015-02-19: 细节向公众公开

简要描述:

php云两处二次注入

详细说明:

最新版。两个注入点。顺带一个绕过waf的小技巧。
第一处:/member/model/index.class.php
39行

function index_action()
{
$this->public_action();
$this->member_satic();
$this->com_cache();
$resume = $this->obj->DB_select_once("resume","`uid`='".$this->uid."'");
$expect=$this->obj->DB_select_once("resume_expect","`id`='".$resume['def_job']."'");
if($_GET['type']=="job")
{
$where="`job_post` in (".$expect['job_classid'].") and `status`<>'1' and `state`='1' and `sdate`<'".mktime()."' and `r_status`<>'2' and `edate`>'".mktime()."'";
}elseif($_GET['type']=="city"){
$where="`cityid`='".$expect['cityid']."' and `status`<>'1' and `state`='1' and `sdate`<'".mktime()."' and `r_status`<>'2' and `edate`>'".mktime()."'";
}else{
$where="`state`='1' and status<>'1' and `sdate`<'".mktime()."' and `r_status`<>'2' and `edate`>'".mktime()."'";
}
$rows=$this->obj->DB_select_all("company_job",$where." order by id desc limit 12","`name`,`id`,`salary`,`edu`,`edate`");


where 语句拼接了$expect['job_classid'].变量。而这个变量来自于$expect=$this->obj->DB_select_once("resume_expect","`id`='".$resume['def_job']."'"); resume_expect 表。
member/model/index.class.php 587行

function saveexpect_action()
{
if($_POST['submit'])
{
$eid=(int)$_POST['eid'];
unset($_POST['submit']);
unset($_POST['eid']);
unset($_POST['urlid']);
$_POST['name'] = iconv("utf-8", "gbk", $_POST['name']);
$where['id']=$eid;
$where['uid']=$this->uid;
$_POST['lastupdate']=time();
if($eid=="")
{
$num=$this->obj->DB_select_num("resume_expect","`uid`='".$this->uid."'");
var_dump($num);
if($num>=$this->config['user_number'])
{
echo 1;die;
}
$_POST['uid']=$this->uid;
$nid=$this->obj->insert_into("resume_expect",$_POST);
if ($nid)
{


可以看到整个$_POST插入到了expect表中。完全是可控的。
测试过程。因为phpyun有两个waf,360就不说了。phpyun自带的依然可以白名单绕过。这里说一下自带的waf。

function gpc2sql($str,$str2) {
if(preg_match("/select|insert|update|delete|union|into|load_file|outfile/is", $str))
{
exit(safe_pape());
}
if(preg_match("/select|insert|update|delete|union|into|load_file|outfile/is", $str2))
{
exit(safe_pape());
}
$arr=array(" and "=>" an d "," or "=>" Or ","%20"=>" ","select"=>"Select","update"=>"Update","count"=>"Count","chr"=>"Chr","truncate"=>"Truncate","union"=>"Union","delete"=>"Delete","insert"=>"Insert","<"=>"&lt;",">"=>"&gt;","\""=>"&quot;","'"=>"&acute;","--"=>"- -");

foreach($arr as $key=>$v){
$str = preg_replace('/'.$key.'/isU',$v,$str);
}
return $str;
}


这个函数直接过滤了select|insert|update|delete|union|into|load_file|outfile 关键字,$arr=array(" and "=>" an d "," or "=>" Or ","%20"=>" ","select"=>"Select","update"=>"Update","count"=>"Count","chr"=>"Chr","truncate"=>"Truncate","union"=>"Union","delete"=>"Delete","insert"=>"Insert","<"=>"&lt;",">"=>"&gt;","\""=>"&quot;","'"=>"&acute;","--"=>"- -"); 这里之前把%20替换为空。之前有人提的利用这里引入or关键字的方式就不可以了。这个过滤还是很变态的。所以这里尝试进行延时注入。
其中过滤sleep的正则是这样的:

sleep\s*?\\([\d\.]+?\\)


看了以前原来已经前辈发过了。 WooYun: 360webscan正则不当可被绕过进行SQL注入
sleep里面进行算数运算就可以了。这里说一下别的方法:
比如sleep((11)),多加一层括号,sleep((select 2)),等等。所以 WooYun: 360webscan正则不当可被绕过进行SQL注入 这里分析的改成benchmark这样也是不安全的。

benchmark\s*?\\(\d+?|sleep\s*?\\([\d\.]+?\\)


最彻底的就是sleep\s*?\(.*\)进行过滤。
最后说一下这里的利用过程。
首先登陆,post数据到数据库。

选区_113.jpg


选区_114.jpg


访问一下url触发。

选区_116.jpg


所以这里实现的绕过也就是前辈说过的

如果我们想让服务器挂掉或者查询当前的数据库环境,很容易,我们可以很轻松的sleep或者获取当前运行的数据库信息了,这些不依赖select字符的事情我们都可以做了。


第二个点存在招聘会的地方,也是二次注入,写数据的时候需要后台审核。
企业预订的时候,抓包。

选区_118.jpg


修改GET /phpyun3.1/index.php?m=ajax&c=zphcom&uid=5&pid=1&jobid=2 HTTP/1.1
jobid为注入payload。
然后查看参会企业触发。只是默认情况下,企业申请需要管理员审核。

选区_119.jpg


相关代码:model/zph.class.php
23行:

function com_action()
{
$this->job_cache();
$row=$this->obj->DB_select_once("zhaopinhui","`id`='".(int)$_GET['id']."'");
$this->yunset("row",$row);
$where="`zid`='".(int)$_GET['id']."' and status='1'";
var_dump($where);
$urlarr["c"]=$_GET['c'];
$urlarr["id"]=$_GET['id'];
$urlarr["page"]="{{page}}";
$pageurl=$this->url("index",$_GET['m'],$urlarr,"1");
$rows=$this->get_page("zhaopinhui_com",$where." order by id desc",$pageurl,"13");
if(is_array($rows)){
foreach($rows as $key=>$v){
$rows[$key]['comname']=$this->obj->get_comname($v['uid']);
$rows[$key]['job']=$this->obj->DB_select_all("company_job","id in (".$v['jobid'].") and `status`<>'1' and `r_status`<>'2'","name,id");
}
}


写数据的代码位于model/ajax.class.php894 line

function zphcom_action()
{
if(!$this->uid || !$this->username || $_COOKIE['usertype']!=2 || $this->uid!=$_GET['uid'])
{
$arr['status']=0;
$arr['content']=iconv("gbk","utf-8","您不是企业用户或者还没有登录,<a href='index.php?m=login&usertype=2'>请先登录</a>");
}elseif(!$_GET['pid']){
$arr['status']=0;
$arr['content']=iconv("gbk","utf-8","你没有选择招聘会");
}elseif(!$_GET['jobid']){
$arr['status']=0;
$arr['content']=iconv("gbk","utf-8","你还没有选择职位");
}elseif(is_array($this->obj->DB_select_once("zhaopinhui_com","uid='".(int)$_GET['uid']."' and zid='".(int)$_GET['pid']."'"))){
$arr['status']=0;
$arr['content']=iconv("gbk","utf-8","您已经参与该招聘会");
}else{
$jobidarr=@explode(",",$_GET['jobid']);
$array=array();
foreach($jobidarr as $v){
if(!in_array($v,$array)){
$array[]=$v;
}
}
$sql['uid']=$_GET['uid'];
$sql['zid']=$_GET['pid'];
$sql['jobid']=@implode(",",$array);
$sql['ctime']=mktime();
$sql['status']=0;
$id=$this->obj->insert_into("zhaopinhui_com",$sql);


漏洞证明:

选区_116.jpg

修复方案:

版权声明:转载请注明来源 D&G@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

确认时间:2014-11-21 20:02

厂商回复:

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

最新状态:

暂无