Browse Source

修正存在命令执行漏洞的问题

tags/6.2.0
tianya 2 years ago
parent
commit
695f393787
7 changed files with 526 additions and 42 deletions
  1. +7
    -3
      src/system/common.inc.php
  2. +15
    -0
      src/system/dedetag.class.php
  3. +9
    -4
      src/system/helpers/channelunit.helper.php
  4. +459
    -0
      src/system/helpers/code.helper.php
  5. +7
    -1
      src/system/taglib/php.lib.php
  6. +1
    -0
      src/system/taglib/tag.lib.php
  7. +28
    -34
      src/theme/templets/singlepage.htm

+ 7
- 3
src/system/common.inc.php View File

@@ -6,12 +6,16 @@
* @license https://www.dedebiz.com/license
* @link https://www.dedebiz.com
*/
//生产环境使用production,如果采用dev模式,会有一些php的报错信息提示,便于开发调试
//生产环境使用`production`,如果采用`dev`模式,会有一些php的报错信息提示,便于开发调试
if (!defined('DEDE_ENVIRONMENT')) {
define('DEDE_ENVIRONMENT', 'production');
define('DEDE_ENVIRONMENT', 'dev');
}
if (!defined('DEBUG_LEVEL')) {
define('DEBUG_LEVEL', FALSE);//如果设置为TRUE则会打印执行SQL的时间和标签加载时间方便调试
if (DEDE_ENVIRONMENT == 'production') {
define('DEBUG_LEVEL', FALSE);
} else {
define('DEBUG_LEVEL', TRUE);
}
}
if (DEDE_ENVIRONMENT == 'production') {
ini_set('display_errors', 0);


+ 15
- 0
src/system/dedetag.class.php View File

@@ -567,6 +567,14 @@ class DedeTagParse
$phpcode = $refObj->GetInnerText();
}
$phpcode = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeMeValue', $phpcode);
// 校验代码安全
$error = checkCode($phpcode);
if ($error) {
if (DEBUG_LEVEL) {
echo htmlErrors($error);
}
return;
}
try {
@eval($phpcode);
$this->CTags[$i]->TagValue = $DedeMeValue;
@@ -807,6 +815,13 @@ class DedeTagParse
$functionname = str_replace("\"}", "\"]", $functionname);
$functionname = preg_replace("/'@me'|\"@me\"|@me/i", '$DedeFieldValue', $functionname);
$functionname = "\$DedeFieldValue = ".$functionname;
$error = checkCode($functionname);
if ($error) {
if (DEBUG_LEVEL) {
echo htmlErrors($error);
}
return "";
}
try {
@eval($functionname.";");
if (empty($DedeFieldValue)) {


+ 9
- 4
src/system/helpers/channelunit.helper.php View File

@@ -412,10 +412,15 @@ function FormatScript($atme)
function FillAttsDefault(&$atts, $attlist)
{
$attlists = explode(',', (string)$attlist);
for ($i = 0; isset($attlists[$i]); $i++) {
list($k, $v) = explode('|', $attlists[$i]);
if (!isset($atts[$k])) {
$atts[$k] = $v;
if (is_array($attlists)) {
for ($i = 0; isset($attlists[$i]); $i++) {
if (empty($attlists[$i])) {
continue;
}
list($k, $v) = explode('|', $attlists[$i]);
if (!isset($atts[$k])) {
$atts[$k] = $v;
}
}
}
}


+ 459
- 0
src/system/helpers/code.helper.php View File

@@ -0,0 +1,459 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
// 允许的函数
$GLOBALS['allowedCalls'] = array(
// 系统
'var_dump',
// 数学
'ceil',
'floor',
'fmod',
'log',
'mt_rand',
'mt_srand',
'pow',
'rand',
'sqrt',
'srand',
// 变量
'empty',
'floatval',
'intval',
'is_array',
'is_binary',
'is_bool',
'is_double',
'is_float',
'is_int',
'is_integer',
'is_long',
'is_null',
'is_numeric',
'is_real',
'is_scalar',
'is_string',
'is_unicode',
'isset',
'strval',
'unset',
// 数组
'array_change_key_case',
'array_chunk',
'array_combine',
'array_count_values',
'array_diff_assoc',
'array_diff_key',
'array_diff',
'array_fill_keys',
'array_fill',
'array_flip',
'array_intersect_assoc',
'array_intersect_key',
'array_intersect',
'array_key_exists',
'array_keys',
'array_merge_recursive',
'array_merge',
'array_multisort',
'array_pad',
'array_pop',
'array_product',
'array_push',
'array_rand',
'array_reverse',
'array_search',
'array_shift',
'array_slice',
'array_splice',
'array_sum',
'array_unique',
'array_unshift',
'array_values',
'array',
'arsort',
'asort',
'compact',
'count',
'current',
'each',
'end',
'in_array',
'key',
'krsort',
'ksort',
'natcasesort',
'natsort',
'next',
'pos',
'prev',
'range',
'reset',
'rsort',
'shuffle',
'sizeof',
'sort',
// 字符串
'json_encode',
'json_decode',
'json_last_error',
'json_last_error_msg',
'base64_decode',
'base64_encode',
'urlencode',
'urldecode',
'parse_url',
'addslashes',
'addcslashes',
'chop',
'count_chars',
'explode',
'implode',
'join',
'levenshtein',
'ltrim',
'metaphone',
'money_format',
'number_format',
'rtrim',
'similar_text',
'soundex',
'str_getcsv',
'str_ireplace',
'str_pad',
'str_repeat',
'str_replace',
'str_rot13',
'str_shuffle',
'str_split',
'str_word_count',
'strcasecmp',
'strchr',
'strcmp',
'strcspn',
'stripos',
'stristr',
'strlen',
'strnatcasecmp',
'strnatcmp',
'strncasecmp',
'strncmp',
'strpbrk',
'strpos',
'strrchr',
'strrev',
'strripos',
'strrpos',
'strspn',
'strstr',
'strtolower',
'strtoupper',
'strtr',
'substr_compare',
'substr_count',
'substr_replace',
'substr',
'trim',
'ucfirst',
'ucwords',
'wordwrap',
// dede内置
'html2text',
'removexss',
'htmlreplace',
'getmktime',
'getpinyin',
'cn_substr',
'cn_substrr',
'mydate',
'subday',
'addday',
'getdatetimemk',
'getdatemk',
'floortime',
'getcururl',
'utf82gb',
'gb2utf8',
'u2utf8',
'utf82u',
'big52gb',
'gb2big5',
'litimgurls',
'split',
// 时间
'strtotime',
'date',
'idate',
'gmdate',
'mktime',
'gmmktime',
'checkdate',
'strftime',
'gmstrftime',
'time',
'localtime',
'getdate',
'date_create',
'date_create_immutable',
'date_create_from_format',
'date_create_immutable_from_format',
'date_parse',
'date_parse_from_format',
'date_get_last_errors',
'date_format',
'date_modify',
'date_add',
'date_sub',
'date_timezone_get',
'date_timezone_set',
'date_offset_get',
'date_diff',
'date_time_set',
'date_date_set',
'date_isodate_set',
'date_timestamp_set',
'date_timestamp_get',
'timezone_open',
'timezone_name_get',
'timezone_name_from_abbr',
'timezone_offset_get',
'timezone_transitions_get',
'timezone_location_get',
'timezone_identifiers_list',
'timezone_abbreviations_list',
'timezone_version_get',
'date_interval_create_from_date_string',
'date_interval_format',
'date_default_timezone_set',
'date_default_timezone_get',
'date_sunrise',
'date_sunset',
'date_sun_info',
// mb字符串处理
'mb_convert_case',
'mb_strtoupper',
'mb_strtolower',
'mb_language',
'mb_internal_encoding',
'mb_http_input',
'mb_http_output',
'mb_detect_order',
'mb_substitute_character',
'mb_parse_str',
'mb_output_handler',
'mb_preferred_mime_name',
'mb_strlen',
'mb_strpos',
'mb_strrpos',
'mb_stripos',
'mb_strripos',
'mb_strstr',
'mb_strrchr',
'mb_stristr',
'mb_strrichr',
'mb_substr_count',
'mb_substr',
'mb_strcut',
'mb_strwidth',
'mb_strimwidth',
'mb_convert_encoding',
'mb_detect_encoding',
'mb_list_encodings',
'mb_encoding_aliases',
'mb_convert_kana',
'mb_encode_mimeheader',
'mb_decode_mimeheader',
'mb_convert_variables',
'mb_encode_numericentity',
'mb_decode_numericentity',
'mb_send_mail',
'mb_get_info',
'mb_check_encoding',
'mb_ord',
'mb_chr',
'mb_scrub',
'mb_regex_encoding',
'mb_regex_set_options',
'mb_ereg',
'mb_eregi',
'mb_ereg_replace',
'mb_eregi_replace',
'mb_ereg_replace_callback',
'mb_split',
'mb_ereg_match',
'mb_ereg_search',
'mb_ereg_search_pos',
'mb_ereg_search_regs',
'mb_ereg_search_init',
'mb_ereg_search_getregs',
'mb_ereg_search_getpos',
'mb_ereg_search_setpos',
);
// 允许的语法
$GLOBALS['allowedTokens'] = array(
'T_AND_EQUAL',
'T_ARRAY',
'T_ARRAY_CAST',
'T_AS',
'T_BOOLEAN_AND',
'T_BOOLEAN_OR',
'T_BOOL_CAST',
'T_BREAK',
'T_CASE',
'T_CHARACTER',

'T_CONCAT_EQUAL',
'T_CONSTANT_ENCAPSED_STRING',
'T_CONTINUE',
'T_CURLY_OPEN',
'T_DEC',
'T_DECLARE',
'T_DEFAULT',
'T_DIV_EQUAL',
'T_DNUMBER',
'T_DO',
'T_DOUBLE_ARROW',
'T_DOUBLE_CAST',

'T_ELSE',
'T_ELSEIF',
'T_EMPTY',
'T_ENCAPSED_AND_WHITESPACE',
'T_ENDDECLARE',
'T_ENDFOR',
'T_ENDFOREACH',
'T_ENDIF',
'T_ENDSWITCH',
'T_FOR',
'T_FOREACH',
'T_IF',
'T_INC',
'T_INT_CAST',
'T_ISSET',
'T_IS_EQUAL',
'T_IS_GREATER_OR_EQUAL',
'T_IS_IDENTICAL',
'T_IS_NOT_EQUAL',
'T_IS_NOT_IDENTICAL',
'T_IS_SMALLER_OR_EQUAL',
'T_LNUMBER',
'T_LOGICAL_AND',
'T_LOGICAL_OR',
'T_LOGICAL_XOR',
'T_MINUS_EQUAL',

'T_MOD_EQUAL',
'T_MUL_EQUAL',
'T_NUM_STRING',
'T_OR_EQUAL',
'T_PLUS_EQUAL',
'T_RETURN',
'T_SL',
'T_SL_EQUAL',
'T_SR',
'T_SR_EQUAL',
'T_STRING',
'T_STRING_CAST',
'T_STRING_VARNAME',
'T_SWITCH',
'T_UNSET',
'T_UNSET_CAST',
'T_VARIABLE',
'T_WHILE',
'T_WHITESPACE',
'T_XOR_EQUAL',
);
// 禁止的表达式
$GLOBALS['disallowedExpressions'] = array(
'/`/',
'/\$\W/',
'/(\]|\})\s*\(/',
'/\$\w\w*\s*\(/',
);
// 执行脚本
function evalCode($code)
{
ob_start();
$code = eval('if(0){' . "\n" . $code . "\n" . '}');
ob_end_clean();
return $code !== false;
}
// 校验脚本
function checkCode($code)
{
global $allowedCalls;
global $allowedTokens;
global $disallowedExpressions;

$tokens = token_get_all('<?php ' . $code . ' ?>');
$errors = array();
$braces = 0;
foreach ($tokens as $token) {
if ($token == '{') $braces = $braces + 1;
else if ($token == '}') $braces = $braces - 1;
if ($braces < 0) {
$errors[0]['name'] = 'Syntax error.';
break;
}
}
if (empty($errors)) {
if ($braces) $errors[0]['name'] = 'Unbalanced braces.';
} else if (!evalCode($code)) {
$errors[0]['name'] = 'Syntax error.';
}
if (empty($errors)) foreach ($disallowedExpressions as $disallowedExpression) {
unset($matches);
preg_match($disallowedExpression, $code, $matches);
if ($matches) {
$errors[0]['name'] = 'Execution operator / variable function name / variable variable name detected.';
break;
}
}
if (empty($errors)) {
unset($tokens[0]);
unset($tokens[0]);
array_pop($tokens);
array_pop($tokens);
$i = 0;
foreach ($tokens as $key => $token) {
$i++;
if (is_array($token)) {
$id = token_name($token[0]);
switch ($id) {
case ('T_STRING'):
if (in_array($token[1], $allowedCalls) === false) {
$errors[$i]['name'] = 'Illegal function: ' . $token[1];
$errors[$i]['line'] = $token[2];
}
break;
default:
if (in_array($id, $allowedTokens) === false) {
$errors[$i]['name'] = 'Illegal token: ' . $token[1];
$errors[$i]['line'] = $token[2];
}
break;
}
}
}
}
if (!empty($errors)) {
return $errors;
}
}
// 错误提示
function htmlErrors($errors = null)
{
if ($errors) {
$errorsHTML = "<div style='width:98%;margin:1rem auto;color:#842029;background:#f8d7da;border-color:#842029;position:relative;padding:.75rem 1.25rem;border:1px solid transparent;border-radius:.2rem'>";
$errorsHTML .= 'PHP内嵌脚本错误:';
$errorsHTML .= '<dl>';
foreach ($errors as $error) {
if ($error['line']) {
$errorsHTML .= '<dt>Line ' . $error['line'] . '</dt>';
}
$errorsHTML .= '<dd>' . $error['name'] . '</dd>';
}
$errorsHTML .= '</dl>';
$errorsHTML .= "</div>\r\n";
echo $errorsHTML;
}
}

+ 7
- 1
src/system/taglib/php.lib.php View File

@@ -12,10 +12,16 @@ if (!defined('DEDEINC')) exit('dedebiz');
function lib_php(&$ctag, &$refObj)
{
global $dsql;
global $db;
$phpcode = trim($ctag->GetInnerText());
if ($phpcode == '')
return '';
$error = checkCode($phpcode);
if ($error) {
if (DEBUG_LEVEL) {
echo htmlErrors($error);
}
return "";
}
ob_start();
extract($GLOBALS, EXTR_SKIP);
@eval($phpcode);


+ 1
- 0
src/system/taglib/tag.lib.php View File

@@ -1,4 +1,5 @@
<?php
if (!defined('DEDEINC')) exit('dedebiz');
/**
* TAG调用标签
*


+ 28
- 34
src/theme/templets/singlepage.htm View File

@@ -6,45 +6,39 @@
<title>{dede:field.title/}-{dede:global.cfg_webname/}</title>
<meta name="keywords" content="{dede:field.keywords/}">
<meta name="description" content="{dede:field.description function='html2text(@me)'/}">
<link href="{dede:global.cfg_templets_skin/}/style/dedecms.css" rel="stylesheet" media="screen">
<script>
function checkSubmit() {
if (document.feedback.msg.value != '') document.feedback.submit();
else alert("评论内容不能为空");
}
</script>
<script src="{dede:global.cfg_cmsurl/}/static/web/js/jquery.min.js"></script>
<link rel="stylesheet" href="{dede:global.cfg_cmsurl/}/static/web/css/bootstrap.min.css">
<link rel="stylesheet" href="{dede:global.cfg_cmsurl/}/static/web/font/css/font-awesome.min.css">
<link rel="stylesheet" href="{dede:global.cfg_cmsurl/}/static/web/css/style.css">
<link rel="shortcut icon" href="{dede:global.cfg_cmsurl/}/static/web/img/favicon.ico">
</head>
<body class="articleview">
{dede:include filename="head.htm"/}
<div class="w960 center clear mt1">
<div class="pleft">
<div class="place">
当前位置: <a href="/">主页</a> &gt; {dede:field name='title'/}
</div>
<div class="viewbox">
<div class="title">
<h2>{dede:field.title/}</h2>
</div>
<div class="content">
 {dede:field.body/}
</div>
</div>
{dede:include filename='top.htm'/}
{dede:include filename='header.htm'/}
{dede:include filename='navbar.htm'/}
<div class="container">
<div class="position">
<nav aria-label="breadcrumb">
<ol class="breadcrumb mt-3">
<li class="breadcrumb-item">当前位置</li>
<li class="breadcrumb-item"><a href="{dede:global.cfg_cmsurl/}/">主页</a></li>
<li class="breadcrumb-item">{dede:field name='title'/}</li>
</ol>
</nav>
</div>
<div class="pright">
<div class="hot mt1">
<dl class="tbox">
<dt>相关页面</dt>
<dd>
<ul class="c1 ico2">
{dede:likesgpage}
<li><a href="[field:url/]">[field:title/]</a></li>
{/dede:likesgpage}
</ul>
</dd>
</dl>
</div>
<main class="container">
<div class="row">
<div class="col-12 article-main">
<h2 class="mt-0 mb-3 zixue">{dede:field.title/}</h2>
<div class="body py-2">{dede:field.body/}</div>
<nav>
<ul class="pagination justify-content-center py-3">{dede:pagebreak/}</ul>
</nav>
<div class="clearfix"></div>
</div>
</div>
</div>
</main>
{dede:include filename="footer.htm"/}
</body>
</html>

Loading…
Cancel
Save