Skip to content

Latest commit

 

History

History
213 lines (160 loc) · 8.61 KB

README.md

File metadata and controls

213 lines (160 loc) · 8.61 KB

DDoS to Webpage

This project's purpose is to demonstrate a DDoS attack and then try to come up with defense techniques to mitigate the effects of the attack.

About the application

TodoApi is a CRUD application in which you can add tasks and edit their content and done status. All changes are saved to a PostgreSQL database.

All services run as Docker containers. They are defined using the Docker Compose version 2 file format. Services are seperated into two machines.

First machine (server machine) runs the docker-compose-server.yml file.

  • app: Basic CRUD web API written in .NET 6.0.
  • postgres: PostgreSQL database.
  • server-1 to server-4: Apache2 (httpd) web servers serving static web pages.

Second machine (reverse proxy machine) runs the docker-compose-reverse-proxy.yml file.

  • proxy-nginx: Nginx reverse proxy server which redirects incoming requests to upstream web servers.

Requirements

Running application locally

  1. Server Machine

    1. Change URL of the API in ./TodoClient/index.js according to machine's IP.

      const todoApiUrl = "http://<machine_ip>:5122/api/TodoItems";
    2. Compile TodoApi using Dockerfile.

      sudo docker build -t "todo-api" TodoApi
    3. Copy docker compose file to root.

      cp ./docker/docker-compose-server.yml docker-compose.yml
    4. Initialize docker compose with the script.

      bash initialize_compose.sh
    5. Run the application.

      sudo docker compose run -d
  2. Reverse Proxy Machine

    1. Copy docker compose file to root.

      cp ./docker/docker-compose-reverse-proxy.yml docker-compose.yml
    2. Run the application.

      sudo docker compose run -d
  3. You can access the application:

    • Go to http://<reverse_proxy_machine_ip> to view the webpage.
    • Go to http://<server_machine_ip>:5122/api/todoitems to access the API.
    • Go to following pages to access each server.
      http://<server_machine_ip>:8080
      http://<server_machine_ip>:8081
      http://<server_machine_ip>:8082
      http://<server_machine_ip>:8083
      
    • Use psql CLI utility if you want to access the database directly
      psql -h <server_machine_ip> -p 5432 -U postgres -d postgres -W
      # Enter the password when prompted
      # Password: 0000

Reverse Proxy Configurations

  • Note: Nginx reverse proxy caches responses from upstream servers by default. This can prevent upstream server DDoS attacks because not every request reach the upstream server.

proxy-nginx.conf

  • Core functionality
  • HTTP upstream module
  • worker_processes: Defines the number of worker processes.
  • worker_connections: Sets the maximum number of simultaneous connections that can be opened by a worker process.
  • proxy_cache: Defines a shared memory zone used for caching.
  • limit_conn: Sets the shared memory zone and the maximum allowed number of connections for a given key value. When this limit is exceeded, the server will return the error in reply to a request.
  • limit_req_zone: Sets the shared memory zone and the maximum burst size of requests. If the requests rate exceeds the rate configured for a zone, their processing is delayed such that requests are processed at a defined rate. Excessive requests are delayed until their number exceeds the maximum burst size in which case the request is terminated with an error.

DDoS Instructions

  • Note: Nginx round robin load balancing is not as expected

    You cannot always see the load balancing action by looking at the server number in the webpage header. Because there are total of 3 files (index.html, index.js, styles.css) in the client and each of them cause GET request. You can only see the server number which serves the GET request of index.html file.

  • Note: If you use Nginx as a load balancer, all traffic goes through Nginx and consumes its bandwidth. This way you cannot exhaust upstream servers by opening more connections. However you can exhaust servers by sending more requests.

Slowloris Attack

Default Nginx configuration is vulnerable to Slowloris attack. Scarce resource is the maximum number of simultaneous worker connections. This number can be calculated as worker_connections * worker_processes and equals to 512 in default nginx configuration. So, it is quite easy to take down unprotected Nginx.

  • Note: You must change ulimit in Linux to open more sockets than the default soft limit of 1021.

    ulimit -n 65536
  • Start the Slowloris from attacker machine.

    python slowloris.py -p 80 -s 3000 --sleeptime 1 <victim_ip>
  • SlowLoris will flood a server with connections. In our example if SlowLoris sends 3000 connections per second, and Nginx can only handle 2048 connections per second, Nginx cannot respond to legit requests so you cannot access the webpage. Load balancing between web servers does not solve the problem because reverse proxy is down.

  • Now change proxy-nginx.conf to mitigate the DDoS attack.

    • Uncomment limit_conn two 10; to limit maximum allowed number of connections for a single IP.
    • Uncomment limit_req zone=one burst=100; to limit allowed request rate per second.
    • Uncomment client_body_timeout 1s;
    • Uncomment client_header_timeout 1s;
  • You can also increase the worker_connections to be able to handle more connections.

XerXes Attack

  • Start by only one server defined in the upstream section of proxy-nginx.conf.

    upstream server_cluster {
        server <server_machine_ip>:8080 weight=1;
        # server <server_machine_ip>:8081 weight=1;
        # server <server_machine_ip>:8082 weight=1;
        # server <server_machine_ip>:8083 weight=1;
        keepalive 32;
    }
    
  • You can change number of CONNECTIONS and THREADS to use in the attack by modifying xerxes.c source code.

    #define CONNECTIONS 32
    #define THREADS 96
  • Start the XerXes from attacker machine.

    ./xerxes <server_machine_ip> 8080
  • Benchmark performance of server using ApacheBench.

    ab -t 30 -c 10 http://<reverse_proxy_machine_ip>/
  • Now activate load balancing in the proxy-nginx.conf. Uncomment following lines:

    server <server_machine_ip>:8080 weight=1;
    server <server_machine_ip>:8081 weight=1;
    server <server_machine_ip>:8082 weight=1;
    
  • Benchmark performance of server using ApacheBench again and compare the results.

Useful Links

Contributors