Securizar un linux

Hace un tiempo me encontré un extenso manual sobre como securizar un sistema linux desde el primer momento.

Voy a compartirlo, indicando la fuente: http://www.esdebian.org/wiki/reforzando-instalacion-debian-gnulinux

1- Introducción:

“La insignificancia es siempre una garantía de seguridad” lo dijo alguien de nombre Esopo hace más de 2500 años pero es tan vigente hoy día como lo fue entonces. En lo que a seguridad se refiere, el concepto de costo/beneficio es, por lejos, el más importante. El nivel de seguridad que uno debe lograr debe ser acorde al valor de lo que se desea proteger. Siempre hay un nivel mínimo de seguridad, un equipo conectado a internet debe cumplir ciertos requerimientos básicos para evitar, por ejemplo, ser utilizado por alguien como zombi para atacar a un tercero, eso tiene que ver con la responsabilidad.

Este articulo se ordenará por ítems donde se mencionarán tareas a llevar a cabo a la hora de asegurar un sistema GNU/Linux incluso desde antes de instalar elsistema operativo. Dado que hay diferentes niveles de seguridad, acorde a los requerimientos de la misma, cada ítem contara con una leyenda indicando a que está orientado. Estas leyendas son:

  • Básico: tareas de aseguramiento mínimo que deberían llevarse a cabo en cualquier sistema.
  • Medio: orientado a equipos de escritorio con conexión a la red internet o servidores hogareños.
  • Avanzado: orientado a equipos con el fin de dar servicios de red, con o sin acceso a la red Internet.
  • Crítico: orientado a equipos que manejan información sensible y de confidencialidad crítica, destinados a brindar servicios de red de disponibilidad 100%.

2- Aseguramiento físico

2.1- Ambiente [Básico]
Mantener los niveles de humedad y temperatura.

2.2- Acceso al equipo [Medio]
Para lograr un nivel medio se deberá restringir el acceso a la consola del equipo y al sistema de alimentación del mismo, un nivel avanzado requerirá además ubicar el equipo en un rack bajo llave con acceso controlado al cuarto donde este se encuentra y un sistema UPS que garantice buen tiempo de disponibilidad y la instalación del software necesario para apagar el equipo en caso que el corte del suministro eléctrico se prolongue por demasiado tiempo. Un nivel avanzado seguramente requiera contar con un equipo electrógeno de apoyo (si debe garantizarse disponibilidad) y acceso físico restringido con bitácora de accesos.

3- Pasos previos a la instalación

3.1- Configuración de la BIOS [Medio]
Colocar password de acceso al programa de configuración de la BIOS y restringir el orden selección de dispositivos de arranque para evitar que el sistema sea arrancado desde un CD o Disquete.
3.2- Configuración de dispositivos en la BIOS [Avanzado]
Deshabilitar todo dispositivo de entrada/salida que no sea requerido para el funcionamiento, como puertos USB, puertos serie, puertos paralelos, disqueteras, etc. Una vez instalado el sistema es deseable también deshabilitar las lectoras de CD-DVD y cualquier otro dispositivo, igualmente el sistema operativo puede reconocerlos si fuera necesario.
3.3- Hardware innecesario [Avanzado]
¿Necesita un servidor contar con disquetera, tarjeta de sonido, modem de acceso telefónico, lectora de tarjetas, puertos USB frontales?
Seguramente no, quitemos todo eso del equipo ya que solo sirven para consumir energía y producir calor.
¿Y para que quieres un mouse si solo instalarás el sistema en modo texto? Quita eso también.

4- Instalación

4.1- Selección del medio [Medio]
Instalar el sistema base a partir de un CD de instalación que no requiera conexión a internet, el origen de este CD debe estar verificado así como su integridad mediante el cálculo del hash md5. El sistema no debe conectarse a la red hasta no realizar el total aseguramiento del equipo.

4.2- Diseño del sistema de archivos [Avanzado]

Hay ciertos aspectos que deberemos tener en cuenta a la hora de diseñar el sistema de archivos.
Será deseable en primer lugar crear particiones separadas para /home, /usr, /var, /tmp, /boot ademas de, por supuesto, / y el área de intercambio.
Algunas consideraciones a tener en cuenta para cada partición:

Partición /
* Tamaño: si bien, se debe garantizar un tamaño suficiente, esto depende de que uso se le dará al equipo pero por lo general con 500MB – 1GB será suficiente.
* Opciones de montaje: una vez instalado, y si se desea hilar muy fino, se podría plantear la posibilidad de montar / como read-only, hay procesos que tendrán problemas con esto (networking es uno de ellos) pero todo es solucionable.

Partición /home
* Tamaño: si el equipo va a ser utilizado como servidor no será necesario, en la mayoría de los casos, que tenga demasiada capacidad, con 500MB – 1GB será suficiente.
* Opciones de montaje: no será necesario ejecutar programas ni crear dispositivos en esta partición (noexec y nodev). Nos aseguraremos igualmente que se ignore el bit suid en esta partición para evitar inconvenientes (nosuid).

Partición /usr
* Tamaño: también depende del tipo de uso que se dará al equipo, para asegurarnos que no habrá problemas le asignaremos como mínimo 5GB.
* Opciones de montaje: no se necesitará crear dispositivos en esta partición (nodev), y tal vez no sea necesario de suid tampoco (nosuid). Una vez finalizada la instalación y configuración podríamos plantearnos el colocar la opción de montar la partición como solo lectura.

Partición /var
* Tamaño: nuevamente depende del tipo de equipo del que se trate, aquí se alojarán los archivos de log, que pueden crecer bastante. También se requerirá de suficiente espacio si se trata de un servidor Web con mysql o un servidor de correos. Recomiendo que, una vez decidido el tamaño de las demás particiones, se asigne el espacio restante a esta partición
* Opciones de montaje: no necesitaremos dispositivos en esta partición ni tampoco del bit suid (nodev y nosuid), y seguramente tampoco necesitamos ejecutar archivos (noexec), analizar este último punto para evitar comportamientos inesperados.
* Sistema de archivos: esto dependerá del tipo de servicio, es sabido que reiserfs cuenta con un mejor rendimiento que ext2/3 al trabajar con muchos archivos pequeños por lo que podría ser recomendable para esta partición si se trata de un servidor Web, servidor de correos o un caché http.

Partición /tmp
* Tamaño: No se necesita demasiado espacio para /tmp, con 500MB-1GB debiera ser suficiente.
* Opciones de montaje: no serán necesarios dispositivos, tampoco suid ni ejecución de archivos (nodev, noexec, nosuid). Sin embargo hay aplicaciones que durante la instalación desempaquetan y ejecutan archivos en /tmp por lo que tal vez queramos aplicar la opción noexec una vez terminadas las instalaciones.

Partición /boot
* Tamaño: no es necesario mucho, con 200MB será más que suficiente.
* Opciones de montaje: se recomienda no montar esta partición.

Partición swap
* Tamaño: se recomienda por lo general contar con un swap del doble del tamaño de la memoria física instalada pero sin superar el GB ya que no seria necesario, un PC de escritorio con 2GB de ram probablemente nunca utilice el swap, recuerde que el swap es algo así como una memoria extra de emergencia y es deseable que no se utilice.
Tratándose de un servidor debe tener en cuenta esto, un equipo que consuma mucha swap (digamos 1GB) estará funcionando realmente muy mal pero usted querrá asignar una buena cantidad de swap para asegurarse de no ver los desagradables mensajes que muestra por consola un equipo que ha agotado la memoria total disponible. Si llegado a ese punto, el kernel necesitara de más memoria, reaccionará iniciando lo que se conoce como OOM Killer, la función badness() decidirá cual de nuestros preciados procesos debe ser sacrificado en pos de la salud del kernel, este matará el proceso y cerrará sus archivos lo cual puede resultar desastroso, por ejemplo, para una base datos.

Por último, podría ser recomendable, si se cuenta con más de un disco, separar la partición swap y/o /var del resto del sistema.

4.3- Selección del mirror [Avanzado]
Como se mencionó anteriormente, es deseable instalar a partir de un medio óptico (CD-ROM/DVD-ROM), y a la hora de agregar los repositorios asegurarse que sean los repositorios oficiales, nunca utilizar backports y, por supuesto, recomiendo no utilizar los repositorios non-free.

4.4- Instalación de paquetes [Medio]
Durante la instalación se nos pregunta que paquetes deseamos instalar, desplegando una lista donde nos ofrece instalar un entorno de escritorio, un sistema básico, etc. Será deseable instalar cualquier paquete una vez finalizada la instalación del sistema base por lo que no seleccionaremos ningún paquete en esta instancia.

4.5- Creación de usuarios y contraseñas [Básico]
Durante la instalación se nos preguntará si deseamos habilitar acceso a root, sería deseable indicar que no, crearemos entonces un usuario no privilegiado, el cual escalará privilegios a superusuario mediante su.
La seguridad de las contraseñas es también un tema crítico, por favor, les imploro que no pongan root como contraseña de root.
A la pregunta habilitar contraseñas ocultas (shadow) contestaremos que sí. Sepa esto: si los password no se almacenan shadow cualquier usuario no privilegiado con un simple programa como “John the ripper” puede acceder al password de root en cuestión de minutos.

4.6- Password al grub [Medio]
Tal vez no desee colocar password al grub en este momento, la razón es que se almacenará en claro en el archivo /boot/grub/menu.lst, más adelante se volverá sobre este punto. Ingresemos solo enter cuando se nos solicite el password

5- Limpieza

5.1- Hardware innecesario (segunda parte) [Avanzado]
Ya hemos terminado la instalación, podríamos quitar esa lectora de CD/DVD si no la utilizaremos más.
¿Y el botón de reset? En GNU/Linux eso no se utiliza, podríamos desconectarlo.

5.2- Paquetes innecesarios [Medio]
Aún habiendo instalado solo el sistema base podremos ver que se han instalado una serie de paquetes innecesarios, lo podremos ver haciendo dpkg -l.
Vamos a valernos de aptitude para seleccionar los paquetes innecesarios que debemos desinstalar, ejecutamos la interfaz ncurses de aptitude y, en la sección “paquetes instalados” iremos recorriendo la lista y, según la descripción, seleccionando los paquetes que no utilizaremos. Estos pueden ser por ejemplo todos los referentes a ppp, si utilizaremos solo ethernet o el cliente dhcp si no lo utilizaremos. También podemos eliminar eject si no tendremos la lectora instalada y todo paquete que pensemos que no serán necesarios, es solo cuestión de aplicar el criterio. Las versiones actuales de debian no instalan sudo por defecto pero lo quitaremos, en el caso que estuviera instalado, si no lo necesitaremos.

5.3- Servicios innecesarios [Medio]
Una vez más debian ha instalado solo lo que le pedimos, es decir nada. Si hacemos netstat -tulp podremos ver que no hay servicios corriendo, tal vez nos encontremos con que estamos corriendo un MTA (exim por defecto), necesario para el correcto funcionamiento de muchos programas. Si es así, la instalación básica de etch no lo instala, simplemente nos aseguraremos que solo este a la escucha localmente (en la interfaz lo) dirá algo como localhost:smtp en la columna Local Address de la salida del comando netstat -tulp. Si no fuera así o hubiera algún otro servicio activo, lo quitaremos, ya sea desinstalando el paquete o modificando la configuración de inetd (según el caso).

6- Configuraciones

6.1- Permisos de usuarios [Medio]
Como se dijo antes, seria deseable no permitir acceso a root al sistema y crear un usuario normal que escale a súperusuario mediante el comando su, pero ¿es deseable que cualquier usuario pueda escalar a superusuario? Evidentemente no.
Editaremos el archivo /etc/pam.d/su y buscaremos las líneas que dicen

# Uncomment this to force users to be a member of group root
# before they can use `su'. You can also add "group=foo"
# to the end of this line if you want to use a group other
# than the default "root" (but this may have side effect of
# denying "root" user, unless she's a member of "foo" or explicitly
# permitted earlier by e.g. "sufficient pam_rootok.so").
# (Replaces the `SU_WHEEL_ONLY' option from login.defs)
# auth       required   pam_wheel.so

El texto en ingles es bastante claro, decomentando la linea # auth required pam_wheel.so lograremos que solo quien pertenezca al grupo root pueda escalar a superusuario con el comando su. Típicamente lo que se hace es crear un grupo de sistema, comúnmente de nombre wheel, para permitir solo a los integrantes de ese grupo poder utilizar su, se hace del siguiente modo: ejecutamos

# addgroup --system wheel


y luego en /etc/pam.d/su dejamos la linea del siguiente modo:

auth       required   pam_wheel.so group=wheel


Luego agreguemos al grupo wheel a los usuarios que deseamos que escalen a superusuario con su.

6.2- Restringir el acceso a root [Medio]
Durante la instalación se me preguntó si quería permitir acceso a root, estábamos de acuerdo en que lo mejor era decir que no, desgraciadamente mi cerebro bifocal me hizo decir SI cuando quería decir NO. Para revertir eso basta con editar el archivo /etc/securetty y borrar (o comentar) todas sus lineas.
Si deseamos que root pueda aún loguearse en alguna tty en especial la dejaremos sin borrar.
NOTA: debemos borrar el contenido del archivo, no el archivo. Si /etc/securetty no existe se saltará ese control y, como consecuencia, root podrá loguearse desde cualquier terminal.

6.3- Interprete de comandos de los usuarios [Medio]
Si miramos en /etc/passwd podremos ver algo como

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
administrador:x:1000:1000:administrador,,,:/home/administrador:/bin/bash


Vemos todos esos usuarios de sistema, en debian se caracterizan por tener un UID menor que 1000, que tienen como interprete de comandos a /bin/sh, eso está mal, esos usuarios no deberían poder ejecutar ordenes de consola. Si bien esos usuarios no pueden hacer login, ya que en /etc/shadow hay un * donde debería estar el hash de su password, les quitaremos el shell para estar seguros ya que no lo necesitan, para eso utilizaremos la utilidad chsh (change shell)

chsh -s /bin/false daemon
chsh -s /bin/false bin
...
chsh -s /bin/false nobody


Y quedará algo como

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/false
bin:x:2:2:bin:/bin:/bin/false
sys:x:3:3:sys:/dev:/bin/false
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/false
man:x:6:12:man:/var/cache/man:/bin/false
lp:x:7:7:lp:/var/spool/lpd:/bin/false
mail:x:8:8:mail:/var/mail:/bin/false
news:x:9:9:news:/var/spool/news:/bin/false
uucp:x:10:10:uucp:/var/spool/uucp:/bin/false
proxy:x:13:13:proxy:/bin:/bin/false
www-data:x:33:33:www-data:/var/www:/bin/false
backup:x:34:34:backup:/var/backups:/bin/false
list:x:38:38:Mailing List Manager:/var/list:/bin/false
irc:x:39:39:ircd:/var/run/ircd:/bin/false
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/bin/false
administrador:x:1000:1000:administrador,,,:/home/administrador:/bin/bash

6.4- Cargador de arranque [Medio]
Si estamos utilizando grub podríamos querer asegurarnos que nadie pueda modificar los parámetros que se envía al kernel durante el arranque, a eso lo lograremos colocando un password al grub.
A esto lo haremos editando el archivo /boot/grub/menu.lst, los pasos son os siguientes:
Si instalamos el sistema separando la partición /boot del resto del sistema e hicimos caso a la recomendación del paso 4.2 para la partición /boot entonces deberemos montar la partición /boot, será algo como:

# mount -t ext3 /dev/hda1 /boot


La contraseña no se almacenará en el sistema, en su lugar se guardará un hash de esta, calculado mediante md5.
Para eso utilizaremos grub-md5-crypt que viene con el paquete grub:

$ grub-md5-crypt
Password:
Retype password:
$1$XPXwl$59U9fEc5VgKjVzN.cinQ31


Editemos ahora el archivo /boot/grub/menu.lst, utilizaremos vim o nano, los únicos editores disponibles si se ha instalado un sistema base, y busquemos donde dice

## password ['--md5'] passwd
# If used in the first section of a menu file, disable all interactive editing
# control (menu entry editor and command-line)  and entries protected by the
# command 'lock'
# e.g. password topsecret
#      password --md5 $1$gLhU0/$aW78kHK1QfV3P2b2znUoe/
# password topsecret


Debajo de esto agregaremos la siguiente linea con el hash que hemos generado nosotros

password --md5 $1$XPXwl$59U9fEc5VgKjVzN.cinQ31

Busquemos ahora la línea que dice lockalternative y dejémosla así:

## should update-grub lock alternative automagic boot options
## e.g. lockalternative=true
## lockalternative=false
# lockalternative=true


De este modo lograremos que el grub pida la contraseña también cuando se intente seleccionar del menú la opción de arrancar como single-user.
IMPORTANTE: No debe descomentar la línea lockalternative, solo debe reemplazar false por true. Sepa también que esto solo logra que no se pueda seleccionar la opción single-user pero si cuenta con más de un kernel esta opción no impide que se seleccione el arrancar con otro kernel en modo normal.

También modificaremos los permisos de /boot/grub/menu.lst para evitar que los usuarios no privilegiados accedan al hash:

# chmod 600 /boot/grub/menu.lst

Hagamos ahora un update-grub necesario para que tome la nueva configuración del lockalternative.

# update-grub
Searching for GRUB installation directory ... found: /boot/grub .
Testing for an existing GRUB menu.list file... found: /boot/grub/menu.lst .
Found kernel: /boot/vmlinuz-2.6.18-6-686
Updating /boot/grub/menu.lst ... done

6.5- Asegurarnos contra ataques “fork” [Medio].
Por defecto, Debian no limita los procesos del sistema, algo que puede provocar un cuelgue del sistema con una bomba fork (bucle infinito).
Para solucionar esto hay que hacer una limitación del número de procesos del sistema agregando una línea como ésta en el archivo /etc/security/limits.conf :
* hard nproc (número de procesos que deseamos poner como máximo, por ej 500).

6.6- Deshabilitando el Ctl+Alt+Supr [Medio]
Esta funcionalidad puede resultar cómoda a veces pero que cualquiera con acceso a la consola del equipo pueda utilizarla difícilmente sea lo mejor.
Abramos el archivo /etc/inittab y busquemos donde dice:

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now


Ahora hay algunas alternativas a gusto del consumidor. Pero primero entendamos la línea:
ca es el id, donde dice 12345 se refiere a los runlevels en los cuales, tras el evento ctrlaltdel se llevará a cabo la acción /sbin/shutdown -t1 -a -r now.
Entonces las alternativas son:

  • Podemos comentar la línea para que no se realice ninguna acción tras presionar Ctl+Alt+Supr.
  • Podemos dejar solo el numero 1 en la columna de runlevels para que la característica se mantenga si hemos ingresado en modo single user.
  • Podemos quitar el 2 de la columna runlevels para que la característica se mantenga en los demás runlevels pero no en el runlevel por defecto.
  • Podemos leer el man de shutdown y sorprendernos al saber que la opción -a significa que si existe el archivo /etc/shutdown.allow la orden shutdown solo se respetará si root a algún usuario listado en dicho archivo está logueado en alguna tty.

Esa última opción es la que más me gusta, dejaremos /etc/inittab como está y haremos:
# echo root > /etc/shutdown.allow
De este modo si se presiona Ctl+Alt+Supr y no está root logueado en ninguna tty se mostrará el mensaje:
shutdown: no authorized users logged in
y el reinicio no tendrá lugar.
Si hemos modificado algo en /etc/inittab avisomeslé a init que debe volver a leer su archivo de configuración.
# init q

6.7- Tareas programadas [Medio]
Las tareas programadas son aquellas que se llevarán a acabo a través del demonio cron. Cualquier usuario puede ejecutar la utilidad crontab y programar alguna tarea, la cual será ejecutada con los privilegios de ese usuario. De todos modos, restrinjamos eso, solo root podrá utilizar crontab. Para eso crearemos el archivo /etc/crontab.allow y lo dejaremos vacío.
Aplicaremos la misma restricción a at, creando vacío el archivo /etc/at.allow.

6.8- Ajuste de algunos parámetros del kernel [Medio]
Editemos el archivo /etc/sysctl.conf y hagamos las siguientes modificaciones:

# Podemos descomentar esta línea si deseamos evitar que klogd envíe los
# mensajes a consola, esto logrará que no aparezca en pantalla algo
# trivial como cuando se conecta un cable de red pero omitirá información
# importante como por ejemplo un Out_Of_Memory
#kernel.printk = 4 4 1 7
#
# Ignorar la tecla petición de sistema, esto nos impedirá hacer un cierre
# limpio del sistema en caso de cuelgue
#kernel.sysrq=0
#
# Protección básica contra ataques de Spoof, a un paquete se lo aceptará solo si
# la dirección IP de origen es alcanzable desde la interfaz por la cual ingresó.
net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
#
# Ignorar ICMP broadcasts
net.ipv4.icmp_echo_ignore_broadcasts = 1
#
# Ignorar ICMP que informan errores en paquetes que nosotros no hemos transmitido.
net.ipv4.icmp_ignore_bogus_error_responses = 1
#
# No aceptar redirección de ICMPs
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
#
# Ni tampoco enviarlos
net.ipv4.conf.all.send_redirects = 0
# No aceptar información de source route (no somos un router)
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
#
# Un paquete marciano es justamente eso, un paquete que parece venido de otro mundo, por
# ejemplo: si mi interfaz de red esta configurada con una IP 200.100.53.9/255.255.255.224
# ¿Como carajos me ha llegado un paquete cuya trama ethernet tiene mi dirección MAC
# pero la IP de destino es 10.0.0.5? Bueno, no tengo la menor idea, eso es un marciano.
# Loguear paquetes marcianos puede ser deseable
net.ipv4.conf.all.log_martians = 1

Para lograr que el kernel tome la nueva configuración:
# sysctl -p

6.9- Cerrar la sesión de root por inactividad [Básico]
Puede suceder que luego de loguemaos como root olvidamos cerrar la sesión sin darnos cuenta dejando la puerta abierta a nustro sistema. Para evitar esto agreguemos la siguiente línea en el .bashrc de root o directamente en /etc/profile para lograr que se aplique a todos los usuarios
readonly TMOUT=300
De este modo la sesión en una tty se cerrará tras 5 minutos de inactividad.

6.10- Almacenar logs remotamente [Critico]
Los archivos de log son sin duda la herramienta mas importante para detectar intentos de intrusión y realizar un análisis del mismo, desgraciadamente si la intrusión paso de ser un intento a un hecho dependeremos de la inoperancia del atacante para poder reunir información importante a través de los logs. Lo primero que hará un atacante medianamente capacitado será intentar borrar todo rastro de su paso por nuestro sistema, una vez adentro su prioridad será manipular los archivos de log.
Para que, tras una auditoria, la información almacenada en los archivos de log pueda ser utilizada como prueba en un proceso judicial no debe existir duda alguna de la integridad de dichos archivos, suele ser un requerimiento legal que, entre otras cosas, el almacenamiento se realice en un equipo remoto.
Syslogd nos permite almacenar los logs en otro equipo, el funcionamiento es sumamente simple pero no por eso menos efectivo.
Básicamente el funcionamiento es el siguiente:

  • Se configura un equipo como servidor de logs poniendo al demonio syslogd a la escucha en el puerto UDP 514.
  • Se configura el equipo cliente para que almacene los logs en el servidor remoto.
  • El equipo cliente emitirá entonces segmentos udp, uno por cada registro, hacia el equipo servidor, la información viaja en texto plano.
  • El equipo cliente puede además almacenar los logs localmente.
  • El equipo cliente no mantiene ninguna conexión persistente con el servidor y no tiene ningún tipo de control sobre éste, lo único que sabe de él es su nombre.
  • Debido a que la transmisión se realiza sobre udp, el cliente no será siquiera capás determinar a ciencia cierta si el servidor está realmente recibiendo los mensajes, el aislamiento es casi total.
  • En caso de intrusión el atacante podría lograr detener la transmisión de registros pero nunca manipular los registros que ya se han emitido.
  • El servidor debe ser un bastión, solo debe estar corriendo el demonio syslogd y todos sus puertos exceptuando el de syslogd deben estar bloqueados. No debe tampoco ser accesible por consola remota, lo ideal es un equipo aislado, tolerante a fallos, solo accesible por consola y con un monitor que muestre los registros que está almacenando.

La configuración es sumamente simple:
En el servidor:
Editar el archivo /etc/default/syslogd

# Full documentation of possible arguments are found in the manpage
# syslogd(8).
# For remote UDP logging use SYSLOGD="-r"
SYSLOGD="-r"


y reiniciar el demonio sysklogd:

# /etc/init.d/sysklogd restart

Haciendo un netstat -ntulp podemos ver que el demonio se ha puesto a la escucha en el puerto udp 514

En el cliente:
Si ya ha leído detenidamente man syslog.conf y entiende su funcionamiento puede editar a gusto /etc/syslog.conf pero básicamente, si desea que todos los registros de log se envíen a un equipo remoto será suficiente con agregar:

*.*    @equipo.servidor.logs

Donde el equipo cliente debe resolver correctamente equipo.servidor.logs a la ip del servidor, esto se logra con una simple modificación en el /etc/hosts del equipo cliente.
Reiniciemos el demonio syslogd en el cliente y ya deberíamos estar recibiendo correctamente los logs en el servidor. Si desea que el cliente genere logs también durante el arranque, en la etapa de boot, modifique /etc/default/boologd y establezca el valor BOOTLOGD_ENABLE=yes

Seria muy buena idea que modificara en el servidor los scripts encargados de hacer la rotación para que almacene los logs por al menos 1 año. Puede también modificar los scripts para que se calcule y almacene un hash de los archivos de log cada vez que se van a rotar para así poder verificar su integridad.

7- El sistema de privilegios.

Todos conocemos a root, al menos hemos oído hablar de él, el “Súperusuario” del sistema, capaz de hacer cosas que nadie más puede hacer. Es bien sabido que solo root puede montar dispositivos, o cargar módulos en el kernel, incluso necesitamos de su permiso para apagar el equipo, pero ¿por qué?, ¿quién controla eso?, ¿quién decide que solo el usuario root puede ejecutar estas tareas?
Bien, a ese control lo hace el kernel, es el kernel quien realmente manda y quien ha delegado esas importantes tareas a aquel usuario que pueda demostrarle que su UID es igual a cero. Bueno, parece que root no era tan Súper como nosotros pensábamos. Esta sección explicará un poco el sistema de privilegios de Linux y los riesgos que implica su mal uso.

7.1- El peligroso bit SUID [Avanzado].
Antes se mencionó que solo root podía montar dispositivos, sin embargo sabemos que un usuario no privilegiado podrá montar un dispositivo si en el archivo /etc/fstab esta indicado explícitamente que puede hacerlo. El bit SUID (Set User ID) es la solución que desde hace años utiliza Unix para resolver el problema que se presenta cuando un usuario sin privilegios debe llevar a cabo tareas que solo root puede realizar.
Cuando un usuario ejecute un archivo el kernel observará sus permisos y si el bit SUID está activo ejecutará el archivo como si lo hubiera ejecutado el dueño del archivo. Atención aquí, no dije “como si el archivo fuera propiedad de quien lo ejecutó”, noten la diferencia. Tampoco dije “Como si el usuario que lo ejecutó fue root”, esto siempre trae confusión por lo que seré bien explicito:
Lo anterior significa que si al archivo ejecutable x, que es propiedad de pepe y tiene el bit SUID activo lo ejecuta paco, la ejecución se llevará a cabo con todos los privilegios Y LIMITACIONES de pepe.
El bit SGID es análogo al SUID pero para los permisos de grupo.
Entonces un usuario normal podrá montar un dispositivo ya que la aplicación que hay que ejecutar para hacerlo, mount, es propiedad de root y tiene su bit SUID activo.

Pero siendo así es ahora la propia aplicación mount y no el kernel quien debe controlar que el usuario tenga permisos de hacer lo que intenta hacer. Evidentemente un archivo ejecutable, propiedad de root y con el bit SUID activo es un riesgo potencial a la seguridad por lo que trataremos de limitarlos todo lo posible.
Bien, busquemos esos archivos:

# find / -path /proc -prune -o -type f -perm +4000 -ls

Y nos podremos encontrar con los siguientes archivos cuyo bit SUID está activo (se leerá algo como rwsr-xr-x en la columna de permisos)

  • /usr/bin/passwd: para que los usuarios puedan cambiar su password. Debe analizar si quitar el bit SUID a este programa, hacerlo seria algo paranoico, /usr/bin/passwd siempre funcionó bien en SUID.
  • /usr/bin/chsh: para que los usuarios puedan cambiar su shell por defecto. Si fuera necesario podríamos cambiar el shell de los usuarios como root directamente, quitaremos el bit SUID a este programa.
  • /usr/bin/newgrp y /usr/bin/gpasswd: cambiar de grupo y cambiar el password a un grupo, es una funcionalidad poco conocida de Linux, se comporta analogo a lo que son passwd y su pero a nivel de grupos. gpasswd permite asignar password a los grupos para que, mediante newgrp, un usuario pueda cambiar su identificador de grupo, previa autenticación. Si lo cree conveniente puede quitar el bit SUID a estos programas.
  • /usr/bin/gpg: si estás en etch este programa aparecerá como SUID, esto es un bug solucionado en la versión 1.4.6-2.2 del paquete gnupg, quitemos el bit SUID a este programa.
  • /usr/sbin/exim4: en mi caso no está instalado pero podria estarlo. Cualquier aplicación que quiera ponerse a la escucha en un puerto bajo (menor al 1024) debe correr con privilegios de root. Una aplicación podría luego degradar sus privilegios, lamentablemente exim no lo hace. Tal vez sea recomendable quitar exim.
  • /bin/su: para poder escalar/degradar privilegios. Seguramente no desee quitar el bit SUID a este comando.
  • /bin/mount y /bin/umount: para poder montar y desmontar dispositivos como usuario no privilegiado. Eliminemos esta característica quitando el bit SUID a mount y umount.
  • /bin/ping, /bin/ping6 y /bin/traceroute.lbl: para poder enviar un ping a la red es necesario saltarse la capa TCP e interactuar directamente sobre IP, eso requiere RAW SOCKETS y solo root puede hacerlo, para que un usuario no privilegiado pueda realizar pings es necesario que el programa sea SUID. Traceroute se basa en ping y su ttl para trabajar y por eso es también SUID. Quitemos el bit SUID a estos programas, más adelante veremos que mediante el uso de las capabilities es posible lograr que estos programas funcionen si ser SUID.

Quitemos esos permisos entonces, para hacerlo basta con ejecutar
# chmod -s archivo_ejecutable

7.2- Cambiar el nombre a root [Básico].
Ciertamente cualquiera que intente ingresar a un sistema intentará hacerlo como root, agreguemos un poco de oscuridad, cambiemos el nombre de root a uno más personal:
# usermod -l todopoderoso root

7.3- Las POSIX Capabilities [Crítico]
Ya se mencionó antes, quien manda aquí no es root sino el kernel y es el kernel quien le da a root esas capacidades. Seguramente ha oído hablar de las capabilities que posee root y de como puede ir renunciando a ellas progresivamente, también sabrá que, una vez renunciada un capability, ya no le es posible a root recuperarla sin reiniciar el sistema. El articulo [http://www.esdebian.org/articulos/24052/asegurando-linux-las-linux-capabilities] detalla esa característica de las capabilities. En esta sección se mencionará la implementación de las POSIX Capabilities en el núcleo Linux y su aplicación granular.
Breve introducción a las POSIX capabilities: en kernel anteriores al 2.6.24 el concepto de capabilities estaba limitado a marcar el máximo de capacidades que “alguien” podía tener. El valor de /proc/sys/kernel/cap-bound actuaba como máscara, entonces mediante la herramienta lcap lo que se hacía en realidad no era quitar capacidades a root sino bajar el umbral máximo. Haciendo por ejemplo lcap 5 lo que hacia no era quitar a root la capacidad CAP_KILL sino decirle al kernel que nadie tiene esa capacidad.
A partir del kernel 2.6.24 se implementa casi por completo las capabilities según el documento POSIX 1003.1e. A partir de entonces las posibilidades se extienden como nunca antes, la implementación de las POSIX capabilities nos permiten al fin librarnos de lo que algunos desarrolladores de UNIX consideraron como el mayor error de diseño que han cometido jamás: el bit SUID.
Mediante el paquete libcap2 y libcap2-bin nos proveen las herramientas necesarias para asignar capabilities a procesos y archivos ejecutables.

Deshaciéndonos del bit SUID de una buena vez.
Empecemos por uno fácil, el ping:

# ls -l /bin/ping
-rwsr-xr-x 1 root root 30788 dic 10  2007 /bin/ping
# chmod u-s /bin/ping
# exit
exit
$ ping www.esdebian.org
ping:
 icmp open socket: Operation not permitted
$ su
Contraseña:
# setcap cap_net_raw=ep /bin/ping
# getcap /bin/ping
/bin/ping = cap_net_raw+ep
# exit
exit
$ ls -l /bin/ping
-rwxr-xr-x 1 root root 30788 dic 10  2007 /bin/ping
$ ping www.esdebian.org
PING
 www.esdebian.org (72.232.176.204) 56(84) bytes of data.
^C
--- www.esdebian.org ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 5014ms
$

Perfecto, librémonos ahora del bit SUID en el comando su:

# ls -l /bin/su
-rwsr-xr-x 1 root root 27108 sep 14 17:51 /bin/su
# chmod u-s /bin/su
# exit
exit
su
Contraseña:
su: Fallo de autenticación
$

Ahora tendrán que irse a una tty y loguearse como root, ya no es posible escalar privilegios con su:

# setcap cap_setuid,cap_setgid,cap_dac_read_search=ep /bin/su

Deben agregar todas las capacidades de una sola vez, no son acumulativas. Bueno, ahora sí:

$ ls -l /bin/su
-rwxr-xr-x 1 root root 27108 sep 14 17:51 /bin/su
$ su
Contraseña:
/#

En general las capacidades que los archivos necesitarán son:

ping - CAP_NET_RAW (13)
traceroute - CAP_NET_RAW (13)
chsh - CAP_CHOWN (0), CAP_DAC_READ_SEARCH (2), CAP_FSETID (4), CAP_SETUID (7)
chfn - CAP_CHOWN (0), CAP_DAC_READ_SEARCH (2), CAP_FSETID (4), CAP_SETUID (7)
chage - CAP_DAC_READ_SEARCH (2)
passwd - CAP_CHOWN (0), CAP_DAC_OVERRIDE (1), CAP_FOWNER (3)
su - CAP_SETUID (7), CAP_SETGID (6), CAP_DAC_READ_SEARCH (2)
unix_chkpwd - CAP_DAC_OVERRIDE (1)
mount - CAP_DAC_OVERRIDE (1), CAP_SYS_ADMIN (21)
umount - CAP_DAC_OVERRIDE (1), CAP_SYS_ADMIN (21)

Algo importante a tener en cuenta sobre las POSIX capabilities:
Usted debe ser conciente que se trata de una tecnología en desarrollo, la implementación se introdujo recientemente para kernels 2.6.24, hubo importantes modificaciónes en 2.6.25 y la versión actual en testing es 2.6.26. Es evidente que la implementación puede contener fallos cuya explotación podria resultar en una escalada total de privilegios a un tercero no autorizado. El siguiente caso servirá de ejemplo: existe un riesgo al ejecutar un binario no SUID/SGID que viene dado por LD_PRELOAD.

La ejecución de un binario SUID/SGID ignorará siempre la precarga dinamica de librerias ya que permitirla significaria que la ejecucion del código contenido en dichas librerias se realizaría con los privilegios del binario SUID/SGID, llegado el caso se podria estar ejecutando código no fiable con los privilegios de un binario SUID 0.

Sin embargo, si se asigna capacidades a un binario no SUID tal restricción no se aplica y el binario heredará sus capacidades agregadas al código cargado mediante la interfaz LD_PRELOAD, las capacidades correctas, la librería adecuada y hemos logrado una escalada total de privilegios.

Para subsanar esto se implementó en su momento el hack LIBC_ENABLE_SECURE_HACK cuya función es hacer creer a libc que el binario con capacidades añadidas es SGID para de ese modo impedir LD_PRELOAD, este bug ya se encuentra resuelto en las actuales glibc pero los que hay por venir podrian ser tan críticos como este. (aporte de Javier Martínez)

8- Asegurando servicios

8.1- Jaulas chroot como mecanismo de seguridad [Avanzado].
Dícese de aquel estúpido que creó una jaula chroot para asegurar un servicio y lo inició como root. La frase tal vez suene un poco fuerte pero sinceramente no cabe otro calificativo.
Chroot NO fue pensado como mecanismo de seguridad, se lo puede utilizar como tal pero si se lo hace a conciencia, una mala utilización resultará contraproducente por una sencilla razón: salir de una jaula chroot es teóricamente imposible para un usuario normal, de hecho también le es imposible entrar, solo root puede hacer la llamada a chroot(). Sin embargo a root le es tan trivial salir de la jaula como lo fue entrar. Hay programas preparados para correr en un entorno chroot pero otros no y es ahí cuando se comenten los errores, como solo root puede crear la jaula es común que al hacer la llamada a chroot se ejecute el servicio que se está intentando asegurar también como root. Dentro o fuera de la jaula root sigue siendo root y tiene poder absoluto.
Las recomendaciones son las siguientes:

  • Nunca inicie nada dentro del chroot con privilegios de súperusuario: una vez dentro del chroot lo primero que debe hacer su programa o script de inicialización es degradar sus privilegios.
  • No monte nunca /proc dentro del chroot: esto no es necesario y resulta en un gran hueco de seguridad.
  • Copie dentro del chroot solo los archivos necesarios, válgase de ldd para detectar las dependencias.
  • No copie dentro del chroot ningún archivo SUID, si quiere copiar /bin/su y utilizarlo para la degradación de privilegios quite el bit SUID.
  • Llévese dentro del chroot solo los descriptores de archivo que sean estrictamente necesarios.
  • Nunca se lleve el descriptor de un directorio.
  • Cree enlaces duros dentro del chroot solo si fuera absolutamente necesario.
  • Si se deben crear dispositivos dentro del chroot hágalo antes, no desde el script de inicialización del chroot.

Solo a modo de ejemplo, y para que tome en serio la primer recomendación, lo invito a que monte un entorno chroot y una vez dentro corra como root el siguiente script en perl.

#!/usr/bin/perl -w
use strict;
chdir "/";
opendir JAULA, "." or die "ERROR: no se pudo obtener el descriptor del directorio\n";
mkdir "temp";
chdir "temp";
chroot ".";
chdir(*JAULA);
chdir "../../../../../../../../../../../../../../../../../../";
chroot ".";
system("/bin/bash");

8.2- Administración mediante consola remota – openssh-server [Medio]
Aseguremos un poco este servicio de uso tan común.
Editemos el archivo /etc/ssh/sshd_config y modifiquemos ciertos aspectos de la configuración.
Un poco de oscuridad, cambiemos el puerto de escucha por uno alto:
Port 4587

Asegurémonos de estar utilizando la versión 2 de ssh:
Protocol 2

Pongamos el servicio a la escucha solo en la interfaz que nos interesa (si tuviéramos más de una):
ListenAddress 192.168.1.1

No permitamos ingresar como root:
PermitRootLogin no

Forcemos la utilización de claves asimétricas para la autenticación, (aquí una breve explicación de como realizarla):
PasswordAutentication no

Editemos /etc/hosts.deny y pongamos:

sshd : ALL

y en /etc/hosts.allow las direcciones IPs de las cuales queremos poder conectarnos:

sshd : 192.168.1.0/24

Y finalmente reiniciemos el servicio:
# /etc/init.d/sshd restart

8.3- Firewall de host – protegiéndonos de la red y evitando ataques de diccionario [Medio]
Por defecto nuestro equipo aceptará entrar y salir todo tráfico de red, limitemos eso con iptables. Crearemos el archivo /etc/init.d/firewall.sh, el contenido variará según de que tipo de equipo se trate.
Suponga que tiene un equipo de sobremesa que solo debe poder navegar por internet, entonces querrá permitir salida de conexiones y rechazar todo intento de conexión entrante.
Si se trata por ejemplo de un servidor web debe permitir entrar conexiones al puerto 80, si además lo quiere administrar remotamente por ssh deberá aceptar conexiones en el puerto que haya designado para eso, supongamos el del ejemplo anterior, el puerto es 4587.
El contenido de /etc/init.d/firewall.sh podría ser el siguiente:


#!/bin/sh
# Cargo los módulos necesarios
modprobe ip_conntrack
modprobe iptable_nat
modprobe ip_conntrack_ftp
#
# Establezco una política por defecto DROP para el tráfico entrante.
/sbin/iptables -P INPUT DROP
# Permito todo tráfico saliente, si se desea se puede limitar eso
/sbin/iptables -P OUTPUT ACCEPT
#
# Permitamos conexiones establecidas y relacionadas y tráfico local
/sbin/iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A INPUT -i lo -j ACCEPT
#
# Si se trata de un servidor web debemos aceptar conexiones en el puerto 80
/sbin/iptables -A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT
#
# Si queremos permitir acceso remoto por ssh, permitiremos conexión en el puerto
# que hemos decidido utilizar para tal fin, en nuestro ejemplo el 4587
# Lo limitaremos a un máximo de 3 conexiones por minuto para combatir ataques de diccionario.
# Podríamos antes loguear la conexión, se creará un registro en /var/log/messages
/sbin/iptables -A INPUT -p tcp --dport 4587 -m state --state NEW -j LOG --log-prefix "Conexión ssh: "
/sbin/iptables -A INPUT -p tcp --dport 4587 -m limit --limit 3/minute -m state --state NEW -j ACCEPT

Solo resta hacer ejecutable el archivo y correrlo, deberemos también crear los enlaces en los runlevels para que se ejecute automáticamente en el arranque.


# chmod 744 /etc/init.d/firewall.sh
# /etc/init.d/firewall.sh
# update-rc.d firewall.sh defaults

Si es muy paranóico, o simplemente quiere probar, puede agregar la siguiente regla antes a la que realiza el ACCEPT de la conexión ssh:
/sbin/iptables -A INPUT -p tcp --dport 4587 -m limit --limit 1/minute -m state --state NEW -j DROP
Esta curiosa regla logrará que el primer intento de conexion sea rechazado, luego del primer intento se aceptarán nuevas conexiones por plazo de un minuto, vencido el mismo se rechazará nuevamente el primer intento de conexión. Esta regla es efectiva para cualquier intento de escaneo de puertos, a ojos del scanner el puerto 4587 estará bloqueado.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s