当前位置:主页 > 查看内容

极致CMS 1.9.2 审计与渗透测试

发布时间:2021-05-03 00:00| 位朋友查看

简介:前言 昨天看了极致CMS1.7今天再来看看极致CMS1.9版本修复了什么漏洞哪些漏洞还能用是不是还有新的东西。 下载链接 极致CMS 这次我下的是1.9.2的稳定版。 下载到本地搭建一下环境然后就是安装。安装的时候注意到了这里 我记得1.7版本安装的时候管理员和密码默……

前言

昨天看了极致CMS1.7,今天再来看看极致CMS1.9版本修复了什么漏洞,哪些漏洞还能用,是不是还有新的东西。
下载链接:
极致CMS
这次我下的是1.9.2的稳定版。
下载到本地搭建一下环境,然后就是安装。安装的时候注意到了这里:
在这里插入图片描述
我记得1.7版本安装的时候管理员和密码默认都是空的让自己填,这里的话默认的管理员和密码格式大概是jizhicms加上四个数字,这玩意怎么说呢,说是弱口令叭,但是9999*9999也挺难爆的,去爆破还不如找洞舒服。

看看后台

安装好之后还是先进一下后台,登录那里发现验证码那里比1.7的验证码难识别的多,感觉靠百度的那个基本不行了。而且试了一下,一个验证码可以利用无数次仍然没改,所以这个验证码的用处其实不大。

进入后台还是老样子传马试试,这次改了配置增加php的文件类型,仍然无法上传成功。
看一下源码;

$fileType = $this->webconf['fileType'];
if(strpos($fileType,strtolower($pix))===false   || stripos($pix,'php')!==false){
	$data['error'] =  "Error: 文件类型不允许上传!";
	$data['code'] = 1002;
	JsonReturn($data);
}

额外增加了对php的过滤,因此没法直接上传php了。考虑上传phtml这样的,但是默认肯定是不解析的,考虑传.htaccess,但是因为文件名不可控也不行。又全局查找了一下,能上传文件的有5个地方,全都进行了php后缀的过滤,因此文件上传这块感觉就已经彻底GG了。

又拿1.7版本的SQL注入的EXP打了一下也没成功,看一下代码上发生了什么改变:

$openid = format_param($openid,1);
$islive = M('member')->find(array('openid'=>$openid));

发现对$openid进行了一层format_parm函数的过滤,感觉有点眼熟啊,跟进一下:

/**
	参数过滤,格式化
**/
function format_param($value=null,$int=0,$default=false){
	if($value==null){ return '';}
	if($value===false && $default!==false){ return $default;}
	switch ($int){
		case 0://整数
			return (int)$value;
		case 1://字符串
			$value = SafeFilter($value);
			$value=htmlspecialchars(trim($value), ENT_QUOTES);
			if(version_compare(PHP_VERSION,'7.4','>=')){
				$value = addslashes($value);
			}else{
				if(!get_magic_quotes_gpc())$value = addslashes($value);
			}
			
			return $value;
		case 2://数组
			if($value=='')return '';
			array_walk_recursive($value, "array_format");
			return $value;
		case 3://浮点
			return (float)$value;
		case 4:
			if(version_compare(PHP_VERSION,'7.4','>=')){
				$value = addslashes($value);
			}else{
				if(!get_magic_quotes_gpc())$value = addslashes($value);
			}
			return trim($value);
	}
}

原来是这个过滤函数,SafeFilter是进行XSS过滤的不用管,$value=htmlspecialchars(trim($value), ENT_QUOTES);把单双引号都给html转义了,
此外还有一层对单双引号这样的加反斜杠的过滤。
再接着看一下find函数有什么变化:
在这里插入图片描述
跟进findAll方法,主要的变化就是加了一层这个:

$conditions = $this->__prepera_format($conditions);

具体不分析了,跟进一下看看代码逻辑,发现对于我们要进行SQL注入的话并无影响。接下来的就是进入query函数,也是有了变化:

	//执行 SQL 语句,返回PDOStatement对象,可以理解为结果集
	public function query($sql){
		$this->arrSql[] = $sql;
        $this->Statement = $this->pdo->query($sql);
        if ($this->Statement) {
			return $this;
        }else{
			$msg = $this->pdo->errorInfo();
			if($msg[2]){
				//Error_msg('数据库错误:' . $msg[2] . end($this->arrSql));
				$log_name = date('Y-m-d-H-i-s-').time();
				register_log('数据库错误:' . $msg[2] . end($this->arrSql),$log_name);
				exit;
			}
		}
	}

1.7版本是会直接把错误信息echo出来,这里的话是写入日志。不过没啥用,只要能注入的话就直接堆叠了,也不需要用到报错注入。

经过这波分析,基本可以确定的就是,CMS本身的find方法是存在漏洞的(说是漏洞也不太好),也就是说,find方法的第一个参数并没有在find方法内进行过滤,还是在进入find方法前进行了一波format_param函数的过滤,因此现在的思路就是找一个开发的遗漏,类似find方法这样的注入参数可控而且因为开发的疏忽,并没有进行format_param的过滤,就可以实现SQL注入了。

之前版本除去wechat这里的SQL注入外,url上的注入也是非常容易利用的,但是试了一下发现也不太行,REQUEST_URI都会被html进行转义,跟进了一下,发现是Fr.php的route方法的第207行调用了format_param,相当于对$_SERVER['REQUEST_URI']这整个部分都进行了一次过滤,因此关于路径上的SQL注入就彻底GG了。
在这里插入图片描述

尝试挖掘SQL注入(失败)

全局搜索了find方法一点一点的看,首先是这个HomeController下面的差点就成功的:

在这里插入图片描述
$id可以通过路由或者get之类的传参,路由的话之前分析过了,都会被html编码一次,因此这里get传的话是一点都没有被过滤的,直接拼接进SQL语句:

$details = M($this->type['molds'])->find(array('id'=>$id,'isshow'=>1));

我本来想着已经成功了,结果发现不行,跟进一下会发现M($this->type['molds'])出了问题:
在这里插入图片描述
跟进入就会发现本来的::table就是jz_menu了,结果这里又拼接了一次jz_:

self::$table = DB_PREFIX.strtolower(self::$table);

导致查的表变成了jz_jz_menu,然后就是前面我说的那个不影响SQL注入的预处理,把我自己打败了:
在这里插入图片描述

	//预处理SQL
	private function __prepera_format($rows)
	{
		$table = self::$table;
		$stmt = $this->db->getTable($table);  
		$stmt->execute();  
		$columns = $stmt->fetchAll(PDO::FETCH_CLASS);
		$newcol = array();
		foreach ($columns as $key => $value) {
			$field = strtolower($value->Field);
			if(stripos($value->Type,'int')!==false || stripos($value->Type,'decimal')!==false){
				
				if(isset($rows[$field])){
					if($rows[$field]!=='' && $rows[$field]!==false){
						$newcol[$field] = $rows[$field];
					}else{
						$newcol[$field] = 0;
					}
				}
				
			}else{
				if(isset($rows[$field])){
					if($rows[$field]!=='' && $rows[$field]!==false ){
						$newcol[$field] = $rows[$field];
					}else{
						$newcol[$field] = null;
					}
				}
				
				
			}
		}
		return $newcol;
		//return array_intersect_key($rows,$newcol);
	}

他会先预查一次表,把然后传入的$rows的键名在预查的表中才行,说白了就是如果正常查jz_menu表,表中有id这一列,因此就不影响。但是这里查的是jz_jz_menu表了,查不到任何东西,因此$rows这里就被扔掉了,加上查的是不存在的表,直接报错,也就失败了,草了气死我了。

看了一下1.7版本同样存在这个问题,这个主要的原因主要还是在于正常的话会传$table的名字,因此不会出现前面有前缀的情况。但是遇到默认的情况的话,开发处理的就有些问题了,

后来把find方法看完了,感觉没一个能SQL注入的,其他的update啥的以后再看了,太难了。

插件

这个插件仍然可以自由编辑代码安装后配置一下密码,再点配置输入密码仍然可以写文件,拿到shell。不过确实这是插件本身功能的问题,要不直接把这个插件删掉,要么就是更改功能,只能编辑html这样的静态文件,要么就是后台添加一个验证,安装插件需要验证一个单独的密码,这样可能才会好一点。不过现在SQL注入给修了,除了弱密码, 后台基本都进不来,所以其实挺安全的了。在这里插入图片描述

此外1.7版本中任意下载指定url的zip文件然后解压的漏洞1.9.2版本也没有修。

任意文件夹下载那里倒是加上了一层过滤:

在这里插入图片描述
因此没法任意下载文件夹了。

总结

总的来说1.9版本基本上已经算是牢不可破了,前台想要SQL注入真是tm的难,我现在就期待开发赶紧修了那个双层表前缀的问题(笑),不知道别的师傅挖到了SQL注入没。
这个下午基本上还是没审出什么东西来,还是太菜了,明天有空再看一天,还找不到洞就算了。呜呜呜太菜了。

;原文链接:https://blog.csdn.net/rfrder/article/details/115440467
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:**遇到“Cannot create file “不要慌** 下一篇:没有了

推荐图文


随机推荐