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

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

缺陷编号:wooyun-2014-075752

漏洞标题:php云人才系统 小漏洞一步步getshell(后台)

相关厂商:php云人才系统

漏洞作者: menmen519

提交时间:2014-09-15 15:30

修复时间:2014-12-14 15:32

公开时间:2014-12-14 15:32

漏洞类型:文件包含

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

php云人才系统 小漏洞一步步getshell,这里包含了php与mysql交互时候的特性(也算一个漏洞),还有phpyun自身图片的验证机制问题,等等,步骤比较艰辛,本来想在这里搞一个csrf呢,找了半天没有找到,到时找到一大堆xss,这里就不利用xss了,且看分析

详细说明:

首先我们做一个小测试:
对于mysql存储来说,建站者都会给每一个字段设置长度,然后当我们插入进去的数据长度超过了设置的长度,那么mysql是不会报错,然而会自然截断存储,这个就给我们编写程序的人留下了隐患。
利用场景分析
1.如果你上传的目录会保存到数据库里面,并且这里上传的文件采用白名单,那么我们就可以根据数据库这个特性绕过程序判断,然后进入数据库,存储一个不在白名单内的文件路径
2.当我们二次利用这个东西的时候,比如说include 或者required 就会执行php代码
发散思考,其实这个思路不仅仅利用在文件这里,我只是举个例子,比如说如果么有对email的长度做验证,那么我们就可以注册一个和管理员一样的email,当后续用这个email查询验证时候,我们所有的回话就是管理员的,这里不做赘述
开始进行测试:

3.png


这里我们创建一个有两列,长度为5的字段,然后我们插入一个大于5的姓名,看看效果会怎样
insert into vff values('xxxxxxxxxx','xx')
我们发现结果里面就只有五个长度:

4.png


这里我们在延伸一下,我们插入
insert into vff values('123 sdsd','xx')

5.png


我们在用
select * from vff where name = '123'
这个是可以取出来的

6.png


这里的东西不多赘述,下来我们直接看phpyun里面的代码:
corn.class.php:(line:94-100):

function run_action(){
if($_GET['id'])
{
$this->cron($_GET['id']);
}
$this->layer_msg('计划任务(ID:'.$_GET["id"].')执行成功!',9,0,"index.php?m=cron");
}


我们跟到$this->cron里面去看看:
common.php:(lines:1987-1999):

if($timestamp)
{
krsort($timestamp);
$croncache = current($timestamp);
ignore_user_abort();
set_time_limit(600);

if(file_exists(LIB_PATH.'cron/'.$croncache['dir']))
{
include(LIB_PATH.'cron/'.$croncache['dir']);
}
$nexttime = $this->nextexe($croncache);


看到了LIB_PATH.'cron/'.$croncache['dir'],然后如果存在则进入到了引用函数,执行了,
那么我们来分析一下$croncache['dir'],从哪里来的.......
cron.class.php:(lines:63-67):

if(!$id){
$_POST["ctime"]=mktime();
$nbid=$this->obj->insert_into("cron",$_POST);
$alert="计划任务(id:".$nbid.")添加成功!";
$this->croncache();


这里明显就是保存之后,然后生成缓存文件,跟到缓存文件继续查看:
cache.class.php:(lines:38-55)

public function cron_cache($dir){
$rows=$this->obj->DB_select_all("cron","`display`='1' order by id asc");
if(is_array($rows)){
foreach($rows as $key=>$value){
$cron_cache[$key]['id']=$value["id"];
$cron_cache[$key]['dir']=$value["dir"];
$cron_cache[$key]['type']=$value["type"];
$cron_cache[$key]['week']=$value["week"];
$cron_cache[$key]['month']=$value["month"];
$cron_cache[$key]['hour']=$value["hour"];
$cron_cache[$key]['minute']=$value["minute"];
$cron_cache[$key]['nexttime']=$value["nexttime"];
}
}
$data['cron']=ArrayToString2($cron_cache);
return $this->obj->made_web_array($this->cachedir.$dir,$data);
}


看到这里大家都明白了$cron_cache[$key]['dir']=$value["dir"];是从我们刚才存储到数据库里面的dir取出来的,我们在回头看看,刚才的那个有什么限制,
cron.class.php:(line:56-59):

$dirArr = explode('.',$_POST['dir']);
if(end($dirArr)!='php'){
$this->obj->ACT_layer_msg("无效的执行文件!",8,"index.php?m=cron");
}


发现这里只能是php文件,当然了根据刚才我们的思路,我们可以绕过去的,我们进入后台:

7.png


1.png


这样一来这两张图,就可以把一个vvvv.png,存储到数据库中了,我们重新上传一个:

2.png


然后我们查看数据库,

8.png


我们在去界面的另外一个地方点击执行

9.png


10.png


前面的着所有的一切,已经正式一个东西,此处可以绕过,并且通过文件包含可以执行代码
那么这个图片码怎么搞定,我们经过尝试,phpyun测试了上传头像和上传身份证一边,只有上传身份证没有对图片的内容做深度校验:

11.png


我们上传后,看看上传上去的文件路径,

12.png


我们看看图片内容改变了没有:

13.png


果真这里没有变化,后续的我就不多说了,直接把那个shell.png换掉就可以了

漏洞证明:

修复方案:

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


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:8

确认时间:2014-09-15 15:41

厂商回复:

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

最新状态:

暂无