最新版。两个注入点。顺带一个绕过waf的小技巧。
第一处:/member/model/index.class.php
39行
code 区域 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行
code 区域 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。
code 区域 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","<"=>"<",">"=>">","\""=>""","'"=>"´","--"=>"- -");
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","<"=>"<",">"=>">","\""=>""","'"=>"´","--"=>"- -"); 这里之前把%20替换为空。之前有人提的利用这里引入or关键字的方式就不可以了。这个过滤还是很变态的。所以这里尝试进行延时注入。
其中过滤sleep的正则是这样的:
code 区域 sleep\s*?\\([\d\.]+?\\)
看了以前原来已经前辈发过了。http://**.**.**.**/bugs/wooyun-2014-073271
sleep里面进行算数运算就可以了。这里说一下别的方法:
比如sleep((11)),多加一层括号,sleep((select 2)),等等。所以http://**.**.**.**/bugs/wooyun-2014-073271 这里分析的改成benchmark这样也是不安全的。
code 区域 benchmark\s*?\\(\d+?|sleep\s*?\\([\d\.]+?\\)
最彻底的就是sleep\s*?\(.*\)进行过滤。
最后说一下这里的利用过程。
首先登陆,post数据到数据库。
访问一下url触发。
所以这里实现的绕过也就是前辈说过的
code 区域 如果我们想让服务器挂掉或者查询当前的数据库环境,很容易,我们可以很轻松的sleep或者获取当前运行的数据库信息了,这些不依赖select字符的事情我们都可以做了。
第二个点存在招聘会的地方,也是二次注入,写数据的时候需要后台审核。
企业预订的时候,抓包。
修改GET /phpyun3.1/index.php?m=ajax&c=zphcom&uid=5&pid=1&jobid=2 HTTP/1.1
jobid为注入payload。
然后查看参会企业触发。只是默认情况下,企业申请需要管理员审核。
相关代码:model/zph.class.php
23行:
code 区域 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
code 区域 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);