侧边栏壁纸
博主昵称
YunZheng

独处未必孤独,喜欢就是自由

Typecho Pingback SSRF 漏洞(CVE-2026-7025)分析与一键修复包

2026年10月25日 27阅读 4评论 5点赞
创创云-专业云计算服务器提供商

✨ 漏洞简介

CVE-2026-7025 是 Typecho Pingback 功能中的一个服务端请求伪造(SSRF)漏洞,影响 Typecho 1.3.0 及以下版本。

发布文章时,Typecho 会自动请求文章中的外链,然后读取对方返回的 X-Pingback 响应头或页面里的 <link rel="pingback"> 地址,再向这个地址发起 XML-RPC 请求。问题出在这一步:这个地址完全由对方站点决定,Typecho 却没做任何校验。

攻击者只要在自己的页面返回:

X-Pingback: http://127.0.0.1:6379/

或者

X-Pingback: http://169.254.169.254/latest/meta-data/

就能让你的服务器去访问本机 Redis、内网服务,甚至云服务器的元数据接口。

漏洞信息

项目说明
🔖 漏洞编号CVE-2026-7025 / AVD-2026-7025
🎯 影响版本Typecho ≤ 1.3.0
🧨 漏洞类型SSRF(服务端请求伪造)
📍 漏洞位置var/Widget/Service.php → sendPingHandle()
🚪 利用入口远端返回的 X-Pingback 响应头 / <link rel="pingback">
⚠️ 危害探测内网、访问本机服务、读取云元数据

🔍 漏洞成因

原始代码(简化后):

$spider->setTimeout(10)->send($url);

// 直接信任远端返回的地址
if (!($xmlrpcUrl = $spider->getResponseHeader('x-pingback'))) {
    if (preg_match("/<link[^>]*rel=[\"']pingback[\"'][^>]*href=[\"']([^\"']+)[\"'][^>]*>/i",
        $spider->getResponseBody(), $out)) {
        $xmlrpcUrl = $out[1];
    }
}

if (!empty($xmlrpcUrl)) {
    // 没有任何校验,直接对该地址发起请求
    $xmlrpc = new \IXR\Client($xmlrpcUrl);
    $xmlrpc->pingback->ping($permalink, $url);
}

整个流程有三处外发请求:抓取文中外链、请求 Pingback 地址、发送 Trackback,三处都没有校验目标地址。

有意思的是:接收 Pingback 的一侧(XmlRpc::pingbackPing)其实调用了 Common::checkSafeHost() 校验来源地址,只是发送一侧漏掉了。

🛠️ 修复方案

修复要点

修复点说明
🛡️ 协议白名单只允许 http / https,拦截 gopher://、file://、dict:// 等
🛡️ 内网拦截复用官方 Common::checkSafeHost(),拦截回环、内网和保留地址
🛡️ 账号信息拦截拒绝 http://user@host 这类可能造成解析歧义的地址
🎯 三处全覆盖抓取外链前、请求 Pingback 地址前、发送 Trackback 前
🧯 异常兜底单个外链请求失败时跳过这一条,不再中断整个循环
📦 改动极小只修改 var/Widget/Service.php 一个文件

新增校验方法

/**
 * 校验外发请求地址:仅允许 http/https,且主机不能解析到内网/保留地址(防 SSRF)
 */
private function isSafeRemoteUrl(string $url): bool
{
    $params = parse_url($url);

    if (false === $params || empty($params['host']) || empty($params['scheme'])) {
        return false;
    }

    if (!in_array(strtolower($params['scheme']), ['http', 'https'], true)) {
        return false;
    }

    /** 禁止携带账号信息,避免 http://a@b 之类的解析歧义 */
    if (isset($params['user']) || isset($params['pass'])) {
        return false;
    }

    $host = trim($params['host'], '[]');

    return Common::checkSafeHost($host);
}

调用位置

// 1. 抓取文章外链前
if (!$this->isSafeRemoteUrl($url)) {
    continue;
}

// 2. 使用远端返回的 X-Pingback / link 地址前(漏洞核心)
if (!empty($xmlrpcUrl) && $this->isSafeRemoteUrl($xmlrpcUrl)) {
    $xmlrpc = new \IXR\Client($xmlrpcUrl);
    $xmlrpc->pingback->ping($permalink, $url);
}

// 3. 发送 Trackback 前
if (!$this->isSafeRemoteUrl($url)) {
    continue;
}
为什么不用担心 302 跳转绕过?
Typecho 自带的 HTTP 客户端没有开启 CURLOPT_FOLLOWLOCATION,不会跟随重定向,所以没法先用公网地址通过校验、再 302 跳到内网。

📦 安装方法

第一步:备份原文件

cp var/Widget/Service.php var/Widget/Service.php.bak

第二步:下载修复包

📥 下载地址:https://kiwl.lanzout.com/ilLnf4dcl7tc

压缩包结构:

typecho-ssrf-fix.zip
└── var/
    └── Widget/
        └── Service.php

第三步:解压到网站根目录

上传到 Typecho 根目录(config.inc.php 所在目录),直接解压覆盖即可:

unzip -o typecho-ssrf-fix.zip

第四步:检查语法

php -l var/Widget/Service.php
# No syntax errors detected in var/Widget/Service.php
⚠️ 如果你自己改过 Service.php,请不要直接覆盖,按上面的「调用位置」手动合并。

🧪 验证方法

在网站根目录执行下面的命令。它只在内存里加载 Typecho 的类并调用校验方法,不写入文件,也不对外发请求:

php <<'EOF'
<?php
define('__TYPECHO_ROOT_DIR__', getcwd());
spl_autoload_register(function ($c) {
    $f = 'var/' . str_replace(['\\', '_'], '/', $c) . '.php';
    if (is_file($f)) require_once $f;
});
require_once 'var/Typecho/Common.php';

$r = new ReflectionClass('Widget\Service');
$o = $r->newInstanceWithoutConstructor();
$m = $r->getMethod('isSafeRemoteUrl');
$m->setAccessible(true);

// 1 = 应放行,0 = 应拦截
$cases = [
    'http://127.0.0.1:6379/' => 0,
    'http://localhost/' => 0,
    'http://169.254.169.254/latest/meta-data/' => 0,
    'http://10.0.0.1/' => 0,
    'http://192.168.1.1/' => 0,
    'http://172.16.0.1/' => 0,
    'http://0.0.0.0/' => 0,
    'http://2130706433/' => 0,
    'http://[::1]/' => 0,
    'http://user@127.0.0.1/' => 0,
    'http://a@www.baidu.com/' => 0,
    'gopher://127.0.0.1:6379/_x' => 0,
    'file:///etc/passwd' => 0,
    'dict://127.0.0.1:11211/' => 0,
    'https://www.baidu.com/' => 1,
    'https://typecho.org/' => 1,
];

$ok = 0;
foreach ($cases as $url => $want) {
    $got = $m->invoke($o, $url);
    $pass = ($got === (bool)$want);
    $ok += $pass;
    printf("%-45s want=%s got=%s %s\n", $url,
        $want ? 'allow' : 'block', $got ? 'allow' : 'block', $pass ? 'PASS' : 'FAIL');
}
echo "RESULT: $ok/" . count($cases) . "\n";
EOF

实测结果(Typecho 1.3.0 + PHP 8.2)

类型测试地址结果
本机 / 回环127.0.0.1、localhost、0.0.0.0、[::1]、十进制 IP 2130706433✅ 拦截
云元数据169.254.169.254✅ 拦截
内网段10.x、192.168.x、172.16.x✅ 拦截
带账号信息的 URLuser@127.0.0.1、a@www.baidu.com✅ 拦截
危险协议gopher://、file://、dict://✅ 拦截
正常外链https://www.baidu.com/、https://typecho.org/✅ 放行
RESULT: 16/16

16 项测试全部通过!

💡 补充建议

  • 用不到 Pingback 的话:直接在后台「设置 → 评论」里关闭 Pingback / Trackback,并关闭 XML-RPC,从根上减少暴露面。
  • 剩余风险:现在是先解析一次 DNS 做校验,curl 发请求时会再解析一次,理论上还存在 DNS Rebinding 绕过的可能。要彻底解决,需要用 CURLOPT_RESOLVE 把校验时拿到的 IP 固定下来,改动会更大,这个修复包暂时没有做。
  • 官方升级:Typecho 官方发布修复版本后,建议升级到官方版本。这个文件到时会被覆盖,属于正常现象。

🔗 相关链接

链接地址
漏洞详情https://avd.aliyun.com/detail?id=AVD-2026-7025
修复包下载https://kiwl.lanzout.com/ilLnf4dcl7tc
Typecho 官网https://typecho.org/

📝 更新日志

v1.0.0 (2026-10-25)

  • ✅ 新增 isSafeRemoteUrl() 外发地址校验方法
  • ✅ 抓取外链、请求 Pingback 地址、发送 Trackback 三处全部加上校验
  • ✅ 拦截内网、回环、保留地址以及非 http/https 协议
  • ✅ 拦截带账号信息的 URL
  • ✅ 单个外链请求异常时跳过,不再中断整个循环
  • ✅ 在 Typecho 1.3.0 + PHP 8.2 环境下通过 16 项测试

如果这篇文章对你有帮助,欢迎分享给身边使用 Typecho 的朋友! Made with ❤️ by YouChuang Open Source Community · Powered by PHP

5赞
打赏

—— 评论区 ——

昵称
邮箱
网址
取消
  1. 头像
    回复

    我用的typecho的二开版本,昨天已经有博主注意到了这个漏洞,经询问作者,二开版本没有这个漏洞。

    1. 头像
      云峥 博主
      Windows 10   Firefox
      回复
      @似水流年

      作者确认过没问题就安心用吧。不过建议:用不到 Pingback 的话在后台顺手关掉,再留意官方修复版,出正式版后升级更保险。(官方不知道何时修。。。。。)

  2. 头像
    回复

    确认自己用的版本不受影响就安心了,不过修复包还是先收藏备用。

    1. 头像
      云峥 博主
      Windows 10   Firefox
      回复
      @海风心情

      等官方修复版出来还是建议升级,更彻底。表情

目录 0
本文暂无目录
人生倒计时