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 192.168.0.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 192.168.0.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$\ast $, para los servicios r-$\ast $ 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.
© 2002 Antonio Villalón Huerta