Sembra che ci siano un paio di cose nella firma che non funzioneranno:
-
L'utilizzo dell'opzione /H
in PCRE utilizza il preprocessore HTTP e dice che il contenuto deve essere confrontato con http_header
. Quando una richiesta GET viene analizzata dal preprocessore, |0d 0a 0d 0a|
indica la fine dell'intestazione; il che significa che non puoi cercarlo all'interno dell'intestazione.
-
Quando si utilizza flow
o qualsiasi preprocessore HTTP, il flusso TCP viene riassemblato (per impostazione predefinita, se non diversamente specificato). Ciò significa che per far corrispondere il contenuto nell'intestazione, tutti i pacchetti che costituiscono la richiesta HTTP devono essere osservati e la richiesta deve terminare prima che il preprocessore sia in grado di analizzare tutte le parti che compongono la richiesta ( es. http_method
, http_uri
, http_header
).
Onestamente, non sono sicuro che l'approccio migliore sarebbe scrivere una firma per rilevare questa attività [genericamente], semplicemente perché va oltre i limiti normali di ciò che Snort è progettato per rilevare.
Tuttavia, ciò che consiglierei in questa situazione sarebbe trovare tutti gli strumenti disponibili pubblicamente per SlowLoris (a partire da link - disponibile per l'installazione tramite pip3), eseguirli in un ambiente di test e analizzare ciò che effettivamente avviene sul filo.
L'ho fatto e questo è il traffico che 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
Questo accade su più connessioni fino al numero massimo di socket specificati (150 di default). Ogni connessione verrebbe mantenuta attiva con una richiesta GET HTTP incompleta inviando un ulteriore campo di intestazione X-a
ogni tanto.
Il modo in cui scriverei una firma per rilevare questa attività sarebbe:
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
Cose importanti su questa regola:
- Aggiunta l'opzione
no_stream
a flow
. Questo dice al preprocessore Stream5 di non preoccuparsi di controllare come il contenuto si riferisce nel contesto del flusso riassemblato. Fondamentalmente guarda solo il pacchetto stesso. Importante quando si utilizza l'opzione dsize
.
-
Aggiunto dsize:<15
. Le righe che contengono le intestazioni X-a
vengono inviate in singoli pacchetti. Ho osservato un tipico pacchetto come:
0000 58 2d 61 3a 20 32 36 38 38 0d 0a X-a: 2688..
Con quattro cifre casuali per il valore, la lunghezza del contenuto è di 11 byte. Ho appena deciso di dire <15
per ogni evenienza.
- Aggiunto
detection_filter
. Trovo che una combinazione di detection_filter
nella regola combinata con una event_filter
offre un controllo migliore per la limitazione e la soglia delle allerte. Le opzioni detection_filter
specificate assicurano di attivare gli avvisi solo se 3
o più si verificano dalla stessa origine in una finestra di 30
secondo.
- Aggiunto un
event_filter
per limitare il numero di avvisi attivati quando viene raggiunto detection_filter
. Limitando gli avvisi a 1
ogni 5
secondi, l'avviso sarà ancora abbastanza loquace da permetterti di sapere che qualcosa sta succedendo senza allagarti con allarmi estranei.
Di seguito è riportato un esempio di output dal test in tempo reale utilizzando Snort v2.9.9.0 per la durata di 3 minuti
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 server 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
----------------------------------------
Avvisi Snort
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
Spero che questo aiuti!