Simple switch Ryu + snort + mininet
Se va a configurar un escenario como el siguiente en mininet:
10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4
+---------+ +--------+ +--------+ +--------+
| h1 | | h2 | | h3 | | h4 |
+---------+ +--------+ +--------+ +--------+
| | | |
| | | |
|1 | 2 | 3 |4
+----------------------------------------------------------+
| s1 |
+----------------------------------------------------------+
La topología de mininet está definida en el siguiente fichero:
#!/usr/bin/python
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
class SingleSwitchTopo(Topo):
"Single switch connected to n hosts."
def build(self, n=4):
switch = self.addSwitch('s1')
# Python's range(N) generates 0..N-1
for h in range(n):
host = self.addHost('h%s' % (h + 1))
self.addLink(host, switch)
# Allows the file to be imported using `mn --custom <filename> --topo dcbasic`
topos = {
'dcconfig': SingleSwitchTopo
}
Para arrancar esta topología:
sudo mn --custom singleSwitchTopo.py --topo dcconfig --mac --controller remote
Vamos a usar el controlador simple_switch_snort.py
para describir el comportamiento de s1
. Este controlador además de definir el comportamiento del switch, se comunica con snort
a través de unun socket unix (SOCKFILE = "/tmp/snort_alert"
, definido en la librería de Ryu: SnortLib) para recibir las alertas que haya definidas en snort
. Cuando recibe una alerta imprime un mensaje. El controlador tiene definido el puerto 3 como puerto mirror, es decir, hace una copia de todos los paquetes en el puerto 3. Esto permite que snort
pueda analizar todos los paquetes del switch s1. En el controlador simple_switch_snort.py
encontramos el siguiente código:
def __init__(self, *args, **kwargs):
super(SimpleSwitchSnort, self).__init__(*args, **kwargs)
# crea el objeto para el manejo de las alertas de snort
self.snort = kwargs['snortlib']
# define el puerto mirror donde está arrancado snort
self.snort_port = 3
self.mac_to_port = {}
# se comunica con snort a través de un socket unix
socket_config = {'unixsock': True}
self.snort.set_config(socket_config)
self.snort.start_socket_server()
Lanzamos el controlador:
sudo ryu-manager ryu/ryu/app/simple_switch_snort.py
El puerto 3, donde está conectado h3
funciona como mirror, es decir, se pueden capturar todos los paquetes que reciba s1
. Para probarlo, lanzamos un ping en h1 hacia h4 (10.0.0.4) y se puede observar como h2
sólo recibe la consulta de ARP y h3
recibe todos los paquetes, siendo que no van dirigidos a h3
El controlador simple_switch_snort.py
tiene programado que al instalar un flujo en el switch, además de realizar la copia al puerto de salida correspondiente, copia ese paquete en el puerto en el que está haciendo mirror:
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
...
actions = [parser.OFPActionOutput(out_port),
parser.OFPActionOutput(self.snort_port)]
# instalar el flujo
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
# enviar packetOut
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
Alerta por tráfico ICMP
Vamos a añadir una regla a snort para que siempre que detecte tráfico ICMP (en particular ocurrirá cuando ejecutemos ping, ICMP Echo Request/Reply) se envíe una alerta.
- En el fichero
/etc/snort/snort.conf
añadimos la siguiente línea al final del fichero. Esto permite definir nuestro propio fichero de reglas que se cargarán al iniciar snort: include $RULE_PATH/myRules.rules
- Crearemos el fichero
/etc/snort/rules/myRules.rules
con las alertas que queramos definir:
alert icmp any any -> any any (msg:"ICMP traffic...";sid:1000004)
- Crearemos el fichero
Ya tenemos snort
preparado para que cuando detecte tráfico ICMP, se muestre esta alerta. Arrancamos snort
: para que procese los paquetes donde el switch está haciendo mirror (desde la máquina real, esta interfaz es s1-eth3
), use un socket unix y la carpeta para almacenar los logs es /tmp
:
sudo snort -i s1-eth3 -A unsock -l /tmp -c /etc/snort/snort.conf
Provocamos tráfico para que se active la alerta. Por ejemplo, en h1
volvemos a ejecutar ping a 10.0.0.4 (h4
), al detectar tráfico ICMP Echo Request y Echo Reply, snort generará una alerta que el controlador recibirá a través del socket unix e imprimirá los siguientes mensajes:
Alerta por el paquete ICMP Echo Request mostrada en el controlador:
alertmsg: ICMP traffic... icmp(code=0,csum=24244,data=echo(data=array('B', [60, 216, 138, 89, 0, 0, 0, 0, 189, 63, 4, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]),id=20998,seq=1),type=8) ipv4(csum=33563,dst='10.0.0.4',flags=2,header_length=5,identification=41865,offset=0,option=None,proto=1,src='10.0.0.1',tos=0,total_length=84,ttl=64,version=4) ethernet(dst='00:00:00:00:00:04',ethertype=2048,src='00:00:00:00:00:01')
Alerta por el paquete ICMP Echo Reply mostrada en el controlador:
alertmsg: ICMP traffic... icmp(code=0,csum=26292,data=echo(data=array('B', [60, 216, 138, 89, 0, 0, 0, 0, 189, 63, 4, 0, 0, 0, 0, 0, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55]),id=20998,seq=1),type=0) ipv4(csum=17598,dst='10.0.0.1',flags=0,header_length=5,identification=8679,offset=0,option=None,proto=1,src='10.0.0.4',tos=0,total_length=84,ttl=64,version=4) ethernet(dst='00:00:00:00:00:01',ethertype=2048,src='00:00:00:00:00:04')
Alerta por ataque XMAS
Snort por defecto tiene configurada la siguiente regla en el fichero scan.rules
:
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"SCAN nmap XMAS"; flow:stateless; flags:FPU,12; reference:arachnids,30; classtype:attempted-recon; sid:1228; rev:7;)
Vamos a provocar que se active esta alerta cuando hacemos un escaneo con nmap desde la máquina h1 hacia a h4. Para ello, primero vamos a activar el servicio sshd
en h4 para ver el comportamiento diferente de un escaneo con un puerto abierto o un puerto cerrado. En h4 lanzamos:
/usr/sbin/sshd
Comprobamos que está lanzado escuchando en el puerto 22:
netstat -ant
Conexiones activas de Internet (servidores y establecidos)
Proto Recib Enviad Dirección local Dirección remota Estado
tcp 0 0 0.0.0.0:22 0.0.0.0:* ESCUCHAR
tcp6 0 0 :::22 :::* ESCUCHAR
Desde h1 ejecutamos el sondeo de los puertos 21 y 22 con ataque XMAS (flags URG, PSH y FIN):
nmap -Pn -sX -p 21-22 -v 10.0.0.4
Con este comando, h1 mandará a los puertos 21 y 22 un segmento TCP con los flags activados: URG, PSH y FIN. El envío de este mensaje SYN al puerto 21, donde no hay servidor, provoca una respuesta de TCP con RST activado. El envío del mensaje SYN al puerto 22 no obtiene respuesta (en este caso hay un servidor de ssh que no responde a este mensaje) y nmap repite de nuevo la misma sonda. Observamos las alertas en el controlador, la primera se corresponde con el mensaje al puerto 21 y las dos siguientes con los dos mensajes al puerto 22:
alertmsg: SCAN nmap XMAS
ipv4(csum=50625,dst='10.0.0.4',flags=0,header_length=5,identification=46858,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=40,ttl=42,version=4)
ethernet(dst='00:00:00:00:00:04',ethertype=2048,src='00:00:00:00:00:01')
alertmsg: SCAN nmap XMAS
ipv4(csum=6852,dst='10.0.0.4',flags=0,header_length=5,identification=24072,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=40,ttl=46,version=4)
ethernet(dst='00:00:00:00:00:04',ethertype=2048,src='00:00:00:00:00:01')
alertmsg: SCAN nmap XMAS
ipv4(csum=40828,dst='10.0.0.4',flags=0,header_length=5,identification=54607,offset=0,option=None,proto=6,src='10.0.0.1',tos=0,total_length=40,ttl=50,version=4)
ethernet(dst='00:00:00:00:00:04',ethertype=2048,src='00:00:00:00:00:01')