DEV Community

Cover image for How to DoS A server
Andrew Irorere
Andrew Irorere

Posted on

How to DoS A server

disclamer
This experiment was done in a controlled home lab on systems I own. No real-world systems were harmed. oh and educational purposes only

How It Started

Like many people learning cybersecurity, I used to think Denial of Service (DoS) attacks required massive botnets, insane bandwidth, and Hollywood-level hacking. Turns out, it doesn't. All you need is a vulnerable server and a way to exploit that vulnerability. No malware. No exploits. Just bad application design and a can-do attitude.

DoS vs DDoS

A DoS attack (Denial of Service) attack uses a single source to overwhelm a target, making it simpler to execute and ultimately block, while DDoS (Distributed Denial of Service) uses a network of compromised devices called a botnet to generate massive, distributed traffic, making it far harder to detect, mitigate, and more impactful. The key difference is distribution. DoS is one-to-one, while DDoS is many-to-one, leveraging a "distributed" network for greater power and stealth. Since I am using one machine to attack a target Dos

The Lab I Built

I set up a small, isolated lab using Oracle VirtualBox
Kali Linux → attacker machine
Ubuntu Linux → target machine

Both VMs were connected using a Host-only network, so that they could communicate with each other, so nothing was exposed to the internet for security reasons, and most importantly, everything stayed legal and safe. This was the “real” environment: two machines, communicating two roles, one goal.

The Vulnerable Server

Let's play a game. Can you spot what is wrong with the Python code below?

from http.server import BaseHTTPRequestHandler, HTTPServer
import time

a = 0

class VulnerableHTTPRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        global a
        time.sleep(3)
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()
        self.wfile.write(bytes(f"Request processed. Count: {a}", "utf-8"))
        a += 1

def run(server_class=HTTPServer, handler_class=VulnerableHTTPRequestHandler, port=8080):
    server_address = ('', port)
    httpd = server_class(server_address, handler_class)
    print(f"Starting vulnerable server on port {port}...")
    httpd.serve_forever()

if __name__ == "__main__":
    run()

Enter fullscreen mode Exit fullscreen mode

Did you see it?
time.sleep(3)

This was added to simulate “heavy processing,” and this single line would become the entire vulnerability. Why is this server vulnerable?

  • It is single-threaded
  • Each request blocks for 3 seconds
  • No rate limiting
  • No concurrency handling

This makes it an ideal target for an application-layer DoS attack.

Starting the Server

On Ubuntu, when I run the command
python3 vulnerable_server1.py

The server is running on port 8080.

which I can verify on my Kali by running:

curl http://192.168.56.103:8080

The server should respond correctly, and each request increases the counter.

The attack

On Kali, I ran this command:
ab -n 50 -c 10 http://192.168.56.103:8080/

At first glance, it didn’t look dangerous, but if you look closely, you will see that 50 total requests, 10 requests at a time, which in most development is nothing, but in the test development, almost immediately Responses slowed down, and requests started queuing. The server felt “stuck” I hadn’t flooded the network. and I hadn’t crashed the OS. I had simply asked the server to do more than it was designed to handle.

What Actually Happened

Here’s the problem, since the server is single-threaded, each requests is blocks for 3 seconds
Only one request can be processed at a time, so when 10 requests arrive simultaneously.
One request ran while the other 9 waited.d New requests piled on top. This wasn’t a bandwidth attack. It was an application-layer DoS.

Watching the Attack in Wireshark

As a Bonus and to truly understand what was happening, I opened Wireshark on my Kali Linux and captured traffic during the attack.

I applied this filter:
ip.addr == 192.168.56.103 && tcp.port == 8080

What I saw:

  • Repeated HTTP GET requests
  • Delayed responses
  • TCP retransmissions
  • Congestion builds up

In the real world, this kind of vulnerability exists in:

  • Internal tools
  • APIs
  • Microservices
  • Custom dashboards

Attackers don’t always break things. Sometimes they just wait for your code to break itself, such a vulnerability would never make it way to production, and if it did, it would be fixed or patched almost immediatialy but still this makes for a good learning exercise.

This could have been prevented by using async or multi-threaded servers, adding rate limiting and or placing a reverse proxy (like Nginx)

Conclusion

Breaking my own server was one of the most valuable lessons I’ve learned so far. It showed me how application-layer DoS really works, why design choices matter and what attack traffic actually looks like. If you’re learning cybersecurity, I highly recommend building labs like this. They’re safe, legal, and incredibly eye-opening.

Add on, I made this blog post without a plan on how to finish it I also tested out, and http spray DoS attack, but the blog was getting too long for that. If you want to check out the tool, it's on my github. I'm planning on improving it later in the coming days if I ever get the time to do that

Top comments (0)