You may have heard of DDoS attacks with huge amounts of bandwidth and compromised devices. But there is another, simpler, attack that only needs one computer and a really small amount of bandwidth. It’s called Slowloris. Even though the original script for the attack came out in 2009, that is seven years ago, it still affects a significant amount of servers.

In this article, I will try to explain what it does first, and then show you how a really simple implementation can be written. As with any security-related text you can find on the internet, it is your responsibility NOT to do anything wrong with it.

The idea for the attack is really simple. It targets servers that use thread pools (mainly Apache). That means instead of trying to fill a servers internet pipes, Slowloris makes it run out of threads. This makes the server unable to respond to legitimate users. Asynchronous/event-driven servers, such as nginx and Caddy, are not vulnerable to this.

You can switch to an asynchronous server to mitigate this attack. If you are using a web framework that has its own HTTP server, putting nginx as a reverse proxy in front of it should protect you.

In order to understand how an attack like this actually works, let’s see how a threaded server would actually respond to a client. First of all, the server accepts a connection. After this, it reads the request method, the path and all the headers. After reading all the headers, the server sends a response and (depending on the situation) closes the connection.

Slowloris actually exploits the fact that the server needs to read all headers before replying to a client. It connects to a server and sends a request just like normal users; but instead of sending all the headers and completing the request, it keeps sending headers really slowly. This keeps the connection open and it keeps the thread handling it occupied. Which means that thread can no longer serve actual users. Here’s what it looks like in a simple way.

GET / HTTP/1.1
Host: example.com
User-Agent: Chromium
[waits 10 seconds]
X-test: 145
[waits 10 seconds]
X-test: 43
[waits 10 seconds]
X-test: 7
[waits 10 seconds]
...

By keeping an array of sockets, sending random headers regularly and recreating the sockets that get closed, one can essentially occupy all of the worker threads of a server. This attack won’t be noticeable in bandwidth graphs. And if done carefully, it won’t be obvious to detect in the server logs either.

Python Implementation

To further explain the details of Slowloris, I will show you how to write a simple implementation in Python. First of all, we will need to construct an array of socket connections.

socket_list = []
for i in range(150):
    s = socket.socket()
    s.connect(("example.com", 80))
    s.send("GET / HTTP/1.1\r\n")
    s.send("Host: example.com\r\n")

    socket_list.append(s)

Next, we will set up a loop to send the headers.

while True:
    for s in socket_list:
        header = "X-test: {}\r\n".format(random.randint(1, 5000))
        s.send("X-a: {}\r\n".format(rand.randint(1, 5000)).encode("utf-8"))
    time.sleep(10)

And, that’s it. Wait. That’s it? Surely it can’t be this simple, right? Well, there are a few other things we should be doing. For example, wrapping any socket code and catching network exceptions will allow us to detect when sockets have been closed by the server. If this happens, we can just remove that socket from socket_list and append a new one. It is also a good idea to add a timeout to the initial socket creation code so it doesn’t get stuck trying create more connections than the server can handle. Remember, we aren’t trying to tie the servers hands with the amount of data we send. We need all our connections to succeed.


Thanks for reading this article about slowloris. You can find a complete implementation, written in Python, here.

If you are interested in this topic, you can find related reading material below.