Parece que hay un par de cosas en tu firma que no funcionarán:
-
El uso de la opción /H
en PCRE utiliza el preprocesador HTTP y dice que el contenido debe coincidir con el http_header
. Cuando el preprocesador analiza una solicitud GET, |0d 0a 0d 0a|
significa el final del encabezado; lo que significa que no puedes buscar eso dentro del encabezado.
-
Cuando se usa flow
o cualquier preprocesador HTTP, la secuencia de TCP se vuelve a ensamblar (de forma predeterminada, a menos que se especifique lo contrario). Esto significa que para hacer coincidir el contenido en el encabezado, todos los paquetes que conforman la solicitud HTTP deben observarse y la solicitud debe finalizar antes de que el preprocesador pueda analizar todas las partes que conforman la solicitud ( por ejemplo, http_method
, http_uri
, http_header
).
Honestamente, no estoy seguro de cuál sería el mejor método para escribir una firma para detectar esta actividad [genéricamente], simplemente porque se sale de los límites normales de lo que Snort está diseñado para detectar.
Sin embargo, lo que recomendaría en esta situación sería encontrar todas las herramientas disponibles públicamente para SlowLoris (comenzando con enlace : disponible para instalar a través de pip3), ejecútelos en un entorno de prueba y analice lo que realmente ocurre por cable.
Hice eso y este es el tráfico que genera:
GET /?1153 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0
Accept-language: en-US,en,q=0.5
X-a: 1350
X-a: 210
X-a: 518
X-a: 4622
X-a: 2951
X-a: 2666
X-a: 149
X-a: 1756
X-a: 4994
X-a: 2688
Esto sucede en varias conexiones hasta el número máximo de sockets especificados (150 de forma predeterminada). Cada conexión se mantendría activa con una solicitud HTTP GET incompleta al enviar un campo de encabezado X-a
adicional de vez en cuando.
La forma en que escribiría una firma para detectar esta actividad sería:
alert tcp $EXTERNAL_NET any -> $HOME_NET $HTTP_PORTS (msg:"SlowLoris.py DoS attempt"; \
flow:established,to_server,no_stream; content:"X-a:"; dsize:<15; \
detection_filter:track by_dst, count 3, seconds 30; \
classtype:denial-of-service; sid:1; rev:1; )
event_filter gen_id 1, sig_id 1, type limit, track by_src, count 1, seconds 5
Cosas importantes acerca de esta regla:
- Se agregó la opción
no_stream
a flow
. Esto le dice al preprocesador Stream5 que no se moleste en verificar cómo se relaciona el contenido en el contexto de la secuencia reensamblada. Básicamente solo mira el paquete en sí. Importante al usar la opción dsize
.
-
Añadido dsize:<15
. Las líneas que contienen los encabezados X-a
se envían en paquetes individuales. Observé un paquete típico para parecerse a:
0000 58 2d 61 3a 20 32 36 38 38 0d 0a X-a: 2688..
Con cuatro dígitos aleatorios para el valor, la longitud del contenido es de 11 bytes. Solo decidí decir <15
por si acaso.
- Se agregó
detection_filter
. Encuentro que una combinación de detection_filter
en la regla combinada con un event_filter
da un mejor control para la limitación de la tasa de alerta y el umbral. Las opciones detection_filter
que especifiqué se aseguran de solo disparar alertas si 3
o más ocurren desde la misma fuente dentro de la ventana de 30
second.
- Se agregó un
event_filter
para limitar la cantidad de alertas que se activan una vez que se alcanza el detection_filter
. Al limitar las alertas a 1
cada 5
segundos, las alertas seguirán siendo lo suficientemente locas como para informarle que algo está sucediendo sin inundarlo con alertas extrañas.
A continuación se muestra una salida de muestra de las pruebas en vivo con Snort v2.9.9.0 durante 3 minutos
SlowLoris.py
(Python3) λ slowloris -p 80 192.168.126.128
[05-12-2017 13:45:01] Attacking 192.168.126.128 with 150 sockets.
[05-12-2017 13:45:01] Creating sockets...
[05-12-2017 13:45:05] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:45:24] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:45:43] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:46:02] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:46:21] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:46:40] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:46:59] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:47:18] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:47:37] Sending keep-alive headers... Socket count: 7
[05-12-2017 13:47:56] Sending keep-alive headers... Socket count: 7
^C
Registro del servidor HTTP
user@host:~$ sudo python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?1061 HTTP/1.1" 200 -
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?524 HTTP/1.1" 200 -
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?1171 HTTP/1.1" 200 -
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?984 HTTP/1.1" 200 -
----------------------------------------
Exception happened during processing of request from ('192.168.126.1', 61831)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 654, in __init__
self.finish()
File "/usr/lib/python2.7/SocketServer.py", line 713, in finish
self.wfile.close()
File "/usr/lib/python2.7/socket.py", line 283, in close
self.flush()
File "/usr/lib/python2.7/socket.py", line 307, in flush
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?634 HTTP/1.1" 200 -
----------------------------------------
Exception happened during processing of request from ('192.168.126.1', 61832)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 654, in __init__
self.finish()
File "/usr/lib/python2.7/SocketServer.py", line 713, in finish
self.wfile.close()
File "/usr/lib/python2.7/socket.py", line 283, in close
self.flush()
File "/usr/lib/python2.7/socket.py", line 307, in flush
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?296 HTTP/1.1" 200 -
192.168.126.1 - - [05/Dec/2017 13:48:01] "GET /?640 HTTP/1.1" 200 -
----------------------------------------
Exception happened during processing of request from ('192.168.126.1', 61834)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 290, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 318, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 331, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 654, in __init__
self.finish()
File "/usr/lib/python2.7/SocketServer.py", line 713, in finish
self.wfile.close()
File "/usr/lib/python2.7/socket.py", line 283, in close
self.flush()
File "/usr/lib/python2.7/socket.py", line 307, in flush
self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------
Snort Alerts
12/05-13:45:05.348446 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61831 -> 192.168.126.128:80
12/05-13:45:24.351347 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:45:43.355735 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:46:02.358688 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:46:21.363346 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:46:40.365834 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:46:59.369221 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:47:18.372293 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:47:37.374814 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
12/05-13:47:56.378355 [**] [1:1:1] SlowLoris.py DoS attempt [**] [Priority: 0] {TCP} 192.168.126.1:61828 -> 192.168.126.128:80
Espero que esto ayude!