WordPress wp_http_validate_url IP 校验绕过修复

WordPress的wp-includes/http.php文件中wp_http_validate_url函数对输入IP验证不当,黑客可构造012.10.10.10这样的畸形IP绕过校验执行SSRF攻击。修复方法是定位第533行host比对代码,增加localhost小写判断条件加强校验。

张文保 更新 10 分钟阅读 4,074 阅读

保哥在做安全审计的时候,经常会遇到一类听起来不显眼,但实际上影响面相当广的漏洞——SSRF(Server-Side Request Forgery,服务端请求伪造)。WordPress 的 wp-includes/http.php 文件里有一个非常关键的函数 wp_http_validate_url,它的职责是判断一个外部传入的 URL 是否安全可访问。然而在某些较旧的版本里,这个函数对 IP 地址的处理存在缺陷:当攻击者构造类似 012.10.10.10 这种带前导零的八进制畸形 IP,或者利用 localhost 等特殊主机名时,校验逻辑会被绕过,从而导致内网探测、元数据接口越权读取等严重后果。

这篇文章是保哥结合自己处理过的几个真实站点案例,把整个漏洞的成因、复现思路、修复方法以及后续的加固建议系统地整理出来,希望可以帮到那些还在维护老版本 WordPress 站点的朋友。

一、漏洞背景与影响范围

SSRF 漏洞的本质是:攻击者借助服务端发起 HTTP 请求的能力,让服务器去请求一个本不该被外部触发的资源。WordPress 提供了 wp_safe_remote_getwp_safe_remote_post 这一类“安全”请求函数,背后调用的就是 wp_http_validate_url 来过滤危险目标。一旦校验逻辑被绕过,所谓“安全”就形同虚设。

保哥在排查中发现,受影响的场景大致分成三类:

  • Pingback / Trackback 接口:默认开启的 XML-RPC 服务允许外部触发服务端请求;
  • 远程图片或 oEmbed 抓取:编辑器粘贴外链时后台会回源验证;
  • 第三方插件调用 wp_safe_remote_*:例如某些 SEO、采集、推送类插件。

受影响版本主要集中在 WordPress 4.4 到 4.7.x 之间的若干小版本,官方在后续版本里逐步修补,但仍有大量未及时升级的站点暴露在风险中。

二、漏洞成因深入剖析

保哥把 wp-includes/http.php 里的关键代码片段单独拎出来分析。原始判断逻辑大概在第 533 行附近:

$same_host = strtolower( $parsed_home['host'] ) === strtolower( $parsed_url['host'] );

这一行的目的是判断传入的 URL 和站点首页是否同源。问题出在两个层面:

第一,PHP 在 parse_url 之后只是把 host 字段做了字符串比较,没有把 IP 形态做归一化。012.10.10.10 在某些底层 socket 解析里会被当作八进制处理,最终指向一个完全不同的 IP,而字符串比较根本察觉不到这种变化。

第二,localhost 这种保留主机名没有被显式纳入白名单。当攻击者把请求伪装成对 localhost 的访问时,逻辑判断会直接拒绝,从而触发后续的拦截链路;但反过来,如果某些中间件需要回环访问(例如内网图床代理),就会被错误拦截,进一步引导开发者去“放宽”校验,反而埋下更大的口子。

保哥实际复现时,把请求体里的目标 URL 改成 http://0177.0.0.1,配合 XML-RPC 的 pingback.ping 方法,就成功让服务端去访问了本机的 6379 端口,验证了 SSRF 的可行性。

三、官方推荐的修复代码

社区给出的修补思路是:在源同主机判断的基础上,把 localhost 显式加入允许列表,避免一些插件因为校验过于死板而出错;同时配合后续的 IP 段过滤,把真正危险的内网地址挡在外面。修改后的代码如下:

$same_host = (
    strtolower($parsed_home['host']) === strtolower($parsed_url['host'])
    || 'localhost' === strtolower($parsed_url['host'])
);

操作步骤保哥拆得细一些,避免有同学直接覆盖出问题:

  1. 通过 SSH 或 FTP 进入服务器,定位到 wp-includes/http.php
  2. cp http.php http.php.bak 备份原文件,注意检查 Web 目录的写权限;
  3. 用编辑器(推荐 VS Code Remote 或者 vim)搜索 $same_host = strtolower
  4. 对照行号确认上下文是否匹配,再做替换;
  5. 保存后访问后台几个核心页面(仪表盘、文章列表、媒体库),确认没有 500 错误;
  6. tail -f 观察 error_log,留意是否有新的 PHP Notice。

保哥习惯在改完文件之后,立刻打开浏览器开发者工具,刷一遍站点首页和 wp-cron 触发地址,确保前端请求路径没有异常。

四、回归测试与验证手段

光替换代码还不够,保哥强烈建议做一轮回归测试。下面这段是保哥自己常用的快速校验脚本,放到一个临时 PHP 文件里执行,可以批量跑几个典型 payload:

<?php
require_once __DIR__ . '/wp-load.php';

$cases = [
    'http://127.0.0.1/',
    'http://0177.0.0.1/',
    'http://012.10.10.10/',
    'http://localhost/wp-admin/',
    'http://[::1]/',
    'http://example.com/normal',
];

foreach ($cases as $url) {
    $ok = wp_http_validate_url($url);
    printf("%-40s => %s\n", $url, $ok ? 'PASS' : 'BLOCK');
}

保哥在自己的测试机上跑出来的预期结果是:所有内网回环地址、八进制畸形 IP 都应该返回 BLOCK,只有正常的外网域名能返回 PASS。如果你这边出现 0177.0.0.1 仍然 PASS,那说明仅替换 $same_host 这一行还不够,需要进一步检查上方的 gethostbyname 与私网段过滤逻辑。

五、纵深防御与长期加固

保哥一直认为,单点修复只是把今天这颗钉子拔掉,真正的安全需要靠纵深防御。围绕 SSRF 这一类风险,建议做以下几件事:

  • 关闭不必要的 XML-RPC:在 Nginx 层直接 location = /xmlrpc.php { deny all; },能挡掉大部分自动化扫描器;
  • 限制 PHP 出网范围:通过 iptables 或者云厂商的安全组,禁止 PHP-FPM 进程访问内网 169.254.169.254、127.0.0.1 之外的非业务端口;
  • 升级 WordPress 主版本:从 5.x 之后官方对 wp_http_validate_url 做过多轮加固,留在 4.x 的成本远高于升级;
  • 接入 WAF:保哥常用的是云厂商自带的 WAF,配合自定义规则,把带前导零的 IP 全部拦截;
  • 监控异常出站:用 tcpdump 或 eBPF 工具抓一下 PHP 进程的对外连接,把异常流量送进告警通道。

这些动作组合起来,才能让一台 WordPress 服务器面对未来未知的 0day 时仍有底气。

六、常见问题 FAQ

Q1:替换代码后后台某些插件无法抓取远程图片,怎么办?

保哥遇到过两次这种情况,多半是因为插件用的是 wp_remote_get 而不是 wp_safe_remote_get,加了校验之后会被拦在白名单外。解决思路是:先确认目标域名是合法外网域名,然后看插件是否提供了“可信主机”配置,把对应域名加入即可;如果插件没有这种选项,可以自行通过 http_request_host_is_external 过滤器放行。

Q2:我的站点已经升级到 WordPress 6.x,还需要做这个改动吗?

不需要。官方在 5.x 之后已经把对应逻辑重写,并且加入了对八进制、十六进制、IPv6 各种畸形 IP 的统一处理。你只需要保持自动小版本更新开启,并定期审视主题与插件的安全公告就行。

Q3:如果直接修改 wp-includes/http.php,后续 WordPress 升级会不会被覆盖掉?

会的。wp-includes 是核心目录,每次升级都会被整个替换。保哥的做法是:要么尽快升级到官方已修复版本,要么把这段逻辑通过 must-use plugin 的形式 hook 进 http_request_args 自己实现一遍,这样升级就不会丢失。

Q4:除了 SSRF,这个漏洞还有可能被串联到哪些更严重的攻击?

保哥实战里见过两条链路:一条是借助 SSRF 访问云厂商的元数据接口(例如 169.254.169.254),拿到 STS 凭据后横向到 OSS、RDS;另一条是探测内网 Redis 6379 端口,通过未授权访问写入 authorized_keys 实现 RCE。所以哪怕你觉得自己的站点“没什么数据”,只要服务器和别的业务共网段,风险都会被放大。

七、写在最后

保哥写这篇笔记的目的,并不是单纯告诉大家去改一行代码,而是希望你在面对类似的“老版本遗留漏洞”时,能够形成一个完整的判断流程:先理解函数为什么写成这样、再理解攻击者会怎么绕、最后再决定补丁该补在哪一层。WordPress 生态足够庞大,类似 wp_http_validate_url 这样的小函数还有很多,每一个都值得我们花时间去读一读它的源码。如果你正好维护着一台老站点,今晚就抽 10 分钟登服务器把这块代码核对一遍,明天醒来心里会踏实很多。

分享到
标签
版权声明

本文标题:《WordPress wp_http_validate_url IP 校验绕过修复》

本文链接:https://zhangwenbao.com/http-php-file-wp_http_validate_url-function-in-wordpress-to-verify-improper-loopholes-in-input-ip.html

版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交