original in fr Frédéric Raynal
fr to en Georges Tarbouriech
en to es en to es Walter Echarri
Frédéric Raynal está preparando su tesis sobre marcas de agua en imágenes digitales en el INRIA (Instituto Nacional de Investigación en Informática y Automatización, con sus siglas en francés)
Xinetd ("Demonio de Servicios Extendidos de Internet" con sus siglas en inglés) brinda una excelente defensa contra intrusiones y reduce los riesgos de ataques por Negación de Servicios (DoS). Al igual la conocida dupla inetd+tcpd, permite corregir los permisos de acceso a una determinada máquina si bien puede hacer mucho más que esto. En el presente artículo analizaremos muchas de sus características.
xinetd ofrece capacidades de control de acceso similares a las proporcionadas por tcp_wrapper. Sin embargo, sus posibilidades se extienden mucho más allá:
La primera parte de este artículo explica cómo funciona xinetd. Nos centraremos en la configuración general de un servicio, en algunas opciones específicas e ilustraremos todo esto con ayuda de ejemplos. La segunda parte muestra el funcionamiento de xinetd, los archivos logs que genera y finaliza con un pequeño truco muy útil.
Algunas señales influyen en el comportamiento de xinetd:
Dos utilidades que acompañan a xinetd (itox y
xconv.pl) permiten convertir
el archivo /etc/inetd.conf
en un archivo de configuración para xinetd. Obviamente, esto no es suficiente ya que
se ignoran las reglas especificadas en la configuración del wrapper. El programa itox
no se sigue desarrollando a pesar de que se sigue manteniendo.
xconv.pl constituye una mejor solución, incluso
a pesar de que sus resultados necesitan modificarse, pues xinetd ofrece más posibilidades que
inetd:
>>/usr/local/sbin/xconv.pl < /etc/inetd.conf > /etc/xinetd.confEl archivo de configuración comienza con una sección por defecto cuyos atributos utilizarán todos los servicios administrados por xinetd. A continuación, se encuentran tanta secciones como servicios existan. En cada una de ellas se pueden redefinir las opciones específicas que vienen por defecto.
Los valores por defecto de cada sección se escriben de la siguiente manera:
defaultsCada uno de los atributos definidos en esta sección conserva el (los) valor(es) proporcionados por los servicios descriptos a continuación. Así, el atributo only_from permite estipular una lista de direcciones autorizadas para conectarse a los servidores:
{
atributo operador valor(es)
...
}
only_from = 192.168.1.0/24 192.168.5.0/24 192.168.10.17A continuación, todos los servicios declarados permiten el acceso a las máquinas cuyas direcciones corresponden a algunas de las que figuran en la lista. Igualmente, es posible modificar para cada servicio estos valores por defecto (ver los operadores explicados más abajo). Sin embargo, este proceso implica ciertos riesgos. En efecto, es mejor, por razones de sencillez y seguridad, no definir valores por defecto para posteriormente modificarlos dentro de un servicio. En el caso de los permisos de acceso, por ejemplo, la política más simple y eficaz consiste en denegar el acceso a todo el mundo y a continuación autorizar el uso de cada servicio sólo a aquellos que realmente lo necesitan (con tcp_wrapper, esta política se traduce en un archivo hosts.deny que contiene la línea ALL:ALL@ALL y un archivo hosts.allow que contiene únicamente los servicios autorizados con las direcciones adecuadas).
Cada sección que describe un servicio en el archivo de configuración es de la forma:
service nombre_del_servicioExisten tres operadores: '=', '+=' y '-='. La mayoría de los atributos sólo soportan el operador '=' que fija un valor a un determinado atributo. El operador '+=' agrega un elemento a una lista de valores en tanto que el operador '-=' lo elimina.
{
atributo operador valor(es)
...
}
La tabla
1 describe brevemente a algunos de estos atributos. Veremos su uso en los ejemplos
que siguen. La lectura de la página man
de xinetd.conf
brinda una información más amplia.
Atributo | Valores y descripción |
flags | Aquí sólo se describen los valores más comunes . Ver la documentación
para descubrir los restantes.
|
log_type | xinetd usa por defecto syslogd y el selector
daemon.info.
|
log_on_success | Cuando el servidor arranca quedan registrados diversos datos:
|
log_on_failure | Nuevamente xinetd registra una gran cantidad de datos cuando el servidor no
puede arrancar, ya sea por falta de recursos o por las reglas de acceso:
|
nice | Cambia la prioridad del servidor al igual que lo hace el comando nice. |
no_access | Lista los clientes que no tienen acceso al servicio. |
only_from | Lista a los clientes autorizados. Si este atributo carece de un valor, se deniega el servicio. |
port | El puerto asociado al servicio. También es definido en el archivo /etc/services. Los 2 números de puerto deben coincidir. |
protocol | El protocolo especificado debe existe en el archivo /etc/protocols. Si no se proporciona un protocolo se emplea el asociado por defecto. |
server | La ruta al servidor. |
server_args | Argumentos que se deben pasar al servidor. |
socket_type | stream (TCP), dgram (UDP), raw (acceso directo a IP) o seqpacket (). |
type | xinetd puede administrar 3 tipos de servicios:
|
wait | Define el comportamiento frente a los threads (hebras). Son posibles dos
valores:
|
cps | Limita el número de conexiones entrantes. El primer argumento es precisamente este número. Cuando se supera este límite, se desactiva el servicio con un retraso (expresado en segundos) proporcionado por el segundo argumento. |
instances | Determina el máximo número de servidores del mismo tipo que pueden funcionar en forma simultánea. |
max_load | Proporciona la carga máxima del servidor (por ejemplo, 2 ó 2.5). Más allá de este límite las solicitudes que se realizan al servidor se rechazan. |
per_source | Restringe el número de conexiones al servidor que tienen un mismo origen. Es un entero o bien UNLIMITED |
Los últimos cuatro atributos mostrados en la tabla 1 permiten el control de los recursos que dependen de un servidor. Esto es eficiente para protegernos de manera eficaz de los ataques del tipo Negación de servicios (DoS) cuyo objetivo consiste en colgar una máquina usando la totalidad de sus recursos.
En esta sección se presentaron algunas características de xinetd. Las siguientes secciones muestran cómo usarlo y se dan ciertas reglas para que funcione correctamente.
Denegar por defecto el acceso a la máquina es la primera etapa de una política de seguridad viable. A continuación, bastará con permitir el acceso (en función de los servicios) a los que tienen la autorización para hacerlo. Hemos visto dos atributos que permiten controlar el acceso a una máquina basados en las direcciones IP: only_from y no_access. Elegir el segundo y escribir:
no_access = 0.0.0.0/0lo cual bloquea completamente el acceso a los servicios. No obstante, si se desea permitir el acceso a todo el mundo, por ejemplo, de echo (ping), se debe escribir en el servicio echo:
only_from = 0.0.0.0/0Aquí está el mensaje registrado con esta configuración en el archivo log:
Sep 17 15:11:12 charly xinetd[26686]: Service=echo-stream: only_from list and no_access list match equally the address 192.168.1.1De hecho, el control de acceso se hace comparando las listas de direcciones contenidas en los dos atributos. Cuando la dirección del cliente se corresponde en ambas listas se da prioridad a la lista menos general. En caso de igualdad, como ocurre en nuestro ejemplo, xinetd es incapaz de elegir y rechaza la conexión. Para evitar esta ambigüedad, será suficiente con escribir:
only_from = 192.0.0.0/8Otra solución menos problemática consiste en controlar el acceso únicamente mediante el atributo:
only_from =Al no precisar ningún valor condena todas las conexiones al fracaso :). A continuación, cada servicio permite el acceso mediante este mismo atributo.
Detalle importante, por no decir esencial: en caso de una ausencia total de reglas de acceso (es decir, ni only_from, ni no_access) para un determinado servicio ¡se permite el acceso al mismo!
Veamos a continuación un ejemplo de defaults :
defaultsEntre los servicios internos, servers, services y xadmin permiten administrar a xinetd. Volveremos sobre este asunto más adelante.
{
instances = 15
log_type = FILE /var/log/servicelog
log_on_success = HOST PID USERID DURATION EXIT
log_on_failure = HOST USERID RECORD
only_from =
per_source = 5disabled = shell login exec comsat
disabled = telnet ftp
disabled = name uucp tftp
disabled = finger systat netstat#INTERNAL
disabled = time daytime chargen servers services xadmin#RPC
disabled = rstatd rquotad rusersd sprayd walld
}
Algunos atributos necesariamente deben aparecer en función del tipo de servicio (INTERNAL,
UNLISTED o RPC) :
Atributo | Comentario |
socket-type | Todos los servicios. |
user | Únicamente para los servicios del tipo no INTERNAL |
server | Únicamente para los servicio del tipo no INTERNAL |
wait | Todos los servicios. |
protocol | Todos los servicios RPC que no se encuentran en /etc/services. |
rpc_version | Todos los servicios RPC. |
rpc_number | Todos los servicios RPC que no se encuentran en /etc/rpc. |
port | Todos los servicios no RPC que no se encuentran en /etc/services. |
Este ejemplo muestra cómo se definen los servicios:
service ntalkNotemos que estos servicios están únicamente autorizados en la red local (192.168.1.0/24). En cuanto al FTP, se preveen restricciones suplementarias: el número de instancias se limita a 4 y sólo será posible su uso en ciertos intervalos de tiempo.
{
socket_type = dgram
wait = yes
user = nobody
server = /usr/sbin/in.ntalkd
only_from = 192.168.1.0/24
}service ftp
{
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.ftpd
server_args = -l
instances = 4
access_times = 7:00-12:30 13:30-21:00
nice = 10
only_from = 192.168.1.0/24
}
Por ejemplo, una compañía desea instalar un servidor FTP para sus empleados
para que puedan consultar los documentos internos. Asimismo quiere brindar un acceso FTP
a sus clientes para que puedan consultar sus productos...bind está hecho a medida para esta companía :)
Definamos dos servicios FTP. Sin embargo, xinetd debe poder distinguirlos:
la solución radica en el atributo id
que define un servicio de manera única (cuando no está definido dentro de un servicio
su valor, por defecto, es el nombre del servicio).
service ftpEl uso de bind permitirá invocar al demonio correspondiente según el destino de los paquetes. De esta manera, en esta configuración, un cliente en una red local debe precisar la dirección local (o el nombre que le es asociado) para acceder a los datos internos. En el archivo log aparecen los siguientes registros:
{
id = ftp-public
wait = no
user = root
server = /usr/sbin/in.ftpd
server_args = -l
instances = 4
nice = 10
only_from = 0.0.0.0/0 #autoriza a todos los clientes
bind = 212.198.253.142 #dirección IP pública para este servidor
}service ftp
{
id = ftp-private
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.ftpd
server_args = -l
only_from = 192.168.1.0/24 #sólo para uso interno
bind = 192.168.1.1 #dirección local IP para este servidor (charly)
}
00/9/17@16:47:46: START: ftp-public pid=26861 from=212.198.253.142La primera parte proviene del comando ftp 212.198.253.142 mientras que la segunda fue ejecutada desde charly a sí mismo: ftp 192.168.1.1.
00/9/17@16:47:46: EXIT: ftp-public status=0 pid=26861 duration=30(sec)
00/9/17@16:48:19: START: ftp-internal pid=26864 from=192.168.1.1
00/9/17@16:48:19: EXIT: ftp-internal status=0 pid=26864 duration=15(sec)
Obviamente, hay un problema: ¿qué ocurre si una máquina no posee dos direcciones IP estáticas? Este es el caso de las conexiones ppp o cuando se usa el protocolo dhcp. Pareciera que sería más conveniente vincular los servicios con las interfaces en vez de hacerlo con las direcciones. No obstante, esto aún no está previsto por xinetd y plantea numerosos problemas (por ejemplo, el escribir un módulo C para acceder a las interfaces y direcciones depende del sistema operativo y puesto que xinetd es soportado por diversos OSes...). El uso de un script permite resolver el problema:
#!/bin/shEste script toma el archivo /etc/xinetd.base, que contiene la configuración deseada con PUBLIC_ADDRESS en lugar de la dirección variable y la transforma en /etc/xinetd.conf reemplazando la cadena de caracteres PUBLIC_ADDRESS por la dirección asociada a la interfase pasada como argumento del script. Por lo tanto, la llamada de este script depende del tipo de conexión: lo más sencillo consiste en agregar la llamada al archivo ifup-* adecuado y volver a ejecutar xinetd.PUBLIC_ADDRESS=`/sbin/ifconfig $1 | grep "inet addr" | awk '{print $2}'| awk -F: '{print $2}'`
sed s/PUBLIC_ADDRESS/"$PUBLIC_ADDRESS"/g /etc/xinetd.base > /etc/xinetd.conf
telnet serviceVeamos qué sucede ahora:
{
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/in.telnetd
only_from = 192.168.1.0/24
redirect = 192.168.1.15 23
}
>>telnet charlyEn efecto, la conexión parece establecerse con charly pero lo siguiente muestra que sabrina (una máquina alpha y por lo tanto "Digital UNIX") tomó el control. Este mecanismo puede ser útil como peligroso. Al configurarlo, el acceso se debe realizar en ambos extremos de la conexión. Por otra parte, es altamente recomendable el uso de un DMZ y un cortafuegos para este tipo de servicio ;-).
Trying 192.168.1.1...
Connected to charly.
Escape character is '^]'.
Digital UNIX (sabrina) (ttyp1)
login:
defaults {Antes de activarlos, deben tomarse ciertas precauciones:
...
disabled = servers services xadmin
...
}
service xadminEl servicio xadmin dispone de 5 comandos:
{
type = INTERNAL UNLISTED
port = 9100
protocol = tcp
socket_type = stream
wait = no
instances = 1
only_from = 192.168.1.1 #charly
}
Necesitaremos únicamente el servicio finger :
finger serviceNo se compiló xinetd con la opción --with-libwrap (ver el atributo server). La sección defaults es del mismo estilo que la proporcionada anteriormente: se deniega todo acceso a charly independientemente del origen de la conexión. No obstante el servicio finger no se encuentra desactivado, por lo tanto:
{
flags = REUSE NAMEINARGS
server = /usr/sbin/tcpd
server_args = in.fingerd
socket_type = stream
wait = no
user = nobody
only_from = 192.168.1.1 #charly
}
pappy@charly >> finger pappy@charly
[charly]
pappy@charly >>pappy@bosley >> finger pappy@charly
[charly]pappy@bosley >>
A primera, pareciera que la petición no funciona adecuadamente, ni desde charly (192.168.1.1), una máquina autorizada
ni desde bosley (192.168.1.10). Examinemos
los archivos log:
/var/log/servicelog :Según xinetd la petición proveniente de charly (las dos primeras líneas) funciona correctamente: se permite el acceso y la petición insume 5 segundos. Por otra parte, se rechaza la petición proveniente de bosley (FAIL).
00/9/18@17:15:42: START: finger pid=28857 from=192.168.1.1
00/9/18@17:15:47: EXIT: finger status=0 pid=28857 duration=5(sec)
00/9/18@17:15:55: FAIL: finger address from=192.168.1.10
/var/log/services :Como vemos ¡existe una única línea correspondiente a las dos peticiones! Efectivamente, la proveniente de bosley (la segunda) fue interceptada por xinetd con lo cual era de esperar que no figurara en el archivo log. En realidad, la línea seleccionada corresponde a la petición autorizada por xinetd proveniente desde charly hacia charly (la primera): la hora y sobre todo el PID son idénticos.
Sep 18 17:15:42 charly in.fingerd[28857]: refused connect from 192.168.1.1
Resumamos los hechos:
De acuerdo a la manera en que han sido definido las líneas server y server_args del servicio, aún son accesibles las características del wrapper (banner - hay un atributo banner para xinetd-, spawn, twist, ...). Hay que recordar que la opción de compilación --with-libwrap sólo agrega el control de los permisos de acceso (con ayuda de los archivos hosts.{allow,deny}) antes de que el proceso xinetd se ejecute. En este ejemplo hemos visto que esta configuración nos permite continuar usando las características del tcp wrapper.
Esta supersposición de características si bien puede funcionar puede conducir a comportamientos extraños. Para que xinetd pueda coexistir junto con inetd y portmap resulta conveniente administrar un servicio únicamente con solo uno de estos "superdemonios".
chroot [options] new_rootGeneralmente esto se usa para proteger los servicios tales como bind/DNS ó ftp. Para emular (reproducir) este comportamiento y aprovechar las características de xinetd hay que declarar chroot como servidor. Bastará entonces con pasar el resto de los argumentos por intermedio del atributo server_args :)
service ftpAsí cuando se envía una petición a este servicio la primera instrucción que se ejecuta es chroot. A continuación, se le pasa el primer argumento de la línea server_args, es decir, el nuevo root. Por último se arranca el servidor.
{
id = ftp
socket_type = stream
wait = no
user = root
server = /usr/sbin/chroot
server_args = /var/servers/ftp /usr/sbin/in.ftpd -l
}
Uno puede preguntarse qué demonio es conveniente elegir: xinetd o inetd. De hecho
xinetd exige un pequeño esfuerzo adicional de administración en especial porque
no viene por defecto incluido en todas las distribuciones (aunque si lo hace Red Hat 7.0).
Lo más conveniente es usar xinetd en máquinas con acceso público (como Internet) puesto
que ofrece una mejor defensa contra posibles intrusiones. Para máquinas dentro de una
red local, en cambio, inetd resultará más que suficiente. No obstante
no hay que descartar el empleo de un cortafuegos.