发布于1小时前1小时 漏洞概述部分 WordPress 插件通过 register_rest_route 注册配置管理接口,但未设置 permission_callback,或仅在业务回调中检查普通参数,导致未登录请求可以读取、修改插件配置。若接口可写入回调地址、模板内容、文件路径或角色权限,风险可能进一步扩大为数据泄露、持久化跳转,甚至代码执行。本文给出一套适用于授权渗透测试和代码审计的验证模板。测试仅使用可回滚的标记值,不写入 PHP 代码、不创建管理员账户,也不触碰真实业务密钥。适用场景与权限边界目标为 WordPress 5.x 或 6.x,且安装了自定义插件或第三方管理类插件。插件通过 /wp-json/ 暴露 REST API。测试方已获得站点所有者授权,并明确允许进行配置写入验证。生产环境只验证无害字段;涉及 webhook、SMTP、支付或身份认证的配置,应在测试环境复现。问题定位首先确认 REST API 是否开放,并枚举命名空间。WordPress 的根接口通常会返回 routes 字段,可据此定位插件自定义路由。不要仅根据 HTTP 200 判断漏洞,部分接口会返回公开状态信息,这是正常设计。curl -sk -D headers.txt -o routes.json python3 - <<'PY' import json obj = json.load(open('routes.json', encoding='utf-8')) for route, meta in obj.get('routes', {}).items(): methods = sorted({m for ep in meta.get('endpoints', []) for m in ep.get('methods', [])}) if any(m in methods for m in ('POST', 'PUT', 'PATCH', 'DELETE')): print(','.join(methods), route) PY重点检查带有 settings、config、options、import、webhook、template 等含义的可写接口。随后分别在无 Cookie、普通订阅者账号和管理员账号下请求,对比状态码、响应体及实际配置变化。成因分析典型缺陷是注册路由时缺少 permission_callback。WordPress 新版本可能给出开发提示,但接口仍可能被注册并执行。add_action('rest_api_init', function () { register_rest_route('acme/v1', '/settings', array( 'methods' => 'POST', 'callback' => 'acme_update_settings', // 缺少 permission_callback )); }); function acme_update_settings(WP_REST_Request $request) { update_option('acme_banner', $request->get_param('banner')); return array('saved' => true); }另一类常见问题是 permission_callback 存在,但只返回 true,或检查了过宽的权限,例如 read。read 能力通常连低权限订阅者也具备,不能用于保护站点级配置。'permission_callback' => function () { return current_user_can('read'); }安全验证步骤验证时选用不会被前台解释为 HTML 或代码的普通文本字段,并使用唯一标记。先读取原值并保存,以便测试后恢复。如果接口不提供读取能力,应由站点管理员从数据库或后台记录原值。MARKER="REST-AUTHZ-CHECK-$(date +%s)" # 不携带 Cookie、Nonce 或 Authorization 头 curl -sk -i \ -X POST ' \ -H 'Content-Type: application/json' \ --data "{\"banner\":\"${MARKER}\"}" # 重新读取公开状态;若无读取接口,由管理员在后台核对 curl -sk ' | python3 -m json.tool判定漏洞至少需要满足两个条件:未认证请求成功进入写入逻辑;服务端持久化数据确实发生变化。仅看到 saved:true 但数据库未变化,不能作为最终证据。验证后应立即恢复原值,并确认对象缓存已刷新。若使用 WP-CLI,可由管理员执行:wp option get acme_banner wp option update acme_banner '原始值' wp cache flush源码与数据库排查在插件目录搜索路由注册点,逐个核对可写方法的权限回调。动态拼接路由或封装注册器时,需要继续追踪参数来源。grep -RIn --include='*.php' \ -E 'register_rest_route|permission_callback|update_option|update_site_option' \ wp-content/plugins/ # 检查标记是否被写入 options 表;表前缀需按实际环境调整 wp db query "SELECT option_name, autoload FROM wp_options WHERE option_value LIKE '%REST-AUTHZ-CHECK-%';"多站点环境还要关注 update_site_option,因为该函数修改的是网络级配置,影响范围可能超出单个站点。若回调最终调用 file_put_contents、wp_handle_upload、unzip_file 或模板渲染函数,应单独评估文件写入和代码执行链路,但不要直接在生产环境上传可执行文件。日志留痕与关联分析Web 访问日志通常是首要证据。应提取请求时间、源地址、方法、URI、状态码、User-Agent 和请求体摘要。若反向代理没有记录请求体,可结合应用审计日志和数据库变更时间判断。# Nginx 日志中筛选目标命名空间及可写请求 grep '/wp-json/acme/v1/' /var/log/nginx/access.log \ | grep -E '"(POST|PUT|PATCH|DELETE) ' # systemd 环境下检查 PHP-FPM 与 Web 服务异常 journalctl --since '2025-01-01 00:00:00' \ -u php-fpm -u nginx --no-pager | grep -Ei 'rest|wordpress|permission|fatal' 如果站点位于 CDN 或负载均衡器后,应优先使用可信代理写入的客户端地址字段,同时校验代理链配置。不能直接相信用户可控的 X-Forwarded-For。证据来源关注字段用途Nginx/Apache时间、方法、URI、状态码、来源地址确定接口调用范围WordPress 审计日志用户 ID、能力、REST 路由区分未登录与低权限调用数据库option_name、值、备份差异确认持久化修改WAF/CDN请求指纹、真实来源、命中规则补全代理前的访问记录修复方案配置写入接口应同时实施身份认证、最小能力校验、参数约束和输出净化。仅校验 Nonce 不等于授权,Nonce 主要用于降低 CSRF 风险,不能替代 current_user_can。add_action('rest_api_init', function () { register_rest_route('acme/v1', '/settings', array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => 'acme_update_settings', 'permission_callback' => function () { return current_user_can('manage_options'); }, 'args' => array( 'banner' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'validate_callback' => function ($value) { return is_string($value) && mb_strlen($value) <= 120; }, ), ), )); }); function acme_update_settings(WP_REST_Request $request) { $value = sanitize_text_field($request->get_param('banner')); update_option('acme_banner', $value, false); return rest_ensure_response(array('saved' => true)); }站点级配置通常要求 manage_options;多站点网络配置应使用 manage_network_options。每个字段建立允许列表,禁止把整个 JSON 对象直接传给 update_option。URL 使用 esc_url_raw,邮箱使用 sanitize_email,整数使用 absint,并设置长度和范围限制。模板、文件名和路径参数应禁止目录穿越,并避免将用户输入交给 include、eval 或命令执行函数。升级插件后重新检查路由权限,避免兼容性修改再次引入 permission_callback 为 true 的回归。在 WAF 上临时限制受影响路由只能由管理网段访问,但不能把 WAF 当作永久修复。修复验证修复后至少执行三组回归:未登录请求应返回 401 或 403;低权限账号应返回 403;具备 manage_options 的管理员应能正常修改合法参数。超长字符串、数组代替字符串、额外未知字段和 HTML 标签也应被拒绝或按预期净化。漏洞关闭标准不是“接口访问失败”,而是未授权主体无法修改配置,同时合法管理员功能与审计记录保持正常。总结WordPress REST API 权限问题的核心是服务端能力校验缺失或过宽。排查时应从路由枚举、权限差异、持久化结果和日志证据四个维度交叉确认。生产环境验证要坚持最小影响原则,使用可回滚标记,不测试代码执行载荷;修复则应落实到 permission_callback、字段级校验、最小权限和回归测试。 网络请求、日志与边界流量分析示意 代码审计、调用链与关键函数定位示意
创建帐户或登录后发表意见