前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >几处cms路径穿越

几处cms路径穿越

作者头像
用户8478399
发布2022-09-22 19:44:24
7000
发布2022-09-22 19:44:24
举报
文章被收录于专栏:White OWL

前言 记录一下最近碰到的几处cms路径穿越的问题(均在后台),均已提交CNVD。

正文 1.某cms的任意文件读取和删除 这个cms目前还是处于更新的状态,来到更多功能-模板管理-新建文件:发现会报错:

根据链接:

往回看下源码:

代码语言:javascript
复制
function addFile() {
        $root = app()->getRootPath() . 'public' . DIRECTORY_SEPARATOR;
        if (!$this->request->isPost()) {
            $dir = rtrim(I('get.path'), '/');
            if (strpos($dir, 'template') === false) {
                exit('error|目录错误!');
            }
            $path = $root . str_replace('/', DIRECTORY_SEPARATOR, $dir);
            $info = [
                'name' => 'newfile.html',
                'content' => '',
                'mode' => 'htmlmixed',
                'isNew' => true,
                'path' => $dir,
            ];
            if (is_file($path)) {
                $parts = pathinfo($path);
                $dir = str_replace('/' . $parts['basename'], '', $dir);
                $info['name'] = $parts['basename'];
                $info['content'] = file_get_contents($path);
                $info['isNew'] = false;
                if ($parts['extension'] == 'js') {
                    $info['mode'] = 'text/javascript';
                } elseif ($parts['extension'] == 'css') {
                    $info['mode'] = 'text/css';
                } elseif ($parts['extension'] == 'json') {
                    $info['mode'] = 'application/json';
                }
            } elseif (is_dir($path)) {
                strpos($path, '.') !== false and exit('error|目录错误!');
            } else {
                exit('error|目录错误!');
            }
            $this->assign('dir', $dir);
            $this->assign('info', $info);
            return $this->fetch();
        }
        $dir = rtrim(I('post.path'), '/');
        $name = I('post.name');
        $content = I('post.content');

        if (strpos($dir, 'template') === false) $this->error('目录错误');
        $path = $root . str_replace('/', DIRECTORY_SEPARATOR, $dir);
        if (is_file($path)) {
            $parts = pathinfo($path);
            $dir = str_replace('/' . $parts['basename'], '', $dir);
            $new = str_replace($parts['basename'], $name, $path);
            $parts = pathinfo($new);
            if (!in_array($parts['extension'], ['js', 'html', 'css', 'txt', 'json'])) {
                $this->error('只允许操作文件类型如下:html|js|css|txt|json');
            }
            file_put_contents($path, $content);
            rename($path, $new) or $this->error('操作失败,请检查文件目录权限!');
        } elseif (is_dir($path)) {
            $path = $path . DIRECTORY_SEPARATOR . $name;
            $parts = pathinfo($path);
            if (!in_array($parts['extension'], ['js', 'html', 'css', 'txt', 'json'])) {
                $this->error('只允许操作文件类型如下:html|js|css|txt|json');
            }
            $rs = file_put_contents($path, $content);
            $rs === false and $this->error('操作失败,请检查文件目录权限!');
        } else {
            $this->error('目录错误!');
        }
        $this->success('操作成功!', U('Template/fileList') . '?path=' . urlencode($dir));
    }

}

get请求进入第一个if后,通过

代码语言:javascript
复制
$dir = rtrim(I('get.path'), '/');

获取path参数,经过一个判断

代码语言:javascript
复制
if (strpos($dir, 'template') === false) {
                exit('error|目录错误!');
            }

然后直接拼接到

代码语言:javascript
复制
$path = $root . str_replace('/', DIRECTORY_SEPARATOR, $dir);

然后通过下面代码返回结果:

代码语言:javascript
复制
$info['content'] = file_get_contents($path);//读取文件
//调用并显示
$this->assign('info', $info);
return $this->fetch();

利用(为了绕过判断,请求路径用template/..实行): 原始包

修改包

响应

通篇来看该cms的文件操作通过数据库实现,因此一定程度上避免了该类问题的发生。 后台清除缓存:

源码:

代码语言:javascript
复制
function clearCache() {
        if (!$this->request->isPost()) {
            return $this->fetch();
        }
        if (!function_exists('unlink')) {
            $this->error('php.ini未开启unlink函数,请联系空间商处理!');
        }

        $clear = I('post.clearCache', []);
        clearCache($clear);

        $this->success('操作成功');

    }
//跟进clearCache
function clearCache($clears = []) {
    if ($clears === true || $clears === 'all') {
        $clears = ['cache', 'log', 'temp'];
    }

    $apps = C('config.apps');//清除的应用
    $runtime = app()->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR;
    foreach ($clears as $item) {
        if ($item == 'cache') {
            delFile($runtime . $item, true);
            continue;
        }
        if ($item == 'log') {
            delFile($runtime . $item, true);
        }
        foreach ($apps as $app) {
            $path = $runtime . $app . DIRECTORY_SEPARATOR . $item;
            delFile($path, true);
        }
    }

    /*清除旧升级备份包,保留最后一个备份文件*/
    $backupArr = glob($runtime . 'data/backup/v*_www');
    for ($i = 0; $i < count($backupArr) - 1; $i++) {
        delFile($backupArr[$i], true);
    }

    delFile($runtime . 'schema');
    delFile($runtime . 'log');//调试时生成的日志文件

    return true;
}

原理跟上面类似,也是直接拼接:

2.某cms任意文件下载 该cms也是处于更新状态,系统管理-数据还原-备份下载

请求包

通过路由找到源码:

代码语言:javascript
复制
// 下载
    public function downfile(string $name)
{
        $file_name = $name; //得到文件名
        header("Content-type:text/html;charset=utf-8");
        $file_name = iconv("utf-8", "gb2312", $file_name); // 转换编码
        $file_sub_path = $this->config['path']; //确保文件在这个路径下面,换成你文件所在的路径
        $file_path = $file_sub_path . $file_name;
        # 将反斜杠 替换成正斜杠
        $file_path = str_replace('\\', '/', $file_path);
        if (!file_exists($file_path)) {
            $this->error($file_path);exit; //如果提示这个错误,很可能你的路径不对,可以打印$file_sub_path查看
        }
        $fp = fopen($file_path, "r"); // 以可读的方式打开这个文件
        # 如果出现图片无法打开,可以在这个位置添加函数
        ob_clean(); # 清空擦掉,输出缓冲区。
        $file_size = filesize($file_path);
        //下载文件需要用到的头
        Header("Content-type: application/octet-stream");
        Header("Accept-Ranges: bytes");
        Header("Accept-Length:" . $file_size);
        Header("Content-Disposition: attachment; filename = " . $file_name);
        $buffer = 1024000;
        $file_count = 0;
        while (!feof($fp) && $file_count < $file_size) {
            $file_con = fread($fp, $buffer);
            $file_count += $buffer;
            echo $file_con;
        }
        fclose($fp); //关闭这个打开的文件
    }

这个$file_name直接拼接,没有经过过滤,利用

3.某cms两处任意文件删除 该cms较老,且处于停更状态,一次偶然机会碰到的。 一、后台附件管理-图片管理可删除图片,

得到删除包:

ids和path可控,找到对应方法:admincms\contraller\upfile.contraller.php

传入的ids 用 “,” 进行分割,然后直接赋值没有过滤,跟进$this->pagebls['path']

发现也是直接赋值,没有过滤,修改ids 为 ,../s,txt, 的形式

二、admincms\contraller\template.contraller.php

找到模板管理,选中一个文件点击删除:

得到删除包

发现id[]是可控的,对应到源码:

发现$idd可控,跟进$this->pagebls['path']

发现$this->pagebls['path']也可控,修改id为id[]=../s.txt

结尾 这东西就是图一乐啊,继续搬砖了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 White OWL 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档