next up previous contents
Next: Seguridad de la subred Up: Seguridad del sistema Previous: Autenticación de usuarios   Índice General

Subsecciones


Seguridad del núcleo

Introducción

El núcleo o kernel de un sistema Unix es la parte más importante del mismo, hasta tal punto que en términos puristas se considera al núcleo como el sistema operativo en sí. Pero incluso si no lo consideramos así, y contemplamos al sistema operativo como el conjunto formado por el núcleo y una serie de herramientas (editor, compilador, enlazador, shell...), es innegable que el kernel es la parte del sistema más importante, y con diferencia: mientras que las aplicaciones operan en el espacio de usuario, el núcleo siempre trabaja en el modo privilegiado del procesador (RING 0). Esto implica que no se le impone ninguna restricción a la hora de ejecutarse: utiliza todas las instrucciones del procesador, direcciona toda la memoria, accede directamente al hardware (más concretamente, a los manejadores de dispositivos), etc. De esta forma, un error en la programación, o incluso en la configuración del núcleo puede ser fatal para nuestro sistema.

Por desgracia muchos administradores piensan que un intruso nunca va a actuar a un nivel tan bajo para comprometer al sistema. Si bien es cierto que en redes habituales la inmensa mayoría de atacantes no poseen los conocimientos necesarios para utilizar el kernel del sistema operativo en beneficio propio, cualquier pirata con el suficiente nivel de experiencia puede conseguir privilegios de root y aprovecharlos para modificar el núcleo o configurarlo a su gusto. Y es justamente este tipo de ataques uno de los más difíciles de detectar: cualquier administrador tiende a confiar ciegamente en lo que el sistema operativo le dice, de forma que si ejecuta la orden
anita:~# uptime
3:46am  up 9 days,  2:22,  6 users,  load average: 1.15, 1.05, 1.07
anita:~#
automáticamente va a asumir que su sistema ha permanecido más de nueve días sin reiniciarse; esto puede ser cierto o no serlo, e independientemente de la veracidad del resultado de esta orden alguien puede haber accedido a nuestro kernel y haber comprometido su seguridad. Por ejemplo, si ha modificado completamente el núcleo, puede haber reprogramado la llamada sysinfo() para que devuelva un resultado erróneo, de forma que el administrador nunca se percate que la máquina ha sido reiniciada para cargar el kernel modificado; incluso en los Unices que soportan la inserción de módulos en el núcleo (como Linux, Solaris o FreeBSD) el atacante puede haber utilizado esta facilidad para modificar el kernel sin necesidad de reiniciar el equipo; excelentes lecturas sobre este tipo de ataques son [Pla99], [Pra99b] o [Pra99a].

Evidentemente, para cualquier intruso el ataque a un núcleo es mucho más fácil en clones de Unix cuyo código fuente esté disponible, como Linux, Minix o algunos BSD, pero el ataque es posible en cualquier sistema ([Pla99] lo demuestra sobre Solaris). El hecho de la completa disponibilidad del código fuente de un sistema operativo (ahora no hablamos de aplicaciones, nos referimos al sistema operativo propiamente dicho) suele despertar controversias entre la comunidad científica dedicada a la seguridad informática: mientras unos argumentan que esta disponibilidad supone un problema de seguridad - un atacante puede dedicarse a revisar el código hasta encontrar un error de programación, y aprovecharlo -, otros les acusan de defender las teorías de Security through Obscurity y sostienen que cuanta más gente tenga acceso al código más errores se localizarán y solucionarán, y por tanto a la larga se va a conseguir un sistema mucho más robusto. Esta segunda postura es la que más fuerza está tomando desde hace unos años, y parece también la más razonable: es cierto que un atacante puede dedicarse a leer código hasta encontrar un error, pero se ha comprobado que la mayoría de los fallos no se suelen detectar de esta forma, sino por cualquier circunstancia que genera un evento extraño sobre el que posteriormente se investiga. Por tanto, la disponibilidad del código del núcleo no debe suponer una amenaza a la seguridad a priori10.1. Además, un administrador de sistemas con un mínimo nivel de conocimientos de programación puede aprovechar la disponibilidad del código para detectar rápidamente problemas de seguridad: por ejemplo, si sospecha que alguien utiliza sus recursos para ejecutar programas adivinadores de contraseñas, puede modificar librerías para detectar llamadas `sospechosas' a la función crypt(), o si piensa que determinado usuario ejecuta un programa setuidado para conseguir privilegios que no le corresponden, puede modificar la llamada al sistema setuid() para comprobar si sus sospechas son ciertas.

Visto esto, parece claro que el núcleo va a representar un pilar básico para conseguir un sistema seguro; es más, al ser el kernel la base del sistema operativo, no sirve de nada esforzarse en conseguir seguridad a nivel de aplicación si nuestro núcleo es inseguro. En este capítulo vamos a tratar aspectos relativos a la seguridad de los núcleos de sistemas Unix, y también hablaremos de aspectos que, sin pertenecer estrictamente al kernel, son de un nivel tan bajo que su funcionamiento es muy dependiente de cada versión de Unix. Como cada clon del sistema operativo tiene sus métodos para configurar o recompilar el kernel, y en además en este trabajo no podemos tratar extensamente cada uno de ellos, es indispensable en cada caso consultar los manuales antes de modificar cualquier parámetro de los vistos aquí.


Linux

Opciones de compilación

A la hora de recompilar un nuevo núcleo de Linux hemos de tener en cuenta algunas opciones dentro del grupo `Networking Options' que pueden afectar a la seguridad de nuestra máquina (algunos de estos aspectos, para núcleos 2.0, pueden encontrarse en [Wre98]). Sin embargo, antes de entrar en detalles con opciones concretas, es muy conveniente que introduzcamos soporte para sistemas de ficheros proc en `Filesystems' (CONFIG_PROC_FS) y activemos el interfaz sysctl en `General Setup' (CONFIG_SYSCTL); con estos pasos habilitamos la capacidad de Linux para modificar ciertos parámetros del núcleo (en /proc/sys/) sin necesidad de reiniciar el sistema o recompilar el kernel.

Pasando ya a comentar algunas opciones que nos ofrece Linux, es bastante interesante para la seguridad configurar nuestro sistema como un cortafuegos a la hora de compilar el núcleo (CONFIG_IP_FIREWALL). Linux ofrece en su kernel facilidades para definir un firewall de paquetes en el sistema, que además permitirá el IP-Masquerading. Para que el subsistema de filtrado funcione es necesario que el IP-Forwarding esté activado de la forma que más tarde veremos.

Otra opción que nos puede ayudar a incrementar la seguridad de nuestro equipo es la defragmentación de paquetes (CONFIG_IP_ALWAYS_ DEFRAG) que llegan a través de la red. Cuando un equipo situado entre el origen y el destino de los datos decide que los paquetes a enviar son demasiado grandes, los divide en fragmentos de longitud menor; sin embargo, los números de puerto sólamente viajan en el primer fragmento, lo que implica que un atacante puede insertar información en el resto de tramas que en teoría no debe viajar en ellas. Activando esta opción, en nuestra máquina estos fragmentos se reagruparán de nuevo incluso si van a ser reenviados a otro host.

Siguiendo con las diferentes opciones del subsistema de red, podemos habilitar el soporte para `SYN Cookies' (CONFIG_SYN_COOKIES) en el núcleo que estamos configurando. Una red TCP/IP habitual no puede soportar un ataque de negación de servicio conocido como `SYN Flooding', consistente básicamente en enviar una gran cantidad de tramas con el bit SYN activado para así saturar los recursos de una máquina determinada hasta que los usuarios no pueden ni siquiera conectar a ella. Las `SYN Cookies' proporcionan cierta protección contra este tipo de ataques, ya que la pila TCP/IP utiliza un protocolo criptográfico para permitir que un usuario legítimo pueda seguir accediendo al sistema incluso si este está siendo atacado. Aunque configuremos y ejecutemos un núcleo con esta opción soportada, hemos de activar las `SYN Cookies' cada vez que el sistema arranca (como veremos luego), ya que por defecto están deshabilitadas.

En ciertas situaciones es interesante analizar en espacio de usuario - es decir, sin sobrecargar al núcleo más de lo estrictamente necesario - un paquete o parte de él (típicamente, los 128 primeros bytes) que llega a través de la red hasta nuestra máquina; de esta forma, un analizador simple puede tomar ciertas decisiones en función del contenido del paquete recibido, como enviar un correo al administrador en caso de sospecha o grabar un mensaje mediante syslog. Justamente esto es lo que conseguimos si habilitamos la opción Firewall Packet Netlink Device (CONFIG_IP_FIREWALL_ NETLINK).

Hasta ahora hemos hablado de la posibilidad que tiene Linux para modificar parámetros del núcleo sin necesidad de recompilarlo o de reiniciar el equipo, mediante el interfaz sysctl; esto implica por ejemplo que podemos modificar el comportamiento del subsistema de red simplemente modificando determinados ficheros de /proc/sys/ (recordemos que el sistema de ficheros /proc/ de algunos Unix es una interfaz entre estructuras de datos del núcleo y el espacio de usuario). Vamos a ver ahora algunos de estos parámetros configurables que tienen mucho que ver con la seguridad del sistema:

Uno de los parámetros que nos interesa es la habilitación o deshabilitación del IP Forwarding en el núcleo de Linux; como hemos dicho antes, el sistema de filtrado de paquetes sólo funciona cuando esta opción está habilitada, lo que se consigue con la orden
luisa:~# echo 1 > /proc/sys/net/ipv4/ip_forward
Sin embargo, si no utilizamos las facilidades de firewalling del núcleo de Linux esta opción ha de estar desabilitada (introduciríamos un `0' en lugar de un `1' en el fichero anterior), ya que de lo contrario corremos el peligro de que nuestra máquina se convierta en un router.

Antes hemos hablado de las `SYN Cookies', y hemos comentado que aunque el soporte para esta característica se introduce al compilar el núcleo, realmente el mecanismo se ha de activar desde espacio de usuario, por ejemplo con una orden como la siguiente:
luisa:~# echo 1 >/proc/sys/net/ipv4/tcp_syncookies
También es muy recomendable que el subsistema de red del kernel descarte las tramas con Source Routing o encaminamiento en origen activado. Este tipo de paquetes contienen el camino que han de seguir hasta su destino, de forma que los routers por los que pasa no han de examinar su contenido sino simplemente reenviarlo, hecho que puede causar la llegada de datos que constituyan una amenaza a nuestras políticas de seguridad. En los núcleos 2.0 esto se conseguía activando la opción CONFIG_IP_NOSR, mientras que en los 2.2 la forma más sencilla de ignorar estos paquetes es introduciendo un `0' en los diferentes ficheros accept_source_route del directorio /proc/sys/net/ipv4/; por ejemplo la siguiente orden descarta las tramas con encaminamiento en origen que llegan al dispositivo de red eth0:
luisa:~# echo 0 >/proc/sys/net/ipv4/conf/eth0/accept_source_route
Hemos de recordar que las modificaciones que hacemos sobre el interfaz sysctl son dinámicas (se pueden efectuar con el sistema funcionando, sin necesidad de reiniciarlo), pero se pierden cuando la máquina se apaga para establecerse a unos valores por defecto al arrancar de nuevo el sistema operativo; seguramente nos interesará mantener los cambios realizados, por lo que en alguno de los ficheros de inicialización de la máquina hemos de incluir las órdenes que acabamos de explicar, obviamente después de haber montado el sistema de ficheros /proc/.

Dispositivos

Linux (no así otros Unices) proporciona dos dispositivos virtuales denominados /dev/random y /dev/urandom que pueden utilizarse para generar números pseudoaleatorios, necesarios para aplicaciones criptográficas. El primero de estos ficheros, /dev/random, utiliza lo que su autor denomina `ruido ambiental' (por ejemplo, temporizadores de IRQs, accesos a disco o tiempos entre pulsaciones de teclas) para crear una fuente de entropía aceptable y - muy importante - que apenas introduce sobrecarga en el sistema. El segundo archivo, /dev/urandom, crea un resumen de la entropía de /dev/random utilizando la función hash SHA ( Secure Hash Algorithm), diseñada por el NIST y la NSA para su Digital Signature Standard ([oST84]). Por tanto, tenemos una fuente de entropía aceptable, /dev/urandom, y otra incluso mejor, pero de capacidad limitada, /dev/random. Para detalles concretos sobre su funcionamiento se puede consultar el fichero que las implementa dentro del núcleo de Linux, drivers/char/random.c.

Como en el propio código se explica, cuando un sistema operativo arranca ejecuta una serie de acciones que pueden ser predecidas con mucha facilidad por un potencial atacante (especialmente si en el arranque no interactua ninguna persona, como es el caso habitual en Unix). Para mantener el nivel de entropía en el sistema se puede almacenar el desorden que existía en la parada de la máquina para restaurarlo en el arranque; esto se consigue modificando los scripts de inicialización del sistema. En el fichero apropiado que se ejecute al arrancar (por ejemplo, /etc/rc.d/rc.M) debemos añadir las siguientes líneas:
echo "Initializing random number generator..."
random_seed=/var/run/random-seed
# Carry a random seed from start-up to start-up
# Load and then save 512 bytes, which is the size of the entropy pool
if [ -f $random_seed ]; then
      cat $random_seed >/dev/urandom
fi
dd if=/dev/urandom of=$random_seed count=1
chmod 600 $random_seed
Mientras que en un fichero que se ejecute al parar el sistema añadiremos lo siguiente:
# Carry a random seed from shut-down to start-up
# Save 512 bytes, which is the size of the entropy pool
echo "Saving random seed..."
random_seed=/var/run/random-seed
dd if=/dev/urandom of=$random_seed count=1
chmod 600 $random_seed
Con estas pequeñas modificaciones de los archivos de arranque y parada del sistema conseguimos mantener un nivel de entropía aceptable durante todo el tiempo que el sistema permanezca encendido. Si de todas formas no consideramos suficiente la entropía proporcionada por estos dispositivos de Linux, podemos conseguir otra excelente fuente de desorden en el mismo sistema operativo a partir de una simple tarjeta de sonido y unas modificaciones en el núcleo ([Men98]), o utilizar alguno de los generadores - algo más complejos - citados en [Sch94].

Algunas mejoras de la seguridad

En esta sección vamos a comentar algunos aspectos de modificaciones del núcleo que se distribuyen libremente en forma de parches, y que contribuyen a aumentar la seguridad de un sistema Linux; para obtener referencias actualizadas de estos códigos - y otros no comentados aquí - es recomendable consultar [Sei99]; para información de estructuras de datos, ficheros o límites del núcleo de Linux se puede consultar [BBD$^$96] o [CDM97].

Límites del núcleo

En include/asm/resource.h tenemos la inicialización de algunas estructuras de datos del núcleo relacionadas con límites a la cantidad de recursos consumida por un determinado proceso; por ejemplo, el máximo número de procesos por usuario (RLIMIT_NPROC) se inicializa a
MAX_TASKS_PER_ USER, valor que en include/linux/tasks.h podemos comprobar que se corresponde con la mitad de NR_TASKS (número máximo de procesos en el sistema); en arquitecturas i86 el valor del límite de procesos por usuario se fija a 256. De la misma forma, el número máximo de ficheros abiertos por un proceso (RLIMIT_NOFILE) se inicializa al valor NR_OPEN, que en el archivo include/asm/limits.h se define como 1024.

Estos límites se pueden consultar desde espacio de usuario con la llamada getrlimit(); esta función utiliza una estructura de datos rlimit, definida en include/linux/resource.h, que contiene dos datos enteros para representar lo que se conoce como límite soft o blando y límite hard o duro. El límite blando de un recurso puede ser modificado por cualquier proceso sin privilegios que llame a setrlimit(), ya sea para aumentar o para disminuir su valor; por el contrario, el límite hard define un valor máximo para la utilización de un recurso, y sólo puede ser sobrepasado por procesos que se ejecuten con privilegios de administrador.

En el fichero include/linux/nfs.h podemos definir el puerto máximo que los clientes NFS pueden utilizar (NFS_PORT); si le asignamos un valor inferior a 1024 (puertos privilegiados), sólo el administrador de otro sistema Unix podrá utilizar nuestros servicios NFS, de forma similar a la variable nfs_portmon de algunos Unices.

Para cambiar los límites de los parámetros vistos aquí la solución más rápida pasa por modificar los ficheros de cabecera del kernel, recompilarlo y arrancar la máquina con el nuevo núcleo; sin embargo, a continuación vamos a hablar brevemente de Fork Bomb Defuser, un módulo que permite al administrador modificar algunos de estos parámetros sin reiniciar el sistema.

Fork Bomb Defuser

El kernel de Linux no permite por defecto limitar el número máximo de usuarios y el número máximo de procesos por usuario que se pueden ejecutar en el sistema sin tener que modificar el código del núcleo; si no queremos modificarlo, casi no hay más remedio que utilizar un poco de programación (unos simples shellscripts suelen ser suficientes) y las herramientas de planificación de tareas para evitar que un usuario lance demasiados procesos o que conecte cuando el sistema ya ha sobrepasado un cierto umbral de usuarios conectados a él.

Mediante el módulo Fork Bomb Defuser se permite al administrador controlar todos estos parámetros del sistema operativo, incrementando de forma flexible la seguridad de la máquina. El código está disponible en http://rexgrep.tripod.com/rexfbdmain.htm.

Secure Linux

Por Secure Linux se conoce a una colección de parches para el núcleo de Linux programados por Solar Designer, uno de los hackers más reconocidos a nivel mundial en la actualidad (entendiendo hacker en el buen - y único - sentido de la palabra). Este software, disponible libremente desde http://www.false.com/security/linux/10.2, incrementa la seguridad que el núcleo proporciona por defecto, ofreciendo cuatro importantes diferencias con respecto a un kernel normal:

Auditd

El demonio auditd permite al administrador de un sistema Linux recibir la información de auditoría de seguridad que el núcleo genera, a través del fichero /proc/audit, filtrarla y almacenarla en ficheros. Esta información tiene el siguiente formato:
AUDIT_CONNECT pid ruid shost sport dhost dport
Conexión desde la máquina al host remoto dhost.
AUDIT_ACCEPT pid ruid shost sport dhost dport
Conexión desde el host remoto dhost a la máquina.
AUDIT_LISTEN pid ruid shost sport
El puerto indicado está esperando peticiones de servicio.
AUDIT_OPEN pid ruid file
Se ha abierto el fichero file.
AUDIT_SETUID pid old_ruid ruid euid
Se ha llamado con éxito a setuid(), modificando el UID de ruid a euid.
AUDIT_EXEC pid ruid file
Se ha ejecutado el fichero file.
AUDIT_MODINIT pid ruid file
Se ha insertado en el kernel el módulo file.
Al leer la información de /proc/audit, el demonio auditd lee las reglas de filtrado del fichero /etc/security/audit.conf, comparando los flags, PID y RUID ( Real User IDentifier) recibidos con cada una de las reglas del archivo de configuración hasta encontrar la apropiada para tratar el evento. Una vez que el demonio auditd ha encontrado el fichero donde almacenar la información recibida, la guarda en él con un formato legible.

Solaris

El subsistema de red

Como en el caso de Linux - y de cualquier Unix - es conveniente detener los paquetes que contengan en ellos el camino a seguir hasta su destino (lo que se conoce por source routing, encaminamiento en origen); en Solaris esto se consigue con la orden
anita:~# /usr/sbin/ndd -set /dev/ip ip_forward_src_routed 0
La orden ndd se utiliza para visualizar y modificar los parámetros de un determinado driver; por ejemplo, si quisiéramos comprobar los parámetros de /dev/ip, lo haríamos con la orden
anita:~# /usr/sbin/ndd /dev/ip \?
El uso del carácter `$\backslash$' no es más que un escape del shell para el símbolo `?'.

Mientras que en Linux era necesario el IP Forwarding para que el sistema de filtrado de paquetes funcione correctamente, en Solaris es conveniente deshabilitar esta opción para evitar que nuestro equipo se convierta en un router. En algunas versiones de Solaris basta crear el fichero /etc/notrouter para deshabilitar el rutado, pero se suele utilizar más a menudo la siguiente orden:
anita:~# /usr/sbin/ndd -set /dev/ip ip_forwarding 0
Si queremos prevenir ataques de ARP Spoofing es conveniente dar un tiempo de vida a las entradas de la tabla de direcciones físicas. En este caso las órdenes a ejecutar (para un tiempo de vida de un minuto) son
anita:~# /usr/sbin/ndd -set /dev/ip ip_ire_flush_interval 60000
anita:~# /usr/sbin/ndd -set /dev/arp arp_cleanup_interval 60
Una máquina Solaris con más de un interfaz de red actúa automáticamente como un router de paquetes entre los interfaces; hemos desabilitado el IP Forwarding, pero para conseguir que los paquetes que lleguen por un interfaz y tengan otro como destino se descarten, previniendo así el Host Spoofing hemos de modificar las siguientes variables del kernel:
anita:~# /usr/sbin/ndd -set /dev/ip ip_strict_dst_multihoming 1
anita:~# /usr/sbin/ndd -set /dev/ip ip_ignore_redirect 1
Hay que resaltar que la configuración mediante ndd de los parámetros anteriores permanecerá hasta que el sistema se reinicie, pero en ese momento se perderá y todos los parámetros volverán a sus valores por defecto; para solucionarlo, podemos crear un script que se ejecute al iniciar el sistema y que lanze todas las órdenes vistas anteriormente. Esto se puede hacer, por ejemplo, creando el fichero /etc/init.d/nddconfig con el siguiente contenido10.3:
#!/bin/sh
#
# /etc/init.d/nddconfig
#

# Fix for broadcast ping bug
/usr/sbin/ndd -set /dev/ip ip_respond_to_echo_broadcast 0

# Block directed broadcast packets
/usr/sbin/ndd -set /dev/ip ip_forward_directed_broadcasts 0

# Prevent spoofing
/usr/sbin/ndd -set /dev/ip ip_strict_dst_multihoming 1
/usr/sbin/ndd -set /dev/ip ip_ignore_redirect 1

# No IP forwarding
/usr/sbin/ndd -set /dev/ip ip_forwarding 0

# Drop source routed packets
/usr/sbin/ndd -set /dev/ip ip_forward_src_routed 0
             
# Shorten ARP expiration to one minute to minimize ARP spoofing/hijacking
# [Source: Titan adjust-arp-timers module]
/usr/sbin/ndd -set /dev/ip ip_ire_flush_interval 60000    
/usr/sbin/ndd -set /dev/arp arp_cleanup_interval 60
Tras crear este archivo hemos de enlazarlo con otro nombre en /etc/rc2.d/, para que se ejecute al entrar en un runlevel 2, por ejemplo con la orden
anita:~# ln /etc/init.d/nddconfig /etc/rc2.d/S70nddconfig

El fichero /etc/system

En este archivo el administrador de un equipo Solaris puede definir variables para el núcleo del sistema operativo, como el número máximo de ficheros abiertos por un proceso o el uso de memoria compartida, semáforos y mensajes para intercomunicación entre procesos. En este apartado vamos a comentar algunos de estos parámetros que pueden afectar a la seguridad; hablaremos especialmente de aquellos que pueden y deben ser limitados para evitar diversos tipos de negaciones de servicio, ataques que recordemos afectan a la disponibilidad de nuestros recursos. Los cambios que se realicen en este archivo no tendrán efecto hasta que la máquina se reinicie con la orden
anita:~# reboot -- -r
o se cree el archivo /reconfigure y se reinice con un reboot normal:
anita:~# touch /reconfigure
anita:~# reboot
Si deseamos ver el valor de alguno de los parámetros en el kernel que se está ejecutando en este momento, lo podemos hacer con la orden adb (nótese que no ofrece ningún prompt, hemos de escribir directamente el parámetro a visualizar, con un `/D' al final para que nos muestre el valor en decimal):
anita:~# adb -k /dev/ksyms /dev/mem
physmem 38da
maxusers/D
maxusers:
maxusers:       56
maxuprc/D
maxuprc:
maxuprc:        901
^d
anita:~#
Una negación de servicio muy típica en Unix es el consumo excesivo de recursos por parte de usuarios que lanzan - voluntaria o involuntariamente - demasiados procesos; esto es especialmente común en sistemas de I+D, donde muchos usuarios se dedican a programar, y un pequeño error en el código (a veces denominado `runaway fork') puede hacer que el sistema se vea parado por un exceso de procesos activos en la tabla. La gravedad del problema aumenta si pensamos que también es muy habitual que los usuarios lancen simulaciones que tardan en ejecutarse varios días (o varias semanas), de forma que una parada inesperada puede causar la pérdida de muchas horas de trabajo. Por tanto, parece obvio que es recomendable limitar el número de procesos simultáneos por usuario; en Solaris este número está ilimitado por defecto, por lo que si deseamos asignar un valor máximo hemos de editar el fichero /etc/system e incluir una línea como la siguiente:
set maxuprc=60
De esta forma limitamos el número de procesos por usuario a 60 (un número aceptable en la mayoría de sistemas10.4), consiguiendo así que un error en un programa no sea capaz de detener la máquina.

Un parámetro del sistema operativo especialmente importante, y que quizás nos interese modificar (sobre todo en máquinas con pocos recursos) es maxusers. Al contrario de lo que mucha gente cree, maxusers no hace referencia al número máximo de usuarios que pueden conectar simultáneamente al sistema, sino que es un valor que escala a otros parámetros del núcleo (como max_nproc, número máximo de procesos en la tabla) o maxuprc. Para modificarlo, podemos incluir en /etc/system una línea con el valor deseado, generalmente el tamaño en MB de la memoria física de nuestra máquina ([Dik99]):
set maxusers=128
También puede ser conveniente limitar parámetros del sistema operativo relativos al sistema de ficheros, ya que también se pueden producir negaciones de servicio relacionadas con ellos. Por ejemplo, es interesante poder limitar el número máximo de ficheros abiertos mediante los parámetros rlim_fd_max (límite hard) y rlim_fd_cur (límite soft) o evitar que los usuarios puedan utilizar chown() en sus ficheros, especificando un valor 1 para la variable rstchown (este es el comportamiento por defecto; si no lo seguimos, aparte de comprometer la seguridad los usuarios sin privilegios podrían ignorar el sistema de quotas).

En algunas arquitecturas SPARC (concretamente en sun4u, sun4d y sun4m) es posible establecer una protección hardware para prevenir ataques de buffer overflow; para ello, en /etc/system hemos de incluir una línea como
set noexec_user_stack=1
Y si además queremos monitorizar los intentos de ataque de este tipo, incluimos en el archivo la línea
set noexec_user_stack_log=1
Si administramos un servidor NFS y deseamos que ignore las peticiones de clientes que no provengan de puertos privilegiados (es decir, que no hayan sido solicitadas por un usuario privilegiado de la máquina cliente) podemos definir la variable NFS_PORTMON en /etc/system; si usamos versiones de Solaris anteriores a la 2.5, debemos incluir una línea como
set nfs:nfs_portmon = 1
mientras que en Solaris 2.5 y posteriores utilizaremos
set nfssrv:nfs_portmon = 1

HP-UX

Generalmente se recomienda utilizar la herramienta SAM ( System Administration Manager) en los sistemas HP-UX, que además de las tareas clásicas de administración permite modificar parámetros de un núcleo, reconstruirlo e instalarlo en el sistema de una forma sencilla, guardando una copia del kernel actual en /SYSBACKUP (algo muy útil, ya que recordemos que un núcleo mal configurado puede hacer que la máquina no arranque). Por tanto, desde SAM hemos de entrar en el menú `Kernel Configuration' y desde ahí elegir los parámetros que deseamos modificar para construir el nuevo kernel; como en el caso de Solaris, podemos fijar el parámetro maxusers (también con un significado similar al que esta variable posee en Solaris) y también el número máximo de procesos por usuario (parámetro maxuprc).

Si deseamos modificar y reconstruir el nuevo núcleo a mano, el proceso difiere de HP-UX 9.x a HP-UX 10.x. Los pasos en ambos casos son los siguientes:
HP-UX 9.x
# cd /etc/conf
# cp dfile dfile.old
# vi dfile
# config dfile
# make -f config.mk
# mv /hp-ux /hp-ux.old
# mv /etc/conf/hp-ux /hp-ux
# cd / ; shutdown -ry 0
HP-UX 10.x
# cd /stand/build
# /usr/lbin/sysadm/system_prep -s system
# vi system
# mk_kernel -s system
# mv /stand/system /stand/system.prev
# mv /stand/build/system /stand/system
# mv /stand/vmunix /stand/vmunix.prev
# mv /stand/build/vmunix_test /stand/vmunix
# cd / ; shutdown -ry 0
Al editar los ficheros /etc/conf/dfile (HP-UX 9.x) o /stand/build/system (HP-UX 10.x) hemos de especificar los parámetros comentados anteriormente, de la forma
maxuprc     60
maxusers    100
Otros parámetros a tener en cuenta relacionados con la gestión de procesos son nproc (número máximo de procesos en el sistema), nkthread (número máximo de hilos simultáneos en el núcleo) o max_thread_proc (número máximo de hilos en un proceso).

Igual que en Solaris - y en cualquier Unix en general - también nos puede interesar limitar algunos parámetros relacionados con el sistema de ficheros, de cara a evitar posibles consumos excesivos de recursos que puedan comprometer nuestra seguridad. Por ejemplo, maxfiles indica un límite soft a los ficheros abiertos por un proceso y maxfiles_lim un límite hard (que obviamente ha de ser mayor que el anterior); nfile indica el número máximo de ficheros abiertos en el sistema y ninode el número de inodos (se recomienda que ambos coincidan). Por último, nflocks indica el número máximo de ficheros abiertos y bloqueados en la máquina.

IRIX

Como en cualquier Unix, antes de pasar a modificar parámetros del núcleo es conveniente guardar una copia del mismo para poder arrancar la máquina en caso de problemas; en IRIX, esto lo conseguimos con una orden como la siguiente:
# cp /unix /unix.SAV
Una vez tenemos la copia, podemos pasar a modificar el kernel del sistema operativo, igual que en los ejemplos anteriores, para evitar principalmente negaciones de servicio por un consumo excesivo de recursos. Para modificar parámetros hemos de utilizar la orden systune, como se muestra a continuación:
# systune -i
Updates will be made to running system and /unix.install
systune-> nproc 
       nproc = 400 (0x190)
systune-> nproc = 500 
       nproc = 400 (0x190) 
       Do you really want to change nproc to 500 (0x1f4)? (y/n) y
In order for the change in parameter nproc to become effective /unix.install 
must be moved to /unix and the system rebooted
systune-> quit
#
En este ejemplo acabamos de consultar y modificar el valor del parámetro nproc, que indica el número máximo de procesos en la máquina (a continuación se comentarán con detalle algunos de estos parámetros útiles de cara a la seguridad). Podemos comprobar que tras modificar su valor los cambios se almacenan en un fichero llamado /unix.install, que no es más que la nueva imagen del núcleo que acabamos de crear; para que los cambios tengan efecto hemos de reiniciar el sistema, lo que automáticamente moverá este nuevo kernel al fichero /unix: por eso hemos de guardar previamente una copia de la imagen original en /unix.SAV, por ejemplo.

Limitando el número total de procesos en la máquina a un valor aceptable para nuestro sistema podemos evitar muchas negaciones de servicio; otra forma de evitarlas es modificando el parámetro maxup, que representa el número máximo de procesos por usuario; su valor, que por defecto es 150, siempre se recomienda que sea menor que nproc-5 ([Zur94]).

Si lo que queremos es limitar el el número máximo de ficheros abiertos por cada proceso podemos asignar el valor que nos interese al parámetro rlimit_nofile_cur, que por defecto está a 200; el valor que le asignemos siempre ha de ser menor que rlimit_nofile_max, por lo que quizás también necesitemos modificar este parámetro.

Otros parámetros del núcleo que quizás nos resulte interesante modificar de cara a nuestra seguridad son nosuidshells (si su valor es distinto de 0 evita que las aplicaciones puedan crear shells setuidados y pertenecientes al administrador), restricted_chown, que define si el estilo de la llamada chown() es BSD (con un valor 0, indicando que sólo el administrador puede cambiar la propiedad de los archivos) o System V (si su valor es 1 indica que cualquier usuario puede utilizar chown()) o nfs_portmon (si es 1 los clientes NFS sólo pueden ser lanzados por administradores remotos, porque han de utilizar puertos privilegiados).

Pasando ya a la configuración del subsistema de red, si en IRIX queremos deshabilitar el IP Forwarding (por defecto está activado en máquinas con más de un interfaz) hemos de editar una configuración del kernel ( /var/sysgen/master.d/bsd) y modificar el valor de la variable ipforwarding de 1 a 0:
int ipforwarding = 0;
Una vez modificado este archivo hemos de ejecutar la orden autoconfig -f, que al igual que sysinfo -i genera un fichero /unix.install que se convierte en /unix (la imagen del núcleo) al reiniciar el sistema.

Antes de finalizar esta sección hay que citar como consulta obligatoria [JZRT99], una obra que proporciona a cualquier administrador de IRIX una visión particular de la seguridad para este sistema operativo, desde un repaso a las herramientas de backup hasta una descripción de las listas de control de acceso, pasando por el sistema de monitorización en IRIX.

SCO Openserver

La configuración de tunables en SCO Openserver se puede realizar utilizando diversas herramientas del operativo, generalmente configure, idtune, getconf o inconfig ([MS94]); por ejemplo, si deseamos modificar el número máximo de procesos en el sistema, lo podemos hacer a través de /etc/conf/cf.d/configure. Esta utilidad nos mostrará un menú con diferentes categorías de parámetros configurables; en nuestro caso debemos elegir MAX_PROC, disponible en la sección Table limits de Configuration Tunables. También podemos configurar aquí el máximo número de descriptores de fichero en uso en el sistema, modificando el valor del parámetro MAX_FILE (<este parámetro no controla el número máximo de ficheros abiertos por proceso!).

Utilizando esta misma utilidad, pero ahora en la sección User and group configuration podemos definir el número máximo de ficheros que un proceso puede abrir simultáneamente (NOFILES), el tamaño de fichero máximo que un usuario puede crear (ULIMIT), el número de procesos simultáneos bajo un mismo identificador de usuario distinto del root (MAXUP), el límite de memoria virtual de un proceso sin privilegios (MAXUMEM) y el comportamiento de la orden chown (CHOWN_RES, donde 0 - valor por defecto - indica que los usuarios no pueden modificar la propiedad de los archivos).

Si modificamos parámetros del núcleo mediante configure debemos reconstruir el kernel del sistema y situarlo en /etc/conf/cf.d/; ambas cosas se consiguen mediante la orden link_unix, situada en ese mismo directorio. Esta utilidad copiará además el núcleo actual, /unix, en /unix.old, para poder arrancar con él en caso de que algo grave suceda al introducir modificaciones:
cristina:~# cd /etc/conf/cf.d/
cristina:/etc/conf/cf.d# ./link_unix
        The UNIX Operating System will now be rebuilt.
        This will take a few minutes. Please wait.
 
        Root for this system build is /.

        The UNIX Kernel has been rebuilt.

Do you want this kernel to boot by default? (y/n) y
Backing up /unix to /unix.old
Installing new /unix

The kernel environment includes device node files and /etc/inittab.
The new kernel may require changes to /etc/inittab or device nodes.

Do you want the kernel environment rebuilt? (y/n) y

The kernel has been successfully linked and installed.
        To activate it, reboot your system.

cristina:/etc/conf/cf.d#
Para configurar parámetros globales del subsistema de red en SCO Openserver podemos utilizar la orden inconfig. Esta utilidad actualizará los datos definidos en /etc/default/inet, así como los que el núcleo en ejecución está utilizando; de esta forma, y al contrario de lo que sucede al utilizar configure, no es necesario reiniciar el sistema para que los nuevos valores se inserten en el kernel, ya que inconfig lo actualiza de forma dinámica (si alguno de los nuevos valores es erróneo, se mantienen los valores actuales para el parámetro correspondiente).

La orden inconfig recibe como argumentos el parámetro a configurar y su nuevo valor; así, si por ejemplo deseamos desactivar el IP Forwarding en nuestra máquina (aunque por defecto ya lo está), podemos conseguirlo con una orden como la siguiente:
cristina:~# inconfig ipforwarding 0
cristina:~#
Una máquina con el IP Forwarding desactivado aún reenviará paquetes source route; para evitar que esto ocurra hemos de asignar al parámetro ipnonlocalsrcroute el valor 0 (utilizado por defecto en SCO Openserver).

Otro de los parámetros del subsistema de red en nuestra máquina que nos puede interesar modificar de cara a aumentar la seguridad es el tiempo de expiración de las entradas de la tabla ARP (por defecto, establecido a veinte minutos); el parámetro de inconfig en este caso será arpt_keep seguido del valor deseado. Además, la tabla ARP se escanea cada cinco minutos en busca de entradas caducas; podemos modificar este tiempo con el parámetro arpt_prune de inconfig.

Para prevenir ataques de IP Spoofing contra el sistema, el núcleo de SCO Openserver introduce un número aleatorio para generar los números de secuencia y el incremento de los mismos en los paquetes TCP; el parámetro tcp_secret es la semilla que alimenta al generador de números aleatorios, y su valor puede ser cualquiera entre 0 y 2147483647. El número de bits de tcp_secret utilizados realmente como semilla lo define el parámetro tcp_seqbits, con un valor entre 16 y 26; el valor por defecto, 21, es una buena elección para nuestra seguridad: si tcp_seqbits es demasiado bajo, aumenta la posibilidad de que un pirata pueda adivinar el número aleatorio que se genera - lo que le facilitaría el ataque -, pero si es demasiado alto se reduce el intervalo entre la aparición de dos números de secuencia iguales, lo que evidentemente también facilita un ataque.

Resumen

En este capítulo hemos hablado de ciertos parámetros del kernel de un sistema Unix que pueden afectar a su seguridad, principalmente a nivel de red y de límites de recursos (para prevenir ataques de negación de servicio, voluntarios o involuntarios, por parte de los usuarios). Aunque las bases de todos los problemas suelen ser comunes a cualquier Unix, se ha particularizado la forma de evitarlos para algunos de los clones más utilizados; en el caso de Unices no vistos aquí, pero también en los que hemos tratado (se trata de información que puede cambiar entre versiones de un mismo operativo), es indispensable - se dijo en la introducción y se insiste ahora - consultar la documentación del sistema y asegurarse muy bien de lo que se está haciendo antes de reconfigurar un núcleo, ya que un error aquí puede ser fatal para la máquina.

En la tabla 9.1 se presentan de forma compacta los parámetros vistos en este capítulo para los diferentes clones de Unix; hemos preferido no dar valores `óptimos' para cada uno de ellos, ya que el valor ideal viene dado por las características de cada sistema: cada administrador ha de conocer lo que es habitual en sus máquinas para de esta forma detectar lo inusual, y con ello los posibles problemas de seguridad que puedan existir.
Tabla 9.1: Parámetros del núcleo para diferentes Unices

\begin{sideways} \begin{tabular}{\vert c\vert c\vert c\vert c\vert c\vert c\vert... ...fssrv:nfs\_portmon & - & nfs\_portmon & - \ \hline \end{tabular}\end{sideways}



Notas al pie

... priori10.1
Sin embargo, ningún Trusted Unix tiene su código disponible...
... http://www.false.com/security/linux/10.2
Esta URL ya no existe, ahora los trabajos de Solar Designer se encuentran en http://www.openwall.com/; gracias, David :).
... contenido10.3
Ejemplo extraído de Solaris Security Guide, documento disponible en http://www.sabernet.net, de autor desconocido.
... sistemas10.4
Aunque en algunos documentos se recomienda, para otros Unices, un número máximo de 200 procesos ([CH99]).

next up previous contents
Next: Seguridad de la subred Up: Seguridad del sistema Previous: Autenticación de usuarios   Índice General