Next: Algunos servicios y protocolos
Up: Seguridad de la subred Previous: Seguridad
de la subred Índice
General
Subsecciones
Por sistema de red de un equipo Unix se entiende el conjunto de software que posibilita
la interconexión entre diferentes máquinas. Este software está
dividido en dos espacios: por un lado, tenemos el soporte de red dentro del
kernel del sistema operativo, encargado de implementar las tareas de más
bajo nivel necesarias para la comunicación entre sistemas, como la pila
de protocolos TCP/IP o los controladores de tarjetas de red; por
otro, ya en el espacio de usuario, tenemos el conjunto de programas y ficheros
utilizados para configurar parámetros del sistema relacionados con la red,
como la dirección IP, las tablas de rutado, o el comportamiento de una
máquina ante solicitudes de servicio desde otros equipos conectados lógicamente
a ella.
En este trabajo vamos a hablar exclusivamente de este software de usuario
(tanto utilidades como ficheros) que de una u otra forma puede afectar a la seguridad
global del equipo. Se trata de una pequeña - muy pequeña - introducción
a esta parte del sistema de red en Unix, sin entrar en ningún detalle;
para temas más concretos, como la configuración del soporte de red
en núcleo, la configuración de interfaces de red, servicios de nombres
o la configuración de las tablas de rutado, se puede consultar [Fri95], [Hun92], [NSS89] o, en el caso de máquinas Linux, [Kir95].
Este fichero se utiliza para obtener una relación entre un nombre de máquina
y una dirección IP: en cada línea de /etc/hosts
se especifica una dirección IP y los nombres de máquina
que le corresponden, de forma que un usuario no tenga que recordar direcciones
sino nombres de hosts. Habitualmente se suelen incluir las direcciones,
nombres y aliases de todos los equipos conectados a la red local, de forma que
para comunicación dentro de la red no se tenga que recurrir a DNS a la
hora de resolver un nombre de máquina. El formato de una línea de
este fichero puede ser el siguiente:
158.42.2.1 pleione pleione.cc.upv.es pleione.upv.es
Esta línea indica que será equivalente utilizar la dirección
158.42.2.1, el nombre de máquina pleione, o los
aliases pleione.cc.upv.es y pleione.upv.es cuando queramos
comunicarnos con este servidor:
luisa:~# telnet pleione
Trying 158.42.2.1...
Connected to pleione.cc.upv.es
Escape character is '^]'.
Connection closed by foreign host.
luisa:~# telnet 158.42.2.1
Trying 158.42.2.1...
Connected to pleione.cc.upv.es
Escape character is '^]'.
Connection closed by foreign host.
luisa:~#
De la misma forma que en /etc/hosts se establecía una correspondencia
entre nombres de máquina y sus direcciones IP, en este fichero
se establece una correspondencia entre nombres de máquina y direcciones
ethernet, en un formato muy similar al archivo anterior:
00:20:18:72:c7:95 pleione.cc.upv.es
En la actualidad el archivo /etc/ethers no se suele encontrar (aunque
para el sistema sigue conservando su funcionalidad, es decir, si existe se tiene
en cuenta) en casi ninguna máquina Unix, ya que las direcciones hardware
se obtienen por ARP.
Este fichero, cada vez más en desuso, permite asignar un nombre simbólico
a las redes, de una forma similar a lo que /etc/hosts hace con las máquinas.
En cada línea del fichero se especifica un nombre de red, su dirección,
y sus aliases:
luisa:~# cat /etc/networks
loopback 127.0.0.0
localnet 195.195.5.0
luisa:~#
El uso de este fichero es casi exclusivo del arranque del sistema, cuando aún
no se dispone de servidores de nombres; en la operación habitual del sistema
no se suele utilizar, ya que ha sido desplazado por DNS.
En cada línea de este fichero se especifican el nombre, número de
puerto, protocolo utilizado y aliases de todos los servicios de red existentes
(o, si no de todos los existentes, de un subconjunto lo suficientemente amplio
para que ciertos programas de red funcionen correctamente). Por ejemplo, para
especificar que el servicio de smtp utilizará el puerto 25, el
protocolo TCP y que un alias para él es mail,
existirá una línea similar a la siguiente:
smtp 25/tcp mail
El fichero /etc/services es utilizado por los servidores y por los clientes
para obtener el número de puerto en el que deben escuchar o al que deben
enviar peticiones, de forma que se pueda cambiar (aunque no es lo habitual) un
número de puerto sin afectar a las aplicaciones; de esta forma, podemos
utilizar el nombre del servicio en un programa y la función getservicebyname()
en lugar de utilizar el número del puerto:
luisa:~# telnet anita 25
Trying 195.195.5.3...
Connected to anita.
Escape character is '^]'.
220 anita ESMTP Sendmail 8.9.1b+Sun/8.9.1; Sun, 31 Oct 1999 06:43:06 GMT
quit
221 anita closing connection
Connection closed by foreign host.
luisa:~# telnet anita smtp
Trying 195.195.5.3...
Connected to anita.
Escape character is '^]'.
220 anita ESMTP Sendmail 8.9.1b+Sun/8.9.1; Sun, 31 Oct 1999 06:43:20 GMT
quit
221 anita closing connection
Connection closed by foreign host.
luisa:~#
Este fichero NO se utiliza para habilitar o deshabilitar servicios, sino
como hemos dicho, simplemente para obtener números de puerto a partir de
nombres de servicio y viceversa.
El sistema de red en Unix utiliza un número especial, denominado número
de protocolo, para identificar el protocolo de transporte específico que
la máquina recibe; esto permite al software de red decodificar
correctamente la información recibida. En el archivo /etc/protocols
se identifican todos los protocolos de transporte reconocidos junto a su número
de protocolo y sus aliases:
luisa:~# cat /etc/protocols
ip 0 IP # internet protocol, pseudo protocol number
icmp 1 ICMP # internet control message protocol
igmp 2 IGMP # internet group multicast protocol
ggp 3 GGP # gateway-gateway protocol
tcp 6 TCP # transmission control protocol
pup 12 PUP # PARC universal packet protocol
udp 17 UDP # user datagram protocol
idp 22 IDP # WhatsThis?
raw 255 RAW # RAW IP interface
luisa:~#
No es usual - ni recomendable - que el administrador modifique este fichero; es
el software de red el que lo va actualizando al ser instalado en la máquina
En este fichero se indican, una en cada línea, las máquinas confiables.
¿Qué significa confiables? Básicamente que confiamos
en su seguridad tanto como en la nuestra, por lo que para facilitar la compartición
de recursos, no se van a pedir contraseñas a los usuarios que quieran conectar
desde estas máquinas con el mismo login, utilizando las órdenes
BSD r
( rlogin,
rsh, rcp...). Por ejemplo, si en el fichero /etc/hosts.equiv del
servidor maquina1 hay una entrada para el nombre de host
maquina2, cualquier usuario11.1 de este sistema puede ejecutar una orden como
la siguiente para conectar a maquina1 <sin necesidad de ninguna
clave!:
maquina2:~$ rlogin maquina1
Last login: Sun Oct 31 08:27:54 from localhost
Sun Microsystems Inc. SunOS 5.7 Generic October 1998
maquina1:~$
Obviamente, esto supone un gran problema de seguridad, por lo que lo más
recomendable es que el fichero /etc/hosts.equiv esté vacío
o no exista. De la misma forma, los usuarios pueden crear ficheros $HOME/.rhosts
para establecer un mecanismo de confiabilidad bastante similar al de /etc/hosts.equiv;
es importante para la seguridad de nuestro sistema el controlar la existencia
y el contenido de estos archivos .rhosts. Por ejemplo, podemos aprovechar
las facilidades de planificación de tareas de Unix para, cada cierto tiempo,
chequear los directorios $HOME de los usuarios en busca de estos ficheros,
eliminándolos si los encontramos. Un shellscript que hace esto
puede ser el siguiente:
#!/bin/sh
for i in `cat /etc/passwd |awk -F: '{print $6}'`; do
cd $i
if [ -f .rhosts ]; then
echo "$i/.rhosts detectado"|mail -s "rhosts" root
rm -f $i/.rhosts
fi
done
Este programa envía un correo al root en caso de encontrar un fichero
.rhosts, y lo elimina; podemos planificarlo mediante cron
para que se ejecute, por ejemplo, cada cinco minutos (la forma de planificarlo
depende del clon de Unix en el que trabajemos, por lo que se recomienda consultar
la página del manual de cron o crond).
El mecanismo de autenticación que acabamos de ver sólo funciona
con las órdenes r* de Unix BSD; la conexión
vía ftp seguirá solicitando un nombre de usuario y una
clave para acceder a sistemas remotos. No obstante, existe una forma de automatizar
ftp para que no solicite estos datos, y es mediante el uso de un archivo
situado en el directorio $HOME de cada usuario (en la máquina desde
donde se invoca a ftp, no en la servidora) y llamado .netrc.
En este fichero se pueden especificar, en texto claro, nombres de máquina,
nombres de usuario y contraseñas de sistemas remotos, de forma que al conectar
a ellos la transferencia de estos datos se realiza automáticamente, sin
ninguna interacción con el usuario. Por ejemplo, imaginemos que el usuario
'root' del sistema luisa conecta habitualmente a rosita
por ftp, con nombre de usuario 'toni'; en su $HOME
de luisa puede crear un fichero .netrc como el siguiente:
luisa:~# cat $HOME/.netrc
machine rosita
login toni
password h/l0&54
luisa:~#
Si este archivo existe, cuando conecte al sistema remoto no se le solicitarán
ningún nombre de usuario ni contraseña:
luisa:~# ftp rosita
Connected to rosita.
220 rosita FTP server (Version wu-2.6.0(1) Thu Oct 21 12:27:00 EDT 1999) ready.
331 Password required for toni.
230 User toni logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>
La existencia de ficheros .netrc en los $HOME de los usuarios
se puede convertir en un grave problema de seguridad: si un atacante consigue
leer nuestro fichero .netrc, automáticamente obtiene nuestro
nombre de usuario y nuestra clave en un sistema remoto. Por tanto, no es de extrañar
que para que el mecanismo funcione correctamente, este fichero sólo puede
ser leído por su propietario; si no es así, no se permitirá
el acceso al sistema remoto (aunque los datos de .netrc sean correctos):
luisa:~# ftp rosita
Connected to rosita.
220 rosita FTP server (Version wu-2.6.0(1) Thu Oct 21 12:27:00 EDT 1999) ready.
Error - .netrc file not correct permissions.
Remove password or correct mode (should be 600).
ftp>
Existe una diferencia abismal entre el uso de .rhosts y el de .netrc;
en el primer caso al menos conseguimos que nuestra clave no se envíe a
través de la red, pero mediante .netrc lo único que conseguimos
es no tener que teclear la clave y el login explícitamente: se
envían de forma automática. Además de esto, si alguien consigue
privilegios de administrador en la máquina cliente, podrá leer los
posibles archivos .netrc que sus usuarios posean; por tanto, este mecanismo
sólo se ha de utilizar para conexiones a sistemas remotos como usuario
anónimo ( anonymous o ftp). Quizás nos convenga
rastrear periódicamente los directorios de conexión de nuestros
usuarios en busca de archivos .netrc, por ejemplo mediante un shellscript
muy similar al que hemos visto para buscar ficheros .rhosts.
Este fichero es el utilizado por el demonio inetd, conocido como el
superservidor de red. El demonio inetd es el encargado de ofrecer la
mayoría de servicios de nuestro equipo hacia el resto de máquinas,
y por tanto debemos cuidar mucho su correcta configuración. Posteriormente
hablaremos de cómo restringir servicios, tanto ofrecidos por este demonio
como servidos independientemente.
Cada línea (excepto las que comienzar por '#', que son tratadas
como comentarios) del archivo /etc/inetd.conf le indica a inetd
cómo se ha de comportar cuando recibe una petición en cierto puerto;
en cada una de ellas existen al menos seis campos (en algunos clones de Unix pueden
ser más, como se explica en [SH95]),
cuyo significado es el siguiente:
- Servicio
Este campo indica el nombre del servicio asociado a la línea correspondiente
de
/etc/inetd.conf; el nombre ha de existir en /etc/services para
ser considerado correcto, o en /etc/rpc si se trata de servicios
basados en el RPC ( Remote Procedure Call) de Sun Microsystems. En
este último caso se ha de acompañar el nombre del servicio con
el número de versión RPC, separando ambos con el carácter
'/'.
- Socket
Aquí se indica el tipo de socket asociado a la conexión.
Aunque dependiendo del clon de Unix utilizado existen una serie de identificadores
válidos, lo normal es que asociado al protocolo TCP
se utilicen sockets de tipo stream, mientras que si el protocolo
es UDP el tipo del socket sea dgram (datagrama).
- Protocolo
El protocolo debe ser un protocolo definido en /etc/protocols, generalmente
TCP o UDP. Si se trata de servicios RPC, de
nuevo hay que indicarlo utilizando rpc antes del nombre del protocolo,
separado de él por el carácter '/' al igual que sucedía
con el nombre; por ejemplo, en este caso podríamos tener protocolos
como rpc/tcp o rpc/udp.
- Concurrencia
El campo de concurrencia sólamente es aplicable a sockets de
tipo datagrama ( dgram); el resto de tipos han de contener una entrada
nowait en este campo. Si el servidor que ha de atender la petición
es multihilo (es decir, puede anteder varias peticiones simultáneamente),
hemos de indicarle al sistema de red que libere el socket asociado
a una conexión de forma que inetd pueda seguir aceptando
peticiones en dicho socket; en este caso utilizaremos la opción
nowait. Si por el contrario se trata de un servidor unihilo (acepta
peticiones de forma secuencial, hasta que no finaliza con una no puede escuchar
la siguiente) especificaremos wait.
Especificar correctamente el modelo de concurrencia a seguir en un determinado
servicio es importante para nuestra seguridad, especialmente para prevenir
ataques de negación de servicio ( DoS). Si especificamos
wait, inetd no podrá atender una petición hasta
que no finalice el servicio de la actual, por lo que si este servicio es muy
costoso la segunda petición no será servida en un tiempo razonable
(o incluso nunca, si inetd se queda bloqueado por cualquier motivo).
Si por el contrario especificamos nowait, el número de conexiones
simultáneas quizás llegue a ser lo suficientemente grande como
para degradar las prestaciones del sistema, lo que por supuesto no es conveniente
para nosotros. Para evitar ataques de este estilo, la mayoría de sistemas
Unix actuales permiten especificar (junto a wait o nowait,
separado de él por un punto) el número máximo de peticiones
a un servicio durante un intervalo de tiempo (generalmente un minuto), de
forma que si este número se sobrepasa inetd asume que alguien
está intentando una negación de servicio contra él, por
lo que deja de ofrecer ese servicio durante cierto tiempo (algunos clones
de Unix incluso paran inetd, es conveniente consultar la documentación
en cada caso). Como evidentemente esto también es una negación
de servicio, algo muy común entre administradores es aprovechar las
facilidades de planificación de Unix para enviar cada poco tiempo la
señal SIGHUP al demonio inetd, de forma que
este relea su fichero de configuración y vuelva a funcionar normalmente.
Por ejemplo, para conseguir esto podemos añadir a nuestro fichero
crontab una línea como la siguiente:
00,10,20,30,40,50 * * * * pkill -HUP inetd
Con esto conseguimos que inetd se reconfigure cada diez minutos
(el equivalente a pkill en ciertos Unices es killall,
pero es recomendable consultar el manual para asegurarse de lo que esta orden
provoca).
- Usuario
En este campo se ha de indicar el nombre de usuario bajo cuya identidad se
ha de ejecutar el programa que atiende cada servicio; esto es así para
poder lanzar servidores sin que posean los privilegios del root, con
lo que un posible error en su funcionamiento no tenga consecuencias excesivamente
graves. Para el grupo, se asume el grupo primario del usuario especificado,
aunque se puede indicar un grupo diferente indicándolo junto al nombre,
separado de éste por un punto.
- Programa
Por último, en cada línea de /etc/inetd.conf hemos
de indicar la ruta del programa encargado de servir cada petición que
inetd recibe en un puerto determinado, junto a los argumentos de
dicho programa. El servidor inetd es capaz de ofrecer pequeños
servicios basado en TCP por sí mismo, sin necesidad
de invocar a otros programas; ejemplos de este tipo de servicios son
time, echo o chargen. En este caso, el valor de este
campo ha de ser internal.
De esta forma, si en /etc/inetd.conf tenemos una línea como
telnet stream tcp nowait root /usr/sbin/in.telnetd
entonces inetd sabe que cuando reciba una petición al puerto
telnet ha de abrir un socket tipo stream (el habitual
para el protocolo TCP) y ejecutar fork() y exec()
del programa
/usr/sbin/in.telnetd, bajo la identidad de root.
La orden ifconfig se utiliza para configurar correctamente los interfaces
de red de nuestro sistema Unix; habitualmente con ifconfig se indican
parámetros como la dirección IP de la máquina,
la máscara de la red local o la dirección de broadcast.
Si como parámetros se recibe únicamente un nombre de dispositivo,
ifconfig nos muestra su configuración en este momento:
anita:/# ifconfig nei0
nei0: flags=863<UP,BROADCAST,NOTRAILERS,RUNNING,MULTICAST> mtu 1500
inet 195.195.5.3 netmask ffffff00 broadcast 195.195.5.255
ether 0:20:18:72:45:ad
anita:/#
Ya hemos dicho que aquí no vamos a hablar de la configuración de
estos dispositivos, sino de sus consideraciones de seguridad. Podemos utilizar
ifconfig para detectar un funcionamiento anómalo de la tarjeta
de red; este 'funcionamiento anómalo' suele ser la causa (siempre en cuanto
a seguridad se trata) de uno de los tres siguientes problemas:
- Dirección IP incorrecta.
Es posible que alguien esté realizando un ataque de tipo IP Spoofing
utilizando nuestro sistema: si utilizamos la dirección IP
de otro equipo, las peticiones que irían a él van a llegar a
nosotros11.2. Estamos suplantando su identidad,
hecho que un atacante puede aprovechar para capturar todo tipo de información
(desde claves hasta correo electrónico).
- Dirección MAC incorrecta.
Esto puede denotar un ataque similar al anterior, pero más elaborado:
estamos suplantando la identidad de otro equipo no sólo a nivel de
IP, sino a nivel de dirección MAC. Cuando
esto sucede, casi con toda seguridad se acompaña de un IP Spoof
para conseguir una suplantación que no sea tan fácil de detectar
como el IP Spoof a secas.
- Tarjeta en modo promiscuo.
Alguien ha instalado un sniffer en nuestro sistema y ha puesto la
tarjeta de red en modo promiscuo, para capturar todas las tramas que ésta
've'. Es un método muy utilizado por atacantes que han conseguido privilegio
de superusuario en la máquina (es necesario ser root para situar
a la tarjeta en este modo de operación) y se está dedicando
a analizar el tráfico de la red en busca de logins y claves
de usuarios de otros equipos.
Este comando se utiliza para configurar las tablas de rutado del núcleo
de nuestro sistema. Generalmente en todo equipo de una red local tenemos al menos
tres rutas: la de loopback, utilizando el dispositivo de bucle interno
( lo, lo0...), la de red local ( localnet), que utiliza la tarjeta
de red para comunicarse con equipos dentro del mismo segmento de red, y una
default que también utiliza la tarjeta para enviar a un router
o gateway paquetes que no son para equipos de nuestro segmento. Si no
se especifica ningún parámetro, route muestra la configuración
actual de las tablas de rutado11.3:
andercheran:~# route
Kernel routing table
Destination Gateway Genmask Flags MSS Window Use Iface
localnet * 255.255.0.0 U 1500 0 16 eth0
loopback * 255.0.0.0 U 3584 0 89 lo
default atlas.cc.upv.es * UG 1500 0 66 eth0
andercheran:~#
Si route nos muestra una configuración sospechosa (esto es, las
tablas no son las que en el sistema hemos establecido como administradores, aunque
todo funcione correctamente) esto puede denotar un ataque de simulación:
alguien ha desviado el tráfico por un equipo que se comporta de la misma
forma que se comportaría el original, pero que seguramente analiza toda
la información que pasa por él. Hemos de recalcar que esto suele
ser transparente al buen funcionamiento del equipo (no notamos ni pérdida
de paquetes, ni retardos excesivos, ni nada sospechoso), y que además el
atacante puede modificar los ficheros de arranque del sistema para, en caso de
reinicio de la máquina, volver a tener configuradas las rutas a su gusto;
estos ficheros suelen del tipo /etc/rc.d/rc.inet1 o /etc/rc?.d/S
inet.
También es posible que alguien esté utilizando algún elemento
utilizado en la conexión entre nuestro sistema y otro (un router,
una pasarela...) para amenazar la integridad de nuestro equipo; si queremos comprobar
el camino que siguen los paquetes desde que salen de la máquina hasta que
llegan al destino, podemos utilizar la orden traceroute. Sin embargo,
este tipo de ataques es mucho más difícil de detectar, y casi la
única herramienta asequible para evitarlos es la criptografía.
Esta orden se utiliza para visualizar el estado de diversas estructuras de datos
del sistema de red, desde las tablas de rutado hasta el estado de todas las conexiones
a y desde nuestra máquina, pasando por las tablas ARP, en
función de los parámetros que reciba.
En temas referentes a la seguridad, netstat se suele utilizar, aparte
de para mostrar las tablas de rutado de ciertos sistemas (con la opción
-r, como hemos visto antes), para mostrar los puertos abiertos que escuchan
peticiones de red y para visualizar conexiones a nuestro equipo (o desde él)
que puedan salirse de lo habitual. Veamos un ejemplo de información mostrada
por netstat:
anita:/# netstat -P tcp -f inet -a
TCP
Local Address Remote Address Swind Send-Q Rwind Recv-Q State
-------------------- -------------------- ----- ------ ----- ------ -------
*.* *.* 0 0 0 0 IDLE
*.sunrpc *.* 0 0 0 0 LISTEN
*.* *.* 0 0 0 0 IDLE
*.32771 *.* 0 0 0 0 LISTEN
*.ftp *.* 0 0 0 0 LISTEN
*.telnet *.* 0 0 0 0 LISTEN
*.finger *.* 0 0 0 0 LISTEN
*.dtspc *.* 0 0 0 0 LISTEN
*.lockd *.* 0 0 0 0 LISTEN
*.smtp *.* 0 0 0 0 LISTEN
*.8888 *.* 0 0 0 0 LISTEN
*.32772 *.* 0 0 0 0 LISTEN
*.32773 *.* 0 0 0 0 LISTEN
*.printer *.* 0 0 0 0 LISTEN
*.listen *.* 0 0 0 0 LISTEN
*.32774 *.* 0 0 0 0 LISTEN
*.* *.* 0 0 0 0 IDLE
*.6000 *.* 0 0 0 0 LISTEN
*.32775 *.* 0 0 0 0 LISTEN
localhost.32777 localhost.32775 32768 0 32768 0 ESTABLISHED
localhost.32775 localhost.32777 32768 0 32768 0 ESTABLISHED
localhost.32780 localhost.32779 32768 0 32768 0 ESTABLISHED
localhost.32779 localhost.32780 32768 0 32768 0 ESTABLISHED
localhost.32783 localhost.32775 32768 0 32768 0 ESTABLISHED
localhost.32775 localhost.32783 32768 0 32768 0 ESTABLISHED
localhost.32786 localhost.32785 32768 0 32768 0 ESTABLISHED
localhost.32785 localhost.32786 32768 0 32768 0 ESTABLISHED
localhost.32789 localhost.32775 32768 0 32768 0 ESTABLISHED
localhost.32775 localhost.32789 32768 0 32768 0 ESTABLISHED
localhost.32792 localhost.32791 32768 0 32768 0 ESTABLISHED
localhost.32791 localhost.32792 32768 0 32768 0 ESTABLISHED
localhost.32810 localhost.6000 32768 0 32768 0 ESTABLISHED
localhost.6000 localhost.32810 32768 0 32768 0 ESTABLISHED
anita.telnet luisa.2039 16060 0 10136 0 ESTABLISHED
anita.telnet bgates.microsoft.com.1068 15928 0 10136 0 ESTABLISHED
localhost.32879 localhost.32775 32768 0 32768 0 TIME_WAIT
*.* *.* 0 0 0 0 IDLE
anita:/#
Por un lado, en este caso vemos que hay bastantes puertos abiertos, esto es, escuchando
peticiones: todos los que presentan un estado LISTEN, como
telnet, finger o smtp (si es un servicio con nombre en
/etc/services se imprimirá este nombre, y si no simplemente el
número de puerto). Cualquiera puede conectar a este servicio (como veremos
en el siguiente punto) y, si no lo evitamos mediante TCP Wrappers, utilizarlo
para enviarle peticiones.
Aparte de estos puertos a la espera de conexiones, vemos otro gran número
de conexiones establecida entre nuestro sistema y otros (como antes hemos dicho,
desde nuestro equipo o hacia él); casi todas las establecidas (estado
ESTABLISHED) son de nuestra máquina contra ella misma, lo que a
priori no implica consecuencias de seguridad. Otra de ellas es desde un equipo
de la red local contra nuestro sistema, lo que también es bastante normal
y no debe hacernos sospechar nada11.4; sin embargo, hay una conexión que sí
puede indicar que alguien ha accedido a nuestro sistema de forma no autorizada:
si nos fijamos, alguien conecta por telnet desde la máquina
bgates.microsoft.com. Es raro que tengamos a un usuario allí, por
lo que deberíamos monitorizar esta conexión y las actividades que
esta persona realice; es muy probable que se trate de alguien que ha aprovechado
la inseguridad de ciertos sistemas para utilizarlos como plataforma de ataque
contra nuestros Unix.
El comando ping se utiliza generalmente para testear aspectos de la
red, como comprobar que un sistema está encendido y conectado; esto se
consigue enviando a dicha máquina paquetes ICMP (de tipo
ECHO_REQUEST), tramas que causarán que el
núcleo del sistema remoto responda con paquetes ICMP, pero
esta vez de tipo ECHO_RESPONSE. Al recibirlos,
se asume que la máquina está encendida:
anita:~# ping luisa
luisa is alive
anita:~#
En otras variantes de Unix (el ejemplo anterior es sobre Solaris) la orden
ping produce un resultado con más información:
luisa:~# ping -c 1 anita
PING anita (195.195.5.3): 56 data bytes
64 bytes from 195.195.5.3: icmp_seq=0 ttl=255 time=0.2 ms
--- luisa ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
luisa:~#
Aunque un simple ping resulta inofensivo en la mayoría de situaciones,
existen casos en los que se puede utilizar como un arma - efectiva - para atacar
sistemas; por ejemplo, uno de los ataques más conocidos es el Ping
Flood, consistente en saturar una línea lenta con un número
de paquetes ICMP suficientemente grande. Esta saturación
causará una degradación del servicio importante, incluso la desconexión
del sistema si se ataca una línea telefónica (un objetivo muy habitual
para los piratas). En este último caso, el de conexiones telefónicas,
otro ataque común - no directamente relacionado con ping, pero
en el que se usa esta herramienta como base - consiste en enviar una trama 'especial'
a un módem, obligándole a finalizar la llamada: los
módems conmutan a modo comando cuando reciben la orden '+++',
y muchos de ellos lo hacen también al recibir remotamente esta secuencia
de control. Así, podemos conectar a un puerto donde se ofrezca determinado
servicio (como FTP o SMTP) en un host con
un módem de estas características y colgar el módem
remoto sin levantarnos de la silla, simplemente enviando la cadena '+++'
seguida de una orden de colgado como 'ATH0':
luisa:~# telnet XXX.XXX.X.XX 21
Trying XXX.XXX.X.XX...
Connected to XXX.XXX.X.XX.
Escape character is '^]'.
220 gema FTP server (Version wu-2.4.2-academ[BETA-15](1) Fri Oct 22
00:38:20 CDT 1999) ready.
USER +++ATH0
^]
telnet> close
Connection closed.
luisa:~# telnet XXX.XXX.X.XX
Trying XXX.XXX.X.XX...
telnet: Unable to connect to remote host: Network is unreachable
luisa:~#
Bien pero, ¿dónde entra ping en este ataque? Muy sencillo:
al conectar a un servicio para enviar la cadena de caracteres, lo habitual es
que el sistema remoto registre la conexión, aunque luego su módem
cuelgue. En cambio, muy pocos sistemas registran en los logs un simple
ping, por lo que esta orden se convierte en un mecanismo que algunos
piratas utilizan para no dejar rastro de sus acciones; esto se consigue de una
forma muy sencilla: en la utilidad ping de la mayoría de Unices
existe un parámetro que permite especificar el contenido del paquete enviado
(por ejemplo, '-p' en Linux), por lo que simplemente hemos de insertar
(en hexadecimal) la cadena '+++ATH0' en la trama que enviamos al sistema
remoto:
luisa:~# ping -c 1 XXX.XXX.X.XX
PING XXX.XXX.X.XX (XXX.XXX.X.XX): 56 data bytes
64 bytes from XXX.XXX.X.XX: icmp_seq=0 ttl=255 time=0.2 ms
--- XXX.XXX.X.XX ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 6.5/6.5/6.5 ms
luisa:~# ping -p 2b2b2b415448300d XXX.XXX.X.XX
PING XXX.XXX.X.XX (XXX.XXX.X.XX): 56 data bytes
^C
--- XXX.XXX.X.XX ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
luisa:~# telnet XXX.XXX.X.XX
Trying XXX.XXX.X.XX...
telnet: Unable to connect to remote host: Network is unreachable
luisa:~#
Para evitar los problemas relacionados con los paquetes ICMP que
sistemas remotos puedan enviar a nuestra máquina puede ser conveniente
filtrar dicho protocolo mediante un cortafuegos (incluso situado en el propio
equipo); si no tenemos esta posibilidad, al menos es interesante registrar las
tramas de este tipo que llegan hasta nuestra máquina, con programas como
icmpinfo (si hacemos esto, hemos de tener cuidado con las negaciones
de servicio ocasionadas por una cantidad de logs excesiva en el disco
duro).
Ah, si es nuestro módem el que presenta el problema que acabamos
de comentar, podemos solucionarlo mediante la cadena de inicialización
's2=255'.
Esta orden se utiliza para imprimir la ruta que los paquetes siguen desde nuestro
sistema hasta otra máquina; para ello utiliza el campo TTL
( Time To Live) del protocolo IP, inicializándolo
con valores bajos y aumentándolo conforme va recibiendo tramas
ICMP de tipo TIME_EXCEEDED. La idea es sencilla:
cada vez que un paquete pasa por un router o una pasarela, esta se encarga
de decrementar el campo TTL en una unidad; en el caso de que se
alcance un valor 0, se devuelve un paquete TIME_EXCEEDED
y se descarta la trama. Así, traceroute inicializa a 1 este campo,
lo que ocasiona que el primer router encontrado ya devuelva el mensaje
de error; al recibirlo, lo inicializa a 2, y ahora es el segundo router
el que descarta el paquete y envía otro mensaje de error, y así
sucesivamente. De esta forma se va construyendo la ruta hasta un determinado
host remoto:
luisa:~# traceroute www.altavista.com
traceroute to altavista.com (204.152.190.70), 30 hops max, 40 byte packets
1 annex4.net.upv.es (158.42.240.191) 156.251 ms 144.468 ms 139.855 ms
2 zaurac-r.net.upv.es (158.42.240.250) 159.784 ms 149.734 ms 149.809 ms
3 atlas.cc.upv.es (158.42.1.10) 149.881 ms 149.717 ms 139.853 ms
4 A1-0-3.EB-Valencia1.red.rediris.es (130.206.211.185) 149.863 ms
150.088 ms 149.523 ms
5 A0-1-2.EB-Madrid00.red.rediris.es (130.206.224.5) 189.749 ms
159.698 ms 180.138 ms
6 A6-0-0-1.EB-Madrid0.red.rediris.es (130.206.224.74) 179.518 ms
159.678 ms 189.897 ms
7 194.69.226.13 (194.69.226.13) 259.752 ms 249.664 ms 259.83 ms
8 * * 195.219.101.1 (195.219.101.1) 290.772 ms
9 195.219.96.34 (195.219.96.34) 1680.33 ms 1660.36 ms 1669.83 ms
10 * 195.66.225.76 (195.66.225.76) 1660.68 ms 1650.33 ms
11 core1-linx-oc3-1.lhr.above.net (216.200.254.81) 2009.88 ms 1970.32 ms *
12 iad-lhr-stm4.iad.above.net (216.200.254.77) 2050.68 ms * *
13 sjc-iad-oc12-2.sjc.above.net (216.200.0.22) 2440.89 ms 2170.29 ms
2579.81 ms
14 pao-sjc-oc12-2.pao.above.net (207.126.96.65) 2441.19 ms 2140.32 ms *
15 mibh-above-oc3.pao.mibh.net (216.200.0.10) 2200.57 ms * *
16 * * www.altavista.com (204.152.190.70) 1810.56 ms
luisa:~#
traceroute se utiliza para realizar pruebas, medidas y administración
de una red; introduce mucha sobrecarga, lo que evidentemente puede acarrear problemas
de rendimiento, llegando incluso a negaciones de servicio por el elevado tiempo
de respuesta que el resto de aplicaciones de red pueden presentar. Además,
se trata de un programa contenido en un fichero setuidado, por lo que
es interesante resetear el bit de setuid de forma que sólo el
root pueda ejecutar la orden: hemos de pensar que un usuario normal rara
vez tiene que realizar pruebas sobre la red, por lo que el bit setuid
de traceroute no es más que un posible problema para nuestra
seguridad; aunque con ping sucede lo mismo (es un fichero setuidado),
que un usuario necesite ejecutar traceroute es menos habitual que que
necesite ejecutar ping (de cualquier forma, también podríamos
resetear el bit setuid de ping).
Servicios
Los servicios ofrecidos por una máquina al resto suelen ser uno de los
principales puntos de ataque contra esa máquina; estos ataques pueden implicar
desde negaciones de servicio (DoS, Denial of Service) más o menos
graves hasta un acceso root remoto sin necesidad de ninguna clave.
Hay dos formas básicas de ofrecer un servicio: o mediante inetd,
o bien lanzando un demonio que se asocia y escucha en cierto puerto, generalmente
en el arranque del sistema. Por norma general se recomienda ofrecer el mínimo
número de servicios; incluso si hay algún servicio que no sabemos
para qué se utiliza, lo mejor para nuestra seguridad sería dejar
de ofrecerlo.
Dejar de ofrecer cierto servicio en máquinas Unix es muy sencillo; no necesitamos
reiniciar el sistema para que los cambios tengan efecto ni nada por el
estilo: con un simple editor de textos podemos limitar los servicios ofrecidos.
En el caso de servicios ofertados a través de inetd, no tenemos
más que editar /etc/inetd.conf y comentar las líneas correspondientes
a los servicios a cerrar (los comentarios en ficheros de configuración
de Unix suelen ser lineales, utilizando el símbolo #). Después
de comentar las líneas correspondientes hemos de reiniciar el demonio
inetd enviándole la señal SIGHUP (con órdenes
como kill, pkill o killall). En el caso de demonios
independientes lanzados durante el arranque del sistema no tenemos más
que enviarles la señal SIGTERM (por norma general, aunque
en algunos casos quizás es necesaria SIGKILL), y también
editar los ficheros que lanzen estos demonios y comentar las líneas encargadas
de la inicialización, para que no se vuelvan a lanzar la próxima
vez que la máquina arranque; generalmente se tratará de archivos
situados en /etc/rc.d/ o en /etc/rc?.d/.
Veamos un ejemplo: imaginemos que en nuestro /etc/inetd.conf tenemos
la línea del servicio de telnet que hemos mostrado anteriormente.
En este caso, si alguien ejecuta un telnet a nuestro sistema, verá
algo parecido a esto:
rosita:~$ telnet anita
Trying 195.195.5.3...
Connected to anita.
Escape character is '^]'.
SunOS 5.7
login:
Si esta línea de /etc/inetd.conf la sustituimos por
#telnet stream tcp nowait root /usr/sbin/in.telnetd
y a continuación ejecutamos pkill -HUP inetd, cuando alguien
haga un telnet a nuestra máquina verá esto:
rosita:~$ telnet anita
Trying 195.195.5.3...
telnet: Unable to connect to remote host: Connection refused
rosita:~$
Demonios típicos que se lanzan desde inetd son in.telnetd
(para recibir peticiones telnet), in.ftpd (para peticiones
ftp), in.talkd (para peticiones talk), in.fingerd
(para finger remoto) o in.r
, para los servicios r-
de Unix BSD. Demonios que se suelen lanzar en el
arranque del sistema son sendmail (gestión de correo electrónico),
httpd (servicio http), lpd (demonio de impresión),
inetd (recordemos que es un demonio que también se ha de iniciar
en el arranque) o nfsd (para compartir sistemas de ficheros mediante
NFS); algunos de estos conviene servirlos desde inetd
en lugar de como demonios independientes, por motivos de seguridad que ya veremos
al hablar de TCP Wrappers.
Hasta ahora hemos hablado de dos formas de ofrecer un servicio: o bien a través
de inetd, o bien como demonio independiente lanzado al arrancar el sistema;
realmente, existe una tercera forma de ofrecer servicios, y es el mecanismo RPC
( Remote Procedure Call), original de Sun Microsystems pero que en la actualidad
está implementado también por OSF ( Open Software Foundation)
en su DCE ( Distributed Computing Environment) y por OMG ( Open Management
Group) en CORBA ( Common Object Request Broker Architecture). La idea
básica del funcionamiento de RPC es sencilla: existe un programa denominado
portmap, rpcbind, rpc.portmap... (su nombre depende
del clon de Unix utilizado) que los servidores RPC utilizan para registrarse.
Así, cuando un cliente desea utilizar esos servicios, en lugar de conectar
a un puerto determinado donde se encuentre el servidor lo hace al puerto del
portmapper, que le indicará la ubicación exacta del servidor
solicitado. Como estos mecanismos pueden llegar a ser muy complejos no vamos a
entrar en detalles de su seguridad; sólo decir que existe una versión
de portmap desarrollada por Wietse Venema que utiliza un control de
accesos similar a TCP Wrappers, lo que evidentemente va a ser muy útil
para nuestra seguridad: sólo permitiremos conexiones RPC a los sistemas
deseados, denegando el acceso al resto. Más detalles de la seguridad de
RPC pueden encontrarse en el capítulo 19 de [GS96].
Cada puerto abierto en nuestro sistema representa una puerta de entrada al mismo,
por lo que como hemos dicho, hemos de minimizar su número ofreciendo sólo
los servicios estrictamente necesarios. Por ejemplo, si ofrecemos el servicio
telnet, cualquier persona, desde cualquier parte del mundo, podrá
acceder a nuestra máquina simplemente conociendo (o adivinando) un nombre
de usuario y su clave; si ofrecemos el servicio netstat, cualquiera
podrá consultar las conexiones activas de nuestra red simplemente tecleando
telnet maquina.dominio.com netstat, desde cualquier ordenador conectado
a la red. Pero no sólo nos tenemos que limitar a cerrar servicios: hay
algunos que, como administradores de un sistema, no vamos a tener más remedio
que ofrecer; en este caso es casi obligatorio restringir su disponibilidad a un
número de máquinas determinado, como veremos al hablar de TCP
Wrappers, y por supuesto utilizar la última versión de los demonios
encargados de procesar las peticiones: un demonio no es más que un programa,
y por supuesto es muy difícil que esté completamente libre de errores.
Un error en el demonio que utilicemos para procesar una petición puede
comprometer la seguridad de todo nuestro sistema, por lo que se recomienda estar
atento a listas de seguridad (como BUGTRAQ o CERT)
en las que se difundan problemas de seguridad y sus soluciones.
Notas al pie
- ... usuario11.1
- Excepto el root.
- ... nosotros11.2
- Si el otro equipo no está activo; si lo está, ninguno funcionará
correctamente.
- ... rutado11.3
- En algunos Unix, esto se consigue con la orden netstat -r.
- ... nada11.4
- Seguramente, uno de nuestros usuarios estará trabajando desde ese
ordenador, aunque también podría tratarse de un atacante...
Next: Algunos servicios y protocolos
Up: Seguridad de la subred Previous: Seguridad
de la subred Índice
General