Skip to content

Instantly share code, notes, and snippets.

@avishaifrad
Created April 29, 2025 19:36
Show Gist options
  • Save avishaifrad/f4e23a97156b1905a7ec8b962a9f2bc8 to your computer and use it in GitHub Desktop.
Save avishaifrad/f4e23a97156b1905a7ec8b962a9f2bc8 to your computer and use it in GitHub Desktop.
CVE-2025-31324-Scanner
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CVE-2025-31324 Vulnerability Scanner
This tool checks whether a SAP system is vulnerable to CVE-2025-31324.
CVE-2025-31324 is a critical vulnerability (CVSS 10) affecting SAP NetWeaver AS
with Visual Composer technology.
DISCLAIMER: This tool is provided "as is", without warranties or guarantees
of any kind, express or implied.
Version: 1.0.0
"""
import argparse
import requests
import sys
import urllib3
import urllib.parse
from datetime import datetime
# Suppress insecure request warnings - for testing potentially vulnerable systems
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Tool version
__version__ = "1.0.0"
# Constants for vulnerability status
VULNERABLE = "vulnerable"
NOT_VULNERABLE = "not_vulnerable"
UNKNOWN = "unknown"
def print_banner():
"""Print scanner banner with version information."""
banner = f"""
============================================================
CVE-2025-31324 Vulnerability Scanner v{__version__}
============================================================
This tool will check if your SAP system is vulnerable to
CVE-2025-31324 (SAP Security Note 3594142) - CVSS Score 10.0
Scan started at: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
"""
print(banner)
def parse_url(url, port=None):
"""
Parse the provided URL and return components needed for vulnerability check.
Args:
url (str): The URL to the SAP system (can be a full URL or just a hostname)
port (int, optional): Port number to override the one in URL if provided
Returns:
tuple: (base_url, full_url) - base URL and complete URL for vulnerability check
"""
# Add scheme if not provided
if not url.startswith('http://') and not url.startswith('https://'):
url = 'https://' + url
# Parse the URL to get its components
parsed_url = urllib.parse.urlparse(url)
# Set default scheme to https if not provided
scheme = parsed_url.scheme or 'https'
# Extract hostname
hostname = parsed_url.netloc
# If hostname contains port, extract it
if ':' in hostname:
hostname = hostname.split(':')[0]
# Determine the port to use (priority: provided port param, URL port, default based on scheme)
if port is not None:
# Use the port parameter provided by the user
port_to_use = port
elif parsed_url.port is not None:
# Use the port from the URL
port_to_use = parsed_url.port
else:
# Default port based on scheme
port_to_use = 443 if scheme == 'https' else 80
# Create the base URL with scheme, hostname, and port
base_url = f"{scheme}://{hostname}:{port_to_use}"
# Create the full URL for the vulnerability check
full_url = f"{base_url}/developmentserver/metadatauploader"
return base_url, full_url
def check_vulnerability(url, port=None):
"""
Check if the target SAP system is vulnerable to CVE-2025-31324.
Args:
url (str): The URL to the SAP system
port (int, optional): Port number to override the one in URL if provided
Returns:
str: Status indicating if the system is vulnerable ("vulnerable", "not_vulnerable", or "unknown")
"""
# Parse the URL to get base_url and the full URL for vulnerability check
base_url, full_url = parse_url(url, port)
print(f"[*] Initiating vulnerability check against: {full_url}")
try:
# Use HEAD request to check the vulnerability with a timeout
response = requests.head(full_url, timeout=10, verify=False)
status_code = response.status_code
# Vulnerability check logic:
# If status code is 200 and no Set-Cookie header is present, system appears vulnerable
if status_code == 200 and 'Set-Cookie' not in response.headers:
print(f"[!] SAP System at {base_url} IS VULNERABLE to CVE-2025-31324.")
return VULNERABLE
elif status_code == 404:
print(f"[-] SAP System at {base_url} DOES NOT appear to have the Visual Composer component installed or available.")
return NOT_VULNERABLE
else:
print(f"[-] The SAP system at {base_url} DOES NOT appear to be vulnerable to CVE-2025-31324.")
return NOT_VULNERABLE
except requests.exceptions.RequestException as e:
print(f"[!] Connection error while testing vulnerability: {e}")
return UNKNOWN
def print_summary(vulnerability_status):
"""
Print a summary of the scan results.
Args:
vulnerability_status (str): Status indicating if the system is vulnerable
("vulnerable", "not_vulnerable", or "unknown")
"""
print("\n" + "="*60)
print(" SCAN SUMMARY ")
print("="*60)
if vulnerability_status == VULNERABLE:
print("[!] System appears VULNERABLE to CVE-2025-31324")
print("[+] ACTION: Apply SAP Security Note 3594142 immediately")
elif vulnerability_status == NOT_VULNERABLE:
print("[-] System does not appear to be vulnerable to CVE-2025-31324")
else: # UNKNOWN
print("[?] Could not determine if the system is vulnerable to CVE-2025-31324")
print("[*] ACTION: Check network connectivity and try again")
print("\nScan completed at: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print("="*60)
def main():
"""Main function to parse arguments and run the vulnerability check."""
parser = argparse.ArgumentParser(
description=(
"CVE-2025-31324 Vulnerability Scanner\n\n"
"This tool checks if your SAP system is vulnerable to CVE-2025-31324 (CVSS 10.0 - Critical)\n\n"
"Example usage: python CVE-2025-31324-Scanner.py https://sap.example.com"
),
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument(
"url",
help="URL to the SAP system (e.g., https://sap.example.com or just sap.example.com)"
)
parser.add_argument(
"--port",
type=int,
help="Port number of the SAP system (overrides port in URL if specified, default: 443 for https, 80 for http)",
required=False
)
# Parse the command line arguments
args = parser.parse_args()
# Print the banner
print_banner()
# Run the vulnerability check
vulnerability_status = check_vulnerability(args.url, args.port)
# Print summary
print_summary(vulnerability_status)
# Return appropriate exit code:
# 0 = not vulnerable
# 1 = vulnerable
# 2 = unknown status
if vulnerability_status == VULNERABLE:
sys.exit(1)
elif vulnerability_status == UNKNOWN:
sys.exit(2)
else: # NOT_VULNERABLE
sys.exit(0)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment