几处cms路径穿越

admin 2022年3月19日23:52:55评论34 views字数 4641阅读15分28秒阅读模式

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

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

几处cms路径穿越

根据链接:

几处cms路径穿越


往回看下源码:


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后,通过

$dir = rtrim(I('get.path'), '/');

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

if (strpos($dir, 'template') === false) {
exit('error|目录错误!');
}

然后直接拼接到

$path = $root . str_replace('/', DIRECTORY_SEPARATOR, $dir);

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

$info['content'] = file_get_contents($path);//读取文件
//调用并显示
$this->assign('info', $info);
return $this->fetch();

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

几处cms路径穿越


修改包


几处cms路径穿越


响应


几处cms路径穿越


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


几处cms路径穿越


源码:

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;
}


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

几处cms路径穿越

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


几处cms路径穿越


请求包


几处cms路径穿越


通过路由找到源码:

// 下载
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直接拼接,没有经过过滤,利用

几处cms路径穿越

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


几处cms路径穿越

得到删除包:


几处cms路径穿越


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


几处cms路径穿越


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


几处cms路径穿越


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

几处cms路径穿越


二、admincmscontrallertemplate.contraller.php
找到模板管理,选中一个文件点击删除:


几处cms路径穿越


得到删除包


几处cms路径穿越


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


几处cms路径穿越


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

几处cms路径穿越


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

几处cms路径穿越


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


来源:先知

注:如有侵权请联系删除



几处cms路径穿越

欢迎大家加群一起讨论学习和交流
(此群已满200人,需要添加群主邀请)

几处cms路径穿越

从业精于勤而荒于嬉,

行成于思而毁于随。

原文始发于微信公众号(衡阳信安):几处cms路径穿越

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月19日23:52:55
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   几处cms路径穿越https://cn-sec.com/archives/834323.html

发表评论

匿名网友 填写信息