WEB攻防-PHP特性-CMS审计实例

前置知识:PHP函数缺陷

测试环境:MetInfo CMS

  1. 函数缺陷导致的任意文件读取

漏洞URL:/include/thumb.php?dir=

漏洞文件位置:MetInfo6.0.0\app\system\include\module\old_thumb.class.php

<?php


defined('IN_MET') or exit('No permission');

load::sys_class('web');

class old_thumb extends web{

      public function doshow(){
        global $_M;

         $dir = str_replace(array('../','./'), '', $_GET['dir']);
         echo $dir;
         echo "<br/>";
          echo !(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http');
          echo "<br/>";

        if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false){
            
            header("Content-type: image/jpeg");
            echo $dir;
            echo 11111111;
            ob_start();
            readfile($dir);
            
            ob_flush();
            flush();
            die;
        }

        if($_M['form']['pageset']){
          $path = $dir."&met-table={$_M['form']['met-table']}&met-field={$_M['form']['met-field']}";

        }else{
          $path = $dir;
        }
        $image =  thumb($path,$_M['form']['x'],$_M['form']['y']);
        if($_M['form']['pageset']){
          $img = explode('?', $image);
          $img = $img[0];
        }else{
          $img = $image;
        }
        if($img){
            header("Content-type: image/jpeg");
            ob_start();
            readfile(PATH_WEB.str_replace($_M['url']['site'], '', $img));
            echo PATH_WEB.str_replace($_M['url']['site'], '', $img);
            echo 2222222;
            ob_flush();
            flush();
        }

    }
}


?>

 

源码中,      $dir = str_replace(array('../','./'), '', $_GET['dir']);过滤了../和./,但str_replace是不迭代循环过滤的,可以双写绕过的

可以看到代码中 if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false)这个条件用于检测一个路径$dir是否是一个以'http'开头且不是相对于当前目录的(不包含'./')。但是,这样的判断方式并不完全准确,因为它只是检查了前4个字符是否为'http',而没有确保整个字符串是一个有效的URL。同时,检查'./'来排除相对路径的方式也是有限的,因为它没有考虑如'../'或其他相对路径形式。当我们试图构造playload:http://localhost/MetInfo/include/thumb.php?dir=http\.....//\config\config_db.php

readfile($dir);打开http\.....//\config\config_db.php这个路径是一个无效路径,所以继续看代码

if($_M['form']['pageset'])

在全局搜索pageset看到是一个跳转地址加参数pageset=1

而我们构造playload没有跳转动作,所以应该是不会满足条件的,也就是说构造的dir会直接赋值给$path

再看下一行 $image =  thumb($path,$_M['form']['x'],$_M['form']['y']);这里对path作了处理,应该是宽高处理,追踪thumb这个函数

找到最后返回调用的函数met_thumb

可以看到红框上面的又做了一次../和./的过滤,如果没有http会执行红框下面的代码,在$image = $this->get_thumb();追踪到get_thumb可以看到return file_exists($thumb_path) ? $this->thumb_url : $this->create_thumb();,继续追踪 $this->create_thumb();,可以看到会返回一个默认路径

 

完整代码

<?php

defined('IN_MET') or exit('No permission');



class image{

	/**
	 * 图片信息
	 * @var [type]
	 */
	public $image;

	/**
	 * 域名
	 * @var [type]
	 */
	public $host;

	/**
	 * 请求图片宽
	 * @var int
	 */
	public $x;

	/**
	 * 请求图片高
	 * @var int
	 */
	public $y;

	/**
	 * 生成图片宽
	 * @var [type]
	 */
	public $thumb_x;

	/**
	 * 生成图片高
	 * @var [type]
	 */
	public $thumb_y;

	/**
	 * 缩略图存放目录
	 * @var [type]
	 */
	public $thumb_dir;

	/**
	 * 缩略图路径
	 * @var [type]
	 */

	/**
	 * 缩略图url
	 * @var [type]
	 */
	public $thumb_url;

	public $thumb_path;


	public function met_thumb($image_path, $x = '', $y = ''){

		global $_M;
		if(!isset($image_path)){
			$image_path = $_M['url']['site'].'public/images/metinfo.gif';
		}
		$this->image_path = str_replace(array($_M['url']['site'],'../','./'), '', $image_path);
		// 如果地址为空 返回默认图片
		if(!$this->image_path){
			return $_M['url']['site'].'public/images/metinfo.gif';
		}
		// 如果去掉网址还有http就是外部链接图片 不需要缩略处理
		if(strstr($this->image_path, 'http')){
			return $this->image_path;
		}
		$this->x = is_numeric($x) ? intval($x) : false;
		$this->y = is_numeric($y) ? intval($y) : false;

		$this->image = pathinfo($this->image_path);
		$this->thumb_dir = PATH_WEB.'upload/thumb_src/';
		$this->thumb_path = $this->get_thumb_file() . $this->image['basename'];

		$image = $this->get_thumb();
		return $image;
	}


	public function get_thumb_file() {
		global $_M;
		$x = $this->x;
		$y = $this->y;

		if($path = explode('?', $this->image_path)){
			$image_path = $path[0];
		}else{
			$image_path = $this->image_path;
		}

		$s = file_get_contents(PATH_WEB.$image_path);

		$image = imagecreatefromstring($s);

		$width = imagesx($image);//获取原图片的宽
		$height = imagesy($image);//获取原图片的高
		if($x && $y) {
			$dirname = "{$x}_{$y}/";
			$this->thumb_x  = $x;
			$this->thumb_y  = $y;
		}

		if($x && !$y) {
			$dirname 		= "x_{$x}/";
			$this->thumb_x  = $x;
			$this->thumb_y  = $x / $width * $height;
		}

		if(!$x && $y) {
			$dirname 		= "y_{$y}/";
			$this->thumb_y  = $y;
			$this->thumb_x  = $y / $height * $width;
		}

		$this->thumb_url = $_M['url']['site'] . 'upload/thumb_src/' . $dirname . $this->image['basename'];

		$dirname = $this->thumb_dir . $dirname ;

		if(stristr(PHP_OS,"WIN")) {
			$dirname = @iconv("utf-8","GBK",$dirname);
		}

		return $dirname;
	}

	public function get_thumb() {
		if($path = explode('?', $this->thumb_path)){
			$thumb_path = $path[0];
		}else{
			$thumb_path = $this->thumb_path;
		}

		return file_exists($thumb_path) ? $this->thumb_url : $this->create_thumb();
	}

	public function create_thumb() {

		global $_M;
		$thumb = load::sys_class('thumb','new');
		$thumb->set('thumb_save_type',3);
		$thumb->set('thumb_kind',$_M['config']['thumb_kind']);
		$thumb->set('thumb_savepath',$this->get_thumb_file());
		$thumb->set('thumb_width',$this->thumb_x);
		$thumb->set('thumb_height',$this->thumb_y);
		$suf = '';
		if($path = explode('?', $this->image_path)){
			$image_path = $path[0];
			$suf .= '?'.$path[1];
		}else{
			$image_path = $this->image_path;
		}

		if($_M['config']['met_big_wate'] && strpos($image_path, 'watermark')!==false){
			$image_path = str_replace('watermark/', '', $image_path);
		}
		$image = $thumb->createthumb($image_path);
		if($_M['config']['met_thumb_wate'] && strpos($image_path, 'watermark')===false){
			$mark = load::sys_class('watermark','new');
			$mark->set('water_savepath',$this->get_thumb_file());
			$mark->set_system_thumb();
			$mark->create($image['path']);
		}


		if($image['error']){
            if (!$_M['config']['met_agents_switch']) {
                return $_M['url']['site'].'public/images/metinfo.gif'.$suf;
            }else{
                $met_agents_img =str_replace('../', '', $_M['config']['met_agents_img']);
                $image_path = $_M['url']['site'] . $met_agents_img;
                return $_M['url']['site'].$met_agents_img.$suf;
            }
		}

		return $_M['url']['site'].$image['path'].$suf;
	}


}

重点看红框部分,再贴一次上面的图

只要二次过滤后的路径有http就返回二次过滤的路径

回到漏洞页面代码,也就是$image接收thump处理后的一个二次过滤../和./的路径,

下面又if($_M['form']['pageset']),这里又直接执行else赋值给$img

最后一个判断可以看到 readfile(PATH_WEB.str_replace($_M['url']['site'], '', $img));

PATH_WEB是一个常量,包含了指定的路径

拼接我们传进来的值,而这个值会被二次过滤../和./,也就是说,我们需要构造一个绕过二次过滤的playload就可以任意读取已知路径的文件

/MetInfo/include/thumb.php?dir=ahttp\.....//\config\config_db.php

 注意:

  • http前面可以加任何字符来绕过if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false),但不能加后面,加前面就满足了substr(str_replace($_M['url']['site'], '', $dir),0,4)的条件
  • 第一个反斜杠也可以是/,只是为了闭合ahppt这个文件名,
  • 而第二个加了底纹的\不可以时候/,因为会被二次过滤,过滤后会变成ahttp\config\config_db.php,而\过滤之后是ahttp\..\config\config_db.php,才能使..\返回上一节目录
  • .. 的作用与之前的目录是否存在无关,它总是表示向上移动一个目录级别。而路径解析器会忽略任何不存在的目录部分,并继续处理剩余的有效部分。这就是为什么 ahttp\..\ 会返回到 MetInfo 这个目录,即使 ahttp\ 目录不存在。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/577026.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python用于高级异常检测和聚类的工具库之BanditPAM使用详解

概要 Python BanditPAM库是一个用于高级异常检测和聚类的工具,具有强大的特性和灵活的功能,可以发现数据中的异常点并进行有效的聚类分析。本文将详细介绍Python BanditPAM库的安装、特性、基本功能、高级功能以及总结。 安装 首先,需要安装Python BanditPAM库。 可以使用…

2024年智能手表行业线上市场销售数据分析

智能手表市场近几年随着各大厂商的加入&#xff0c;逐渐朝着专业化、智能化发展。从一开始被认为是“智商税”、“鸡肋产品”到如今可以成为人体心脑血管健康监测、专业运动测速、移动定位的“多功能电子管家”&#xff0c;智能手表市场仍在不断发展中。 根据鲸参谋数据显示&a…

Git -- 运用总结

文章目录 1. Git2. 基础/查阅2.1 基础/查阅 - git2.2 仓库 - remote2.3 清理 - rm/clean2.4 版本回退 - reset 3. 分支3.1 分支基础 - branch3.2 分支暂存更改 - stash3.3 分支切换 - checkout 4. 代码提交/拉取4.1 代码提交 - push4.2 代码拉取 - pull 1. Git 2. 基础/查阅 2…

2分钟自己写小游戏:使用js和css编写石头剪刀布小游戏、扫雷小游戏、五子棋小游戏。新手老手毕业论文都能用。

系列文章目录 【复制就能用1】2分钟玩转轮播图,unslider的详细用法 【复制就能用2】css实现转动的大风车&#xff0c;效果很不错。 【复制就能用3】2分钟自己写小游戏&#xff1a;剪刀石头布小游戏、扫雷游戏、五子棋小游戏 【复制就能用4】2024最新智慧医疗智慧医院大数据…

【声网】实现web端与uniapp微信小程序端音视频互动

实现web端与uniapp微信小程序端音视频互动 利用声网实现音视频互动 开通声网服务 注册声网账号 进入Console 成功登录控制台后&#xff0c;按照以下步骤创建一个声网项目&#xff1a; 展开控制台左上角下拉框&#xff0c;点击创建项目按钮。 在弹出的对话框内&#xff0c;依…

严把质量关,饮片追溯系统应用,信息化追溯助力用药安全-亿发

中药饮片作为我国中药产业的重要组成部分&#xff0c;在医药工业中发挥着至关重要的作用。近年来&#xff0c;中药饮片行业虽然取得了稳步增长&#xff0c;但同时也面临着产业集中度低、竞争激烈、质量良莠不齐等诸多挑战。为了应对这些问题&#xff0c;国家和各地纷纷加强中药…

URL路由基础与Django处理请求的过程分析

1. URL路由基础 对于高质量的Web应用来讲&#xff0c;使用简洁、优雅的URL设计模式非常有必要。Django框架允许设计人员自由地设计URL模式&#xff0c;而不用受到框架本身的约束。对于URL路由来讲&#xff0c;其主要实现了Web服务的入口。用户通过浏览器发送过来的任何请求&am…

如何在vue3+vite中优雅的使用iconify图标

前言 从Vue2迁移到Vue3&#xff0c;在使用上有着很大的差别。本文的话主要是针对图标的使用差别上进行分析&#xff0c;同时给出基于iconify图标库中unplugin-icons的用法。这里特殊说明一下&#xff1a;其实element-plus中用到的图标也是基于iconify图标库的&#xff0c;在我们…

【python】语言学习笔记--用来记录总结

请问以下变量哪些是tuple类型&#xff1a; a ()b (1)c [2]d (3,)e (4,5,6)answer在Python中&#xff0c;元组&#xff08;tuple&#xff09;是由逗号分隔的一组值组成的有序序列&#xff0c;通常用圆括号括起来。让我们逐个检查变量&#xff0c;看哪些是元组类型&#xff…

uniapp微信小程序开发踩坑日记:Vue3 + uniapp项目引入Echarts图表库

一、下载插件包 下载地址如下&#xff1a; lime-echart: 百度图表 echarts&#xff0c;uniapp、taro 使用 echarts 图表&#xff0c;全面兼容各平台小程序、H5、APP、Nvue 将以下两个文件夹放到项目的components里 同样地&#xff0c;将静态资源文件夹下内容放到自己项目的s…

openWebUI+ollamawindows+不用docker+webLite本地安装

openWebUI & ollama & windows & 不用docker & webLite 本地安装 总结一下安装教程 10核CPU16G内存 两个web框架都可以&#xff0c;先说简单的 ollama-webui-lite(https://github.com/ollama-webui/ollama-webui-lite) 轻量级&#xff0c;只使用nodejs 先装…

Unreal Engine子类化系统UButton

UE系统Button点击事件无法传递参数&#xff0c;通过子类化系统Button添加自定义参数扩展实现Button点击事件参数传递点击C类文件夹&#xff0c;在右边的区域点击鼠标右键&#xff0c;在弹出的菜单中选择“新建C类”在弹出的菜单中选中“显示所有类”&#xff0c;选择Button作为…

python版的openCV使用及下载

一、下载OpenCV模块 截止目前&#xff1a;现在OpenCV使用环境还是python3.8的版本所以咱们下载时记得用3.8版本的 终端下载&#xff1a;pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python 这是国内的镜像下载能快一些&#xff1b; 下载成功的标志&am…

Gin的中间件执行流程与用法

一、背景 我们在使用Gin框架进行Web开发的时候&#xff0c;基本上都会遇到登录拦截的场景。 例如某些接口必须在登录以后才能访问&#xff0c;根据登录用户的信息以及权限&#xff0c;拿到属于自己的数据, 反之&#xff0c;没登录过则直接拒绝访问。 那么我们怎么做到这些登录…

vue项目npm run build 打包之后如何在本地访问

vue项目npm run build 打包之后如何在本地访问 如果直接访问时&#xff0c;则会报错如下的信息&#xff1a; 报错码&#xff1a; Access to script at file:///D:/assets/index-DDVBfHVo.js from origin null has been blocked by CORS policy: Cross origin requests are on…

光伏无人机:巡检无人机解决巡检难题

随着科技的飞速发展&#xff0c;无人机技术已经广泛应用于各个领域&#xff0c;其中光伏无人机在解决光伏电站巡检难题方面发挥了重要作用。光伏无人机以其高效、精准、安全的特点&#xff0c;为光伏电站的巡检工作带来了革命性的变革。 光伏电站通常位于广阔的户外场地&#x…

用Python绘制了几张有趣的可视化图表

流程图存在于我们生活的方方面面&#xff0c;对于我们追踪项目的进展&#xff0c;做出各种事情的决策都有着巨大的帮助&#xff0c;而对于的Python而言呢&#xff0c;绘制流程图也是十分轻松的&#xff0c;今天小编就来为大家介绍两个用于绘制流程图的模块&#xff0c;我们先来…

【stomp 实战】Spring websocket使用详解和基本原理

spring框架对websocket有很好的支持&#xff0c;stomp协议作为websocket的子协议&#xff0c;Spring也做了很多封装&#xff0c;让我们在开发中易于使用。 学习使用Spring的Websocket模块&#xff0c;当然最好的办法就是看官网说明了。本篇文章对官网做一些简述和个人的理解。 …

srpingMVC基本使用

文章目录 1. springMVC基本功能(1) maven坐标导入(2) 编写表现层(3) springMVC配置类编写(4) 部署tomcat访问 2. 各种请求方法get请求post请求put请求delete请求请求参数提取 3. 请求参数接收(1) param参数接受封装到对象中 (2) 路劲参数接收集合接受时间类型接收json参数接收m…

【Jenkins】持续集成与交付 (一):深入理解什么是持续集成?

【Jenkins】持续集成与交付 (一):深入理解什么是持续集成? 1、软件开发生命周期与持续集成2、 持续集成的流程3、持续集成的好处4、Jenkins的应用实践5、结语💖The Begin💖点点关注,收藏不迷路💖 1、软件开发生命周期与持续集成 软件开发生命周期(SDLC)是指软件从…
最新文章