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, 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.
© 2002 Antonio Villalón Huerta