极致CMS 1.9.2 审计与渗透测试

前言

昨天看了极致CMS1.7,今天再来看看极致CMS1.9版本修复了什么漏洞还能用,是不是还有新的东西。
下载链接:
极致CMS
这次我下的是1.9.2的稳定版。
下载到本地搭建一下环境,然后就是安装。安装的时候注意到了这里:
极致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函数有什么变化:
极致CMS 1.9.2 审计与渗透测试
跟进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了。
极致CMS 1.9.2 审计与渗透测试

尝试挖掘SQL注入(失败)

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

极致CMS 1.9.2 审计与渗透测试
$id可以通过路由或者get之类的传参,路由的话之前分析过了,都会被html编码一次,因此这里get传的话是一点都没有被过滤的,直接拼接进SQL语句:

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

我本来想着已经成功了,结果发现不行,跟进一下会发现M($this->type['molds'])出了问题:
极致CMS 1.9.2 审计与渗透测试
跟进入就会发现本来的::table就是jz_menu了,结果这里又拼接了一次jz_:

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

导致查的表变成了jz_jz_menu,然后就是前面我说的那个不影响SQL注入的预处理,把我自己打败了:
极致CMS 1.9.2 审计与渗透测试

	//预处理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注入给修了,除了弱密码, 后台基本都进不来,所以其实挺安全的了。极致CMS 1.9.2 审计与渗透测试

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

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

极致CMS 1.9.2 审计与渗透测试
因此没法任意下载文件夹了。

总结

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

版权声明:玥玥 发表于 2021-04-06 3:41:57。
转载请注明:极致CMS 1.9.2 审计与渗透测试 | 女黑客导航