Otra protección más con iptables y módulo recent

Al hilo de esta entrada, si lo que queremos es controlar, incluso, un posible escaneo de puertos desde una IP, y no solo peticiones abusivas a uno de nuestros servicios que es de lo que trataba la entrada anterior, tenemos:

iptables -I INPUT  --m state --state NEW -m recent  --set
iptables -I INPUT  --m state --state NEW -m recent  --update --seconds 60 --hitcount 5 -j DROP

Con la ejecución de estas 2 órdenes, cualquier intento de realizar más de 5 conexiones (destinados a cualquiera de nuestros puertos) desde una misma IP, producirá un bloqueo de las conexiones desde esta IP durante 60 segundos.

Este es un mecanismo fácil, rápido y eficiente de control de las peticiones que recibimos en nuestros servidores y más ligero que opciones como la comentada aquí, ya que detectamos y protegemos con el módulo recent de iptables, en un nivel más bajo y que apenas introduce carga al sistema.

Como ya comenté, lo podemos hacer también en routers, solo que afecta a otras tablas/cadenas (filter/FORWARD, nat/PREROUTING,…) y opciones a considerar.

¡Espero que os sea útil!

 Referencias

  1. man iptables

Port Knocking con iptables

Existe software desarrollado, como knockd, que nos permite utilizar una técnica de protección muy interesante: Port Knocking La idea es que, cuando se da una secuencia concreta de conexiones a determinados puertos, se habilita otro, que es nuestro objetivo final. Por ejemplo, tenemos deshabilitado el acceso al servidor SSH y, tras recibir una secuencia de conexión a los puertos 2000, 2002 y 50005, se activa la conexión, para esa IP de origen, al puerto 22 del SSH. Es una técnica más de las utilizadas para la fortificación de SSH (no es la panacea, ya que se puede descubrir la secuencia fácilmente, pero ya se sabe que cuanto más azúcar, más dulce).

Esta función se puede desarrollar  de manera muy sencilla con iptables y el módulo recent (que gestiona listas dinámicas de IPs  y que ya utilizamos para controlar el número de conexiones entrantes desde una misma IP en esta entrada). La siguiente lista de órdenes habilitaría el acceso al servicio SSH para la IP de origen desde la que se intente la conexión (en la secuencia correcta) a los puertos 2000 y 3000:

/sbin/iptables -N CADENA_PASO2
/sbin/iptables -A CADENA_PASO2 -m recent --name PASO1 --remove
/sbin/iptables -A CADENA_PASO2 -m recent --name PASO2 --set
/sbin/iptables -A CADENA_PASO2 -j LOG --log-prefix "ENTRANDO EN PASO 2: "
/sbin/iptables -I INPUT -m recent --update --name PASO1
/sbin/iptables -I INPUT -p tcp --dport 2000 -m recent --set --name PASO1
/sbin/iptables -I INPUT -p tcp --dport 3000 -m recent --rcheck --name PASO1 -j CADENA_PASO2
/sbin/iptables -I INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name PASO2 -j ACCEPT

Con estas reglas, debemos activar la política por defecto a DROP, para la cadena INPUT; también necesitamos una regla ACCEPT, para el puerto de origen 22 para cualquier destino en la cadena OUTPUT.

Para conectarnos, podemos ejecutar uno de los siguientes bloques de órdenes:

nmap -sn -PS2000 --host_timeout 200 --max-retries 0 servidor
nmap -sn -PS3000 --host_timeout 200 --max-retries 0 servidor
ssh [email protected] # Ahora está permitido 
telnet servidor 2000
telnet servidor 3000
ssh [email protected] # Ahora está permitido 

Con la segunda opción, los telnets estarán esperando a que salte el timeout y con 5″ de ventana de tiempo…

En cuanto a la primera:

  • “-sn”: No port scan
  • “-PS4000”: TCP SYN al puerto 4000
  • “–max-retries 0”: que no intente ningún reenvío
  • “–host-timeout 200”: que espere 200ms

Si queremos emular al conocido personaje Seldon Cooper,  y sus 3 “toques” cada vez que llama a una puerta, solo debemos añadir un puerto y su correspondiente fase más. Así, por ejemplo, para que la secuencia de activación de SSH sea: 4000, 2000, 3000, deberíamos configurar las iptables de la siguiente manera:

/sbin/iptables -N CADENA_PASO2
/sbin/iptables -A CADENA_PASO2 -m recent --name PASO1 --remove
/sbin/iptables -A CADENA_PASO2 -m recent --name PASO2 --set
/sbin/iptables -A CADENA_PASO2 -j LOG --log-prefix "ENTRANDO EN PASO 2: "
/sbin/iptables -N CADENA_PASO3
/sbin/iptables -A CADENA_PASO3 -m recent --name PASO2 --remove
/sbin/iptables -A CADENA_PASO3 -m recent --name PASO3 --set
/sbin/iptables -A CADENA_PASO3 -j LOG --log-prefix "ENTRANDO EN PASO 3: "
/sbin/iptables -I INPUT -m recent --update --name PASO1
/sbin/iptables -I INPUT -p tcp --dport 4000 -m recent --set --name PASO1
/sbin/iptables -I INPUT -p tcp --dport 2000 -m recent --rcheck --name PASO1 -j CADENA_PASO2
/sbin/iptables -I INPUT -p tcp --dport 3000 -m recent --rcheck --name PASO2 -j CADENA_PASO3
/sbin/iptables -I INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name PASO3 -j ACCEPT

Estas líneas que implementan la funcionalidad port knocking se deben añadir a los filtros que tengamos en nuestro servidor (o router, pero en este caso las reglas anteriores deben ir a la cadena FORWARD) y debemos tener en cuenta que:

  1. Las comunicaciones para SSH (o el servicio que sea) deben estar INHABILITADAS.  Con, por ejemplo, /sbin/iptables -P INPUT DROP lo logramos. La activación se hace con las órdenes del port knocking. Si no queremos ser tan drásticos: /sbin/iptables -A INPUT -p tcp –dport 22 -j DROP
  2. Debemos tener una regla que habilite las conexiones establecidas. Si no, nuestra sesión durará 5″ 🙁 Por ejemplo, una podría ser: /sbin/iptables -A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

¡Espero que os sea útil!

 Referencias

  1. man iptables
  2. Guía avanzada de nmap elaborada en conjunto por CSIRT-CV y el Centro Criptológico Nacional (CCN)

Más sobre fortificación de SSH

En cuanto ponemos un servicio SSH accesible desde cualquier parte de Internet, los ataques de fuerza bruta y demás se suceden casi al instante (es una licencia, evidentemente, hay un tiempo de “descubrimiento”). Nos llegan desde todo el globo terráqueo por lo que, hablando de protección y suponiendo que nunca accederá un usuario desde determinados continentes o países, aplicar la Geolocalización IP para deshabilitar conexiones se convierte en una opción muy interesante. Aún reconociendo la importancia de realizar buenos filtros y de implementar mecanismos de autenticación multifactor, en esta entrada nos vamos a centrar solo en las opciones de SSH básicas para su protección. He tomado como base, la clase que impartía en Administración de Servicios de Internet dedicada a SSH y su fortalecimiento.

Las opciones con las que vamos a intentar mejorar y adaptar la configuración de nuestro servicio a nuestra política de seguridad y a nuestras necesidades, las encontraremos en el fichero /etc/ssh/sshd_config.

Empecemos….

Leer más


Fortificando el acceso con SSH: 2FA con Google Authenticator

Como comentaba al final de la entrada anterior, quien disponga de un hosting propio al que se conecte con sesiones de trabajo también debería estar interesado en fortificar este acceso utilizando un mecanismo 2FA en el servicio SSHGoogle Authenticator es una buena opción, entre otros argumentos, nos centraliza en la misma herramienta el acceso a múltiples servicios: los de Google, Redes Sociales,…

Para el caso que nos ocupa, debemos, para CentOS:

  • Instalar en el servidor el software necesario para la autenticación.
yum install pam-devel make gcc-c++ wget 
wget http://google-authenticator.googlecode.com/files/libpam-google-authenticator-1.0-source.tar.bz2
tar xvf libpam-google-authenticator-1.0-source.tar.bz2 && cd libpam-google-authenticator-1.0
make
sudo make install
  • Este sistema está basado en el tiempo y, por tanto, debemos asegurarnos que la fecha y hora de nuestros sistemas estén sincronizadas. Es un paso MUY IMPORTANTE y, si no lo hacemos, NO FUNCIONARÁ. Para ello, debemos instalar el servidor ntp y configurarlo para que se sincronice con algún servicio accesible desde nuestra red:
yum install ntp
En el fichero /etc/ntp.conf añadimos la información de nuestro servidor de tiempos: server servidor_ntp
service ntpd start
  • Ejecutamos google-authenticator con el usuario que queremos proteger (no tienen que ser todos) Nos generará un enlace al sitio de Google donde encontraremos el código QR con el que debemos, en nuestro móvil y con la app Google Authenticator, crear una cuenta para nuestro acceso SSH igual que comentamos en la entrada anterior para WordPress. Además, nos proporcionará los códigos de un solo uso que debemos usar cuando no tengamos disponible dicha app.
  • Además de la ejecución, deberemos responder a 4 preguntas: mejor ‘Y’ a todas ;).
    • Con la primera, le estamos indicando que queremos que los tokens estén basados en el tiempo y que actualice el fichero HOME/.google_authenticator que es donde almacenará información importante como el enlace y los código mencionados en el punto anterior.
    • En la segunda nos pregunta si queremos deshabilitar el uso del mismo token por diferentes usuarios
    • En la tercera nos indica el tiempo por defecto (30″) para compensar posibles diferencias temporales entre cliente y servidor
    • Y en la última, limita el número de intentos a 3 cada 30″ para evitar ataques de fuerza bruta
  • En el siguiente paso, debemos configurar el módulo PAM del servicio SSH. En el fichero /etc/pam.d/sshd debemos añadir
auth   required  pam_google_authenticator nullok secret=/home/${USER}/.google_authenticator

nullok permite que los usuarios para los que no tengamos configurado el segundo factor de autenticación, puedan entrar al sistema sin solicitarles el código. Con secret le indicamos dónde está el fichero con la información de autenticación.

  • En el fichero /etc/ssh/sshd_config debemos activar (escribir  YES) la opción ChallengeResponseAuthentication.
  • También debemos asegurarnos, en el mismo fichero, que esté UsePAM yes y PubKeyAuthentication no
  • Y finalmente, reiniciar el servicio ejecutando:
service sshd restart

Existen más opciones que nos pueden interesar para afinar el sistema 2FA. Por ejemplo una idea es que cuando accedamos desde determinados sitios (nuestra red local), no nos solicite el segundo factor. Esto se consigue con la instalación (si no está ya) del módulo pam_access y configurando las PAM:

auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/access-local.conf
auth       required     pam_google_authenticator.so nullok secret=/home/${USER}/.google_authenticator

Además, en el fichero /etc/security/access-local.conf debemos escribir algo parecido a esto (donde 10.0.0.0/24 es la red local):

# only allow from local IP range
+: ALL :10.0.0.0/24
+: ALL : LOCAL
-: ALL : ALL

Si queremos que el 2FA NO se aplique a los usuarios de un grupo determinado:

auth [success=1 default=ignore] pam_succeed_if.so user ingroup sudo
auth       required     pam_google_authenticator.so nullok secret=/home/${USER}/.google_authenticator

Si quisiéramos que se aplicara solo a ese grupo, basta con sustituir “user ingroup” por “user notingroup

La información de esta entrada sirve también para proteger otros servicios de sesión de usuario como login, su, sudo, lightdm

¡Espero que os sea útil!

Referencias

  1. https://code.google.com/p/google-authenticator/wiki/PamModuleInstructions

 


Cómo controlar la recepción de peticiones abusivas desde una misma IP

Hace unos meses escribí esta entrada sobre un guión en Python para la detección de peticiones abusivas hacia un servidor web Apache. Me faltó indicar cómo controlarlas y es muy sencillo:

iptables -I INPUT --dport 80  -p tcp --syn -m recent --name "CONTROL-WEB" --set
iptables -I INPUT -p tcp --dport 80 --syn -m recent --update --seconds 30 --hitcount 20 -j DROP

Estas líneas de iptables, que podemos añadir al principio de la lista de órdenes de nuestro filtro de acceso al servidor, se encargan de contar el número de peticiones de establecimiento de conexión por cada dirección IP en los últimos 30 segundos, descartando los que puedan llegar cuando la cuenta ha superado el valor de 20 e impidiendo, por tanto, la conexión desde esa IP. El guión de la entrada mencionada nos puede servir para hacernos una idea de qué es lo habitual en nuestro sistema y ajustar los segundos y número de conexiones en esos segundos que queremos admitir.

La primera orden crea una lista dinámica de nombre CONTROL-WEB en la que insertará la IP de origen del paquete. La segunda, comprueba si esa IP se ha añadido a la lista en los últimos 30″ y, en el caso de que se hayan contabilizado más de 20 peticiones, deniega la petición.

Podemos ser más específicos indicando que solo queremos contabilizar los inicio de conexión:

iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent -name "CONTROL-WEB" --set
iptables -I INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 30 --hitcount 50 -j DROP

En el directorio /proc/net/xt_recent encontraremos un fichero de nombre CONTROL-WEB y cuyo contenido es la lista de IPs añadidas por las reglas anteriores.

Referencia

  1. man iptables

Fortificando la autenticación de usuarios en WordPress

Al margen de la elección de contraseña, es una opinión, y cada vez más generalizada, que para aumentar la seguridad en la autenticación de los usuarios, debemos recurrir a sistemas MFA (Multi-Factor Authentication). Estos sistemas consisten en incluir diferentes factores de autenticación (2 o más): uno basado en algo que conocemos (por ejemplo, el clásico de la contraseña); otro en algo que poseemos (el móvil, por ejemplo) y/o algo que solo es el usuario (por ejemplo, su huella o cualquier característica biométrica).

Si queremos mejorar la seguridad de nuestro blog, existen pluggins que implementan un mecanismo 2FA (doble factor de autenticación) basado en Google Authenticator. En este blog estoy probando: WP Google Authenticator.

Es muy fácil de utilizar:

  1. Lo instalamos (Plugins>Añadir Nuevo y tras esto: Activar)
  2. Tras este proceso, en Ajustes, tendremos las opciones del plugin. En mi caso activé que el número máximo de veces que se puede autenticar un usuarios sin 2FA sea de 3)
  3. En Usuarios>Tu Perfil, abajo aparece información importante. Por un lado, el botón Get QR Code al que pulsaremos para obtener el código QR  sincronizará la aplicación Google Authenticator de nuestro móvil con el plugin. Para esto:
    • Arranqueremos en nuestro móvil Google Authenticator,
    • En Menú: Configurar Nueva cuenta,
    • Escanear código ¡et voila!
  4. Además en Usuario>Tu perfil tendremos el código de recuperación y tu clave secreta que no debes compartir con nadie.

Ahora, cada vez que queremos acceder al control de nuestro WordPress, nos encontraremos con:

Captura de pantalla de 2014-07-30 12:57:32

Quien disponga de un hosting propio al que se conecte con sesiones de trabajo que quiere fortalecer, también podemos utilizar Google Authenticator para implementar  un 2FA en el servicio SSH. Esto, en otra entrada que publicaré en breve 😉


Virtualhost con nombre en Apache y Nagios

RECORDATORIO: Si estás comprobando el funcionamiento de tu sitio web con Nagios y dispones de varios sitios definidos con VirtualHost basados en el nombre debes asegurarte que en la petición se mande el nombre del sitio deseado.

Si lo hiciéramos “a mano”, la conversación desde el cliente nagios al servidor Apache sería así:

telnet nombre_servidor 80
GET / HTTP/1.0
HOST:nombre_servidor
línea en blanco
línea en blanco

Para comprobar la disponibilidad, Nagios utiliza la orden check_http internamente y, para asegurarnos que indica el nombre del servidor, la invocación debe incluir el parámetro “-u <nombre_servidor>”:

check_http -I -p 80 -u <nombre_servidor> -R "string a buscar"

Autenticación con LDAP en Alfresco

En /opt/alfresco-4.2.f/tomcat/shared/classes/alfresco-global.properties debemos añadir la cadena de conexión del LDAP:

authentication.chain=ldap1:ldap,alfrescoNtlm1:alfrescoNtlm

Una recomendación es dejar, como última cadena alfrescoNtlm1:alfrescoNtlm para la autenticación nativa de Alfresco*.

Después debemos configurar el acceso a nuestro directorio para lo que necesitamos un fichero con los valores de LDAP. Para ello podemos partir de uno existente ejecutando la orden**:

sudo cp $ALFRESCO_DIR/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties 
$ALFRESCO_DIR/tomcat/shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1/ldap-authentication.properties

En mi caso, el valor de $ALFRESCO_DIR es el directorio por defecto en la instalación /opt/alfresco-4.2.f/

En el fichero copiado: $ALFRESCO_DIR/tomcat/shared/classes/alfresco/extension/subsystems/Authentication/ldap/ldap1/ldap-authentication.properties

podemos configurar el uso y conexión al sevidor LDAP. Si solo queremos autenticar, debemos insertar las líneas:

  • ldap.authentication.active=true
  • ldap.authentication.userNameFormat=uid=%s,dc=midominio,dc=dominio_primer_nivel
  • ldap.authentication.java.naming.provider.url=ldap://servidorLDAP.midominio.es:puerto

Si no queremos sincronizar la información de los usuarios y grupo: ldap.synchronization.active=false

Para que el sistema funcionara con cierta seguridad, deberíamos configurar la conexión bajo SSL. Otra opción es que la comunicación entre el servidor Alfresco y el directorio se realice por un túnel cifrado con, por ejemplo, IPSec y, en este caso, desde el punto de vista del servicio, no tenemos que hacer nada más.

Por último, que no se nos olvide desactivar el usuario invitado. En el mismo fichero de configuración del LDAP: ldap.authentication.allowGuestLogin=false

*Para desactivar los accesos anónimos/invitados también en la autenticación nativa de Alfresco, en el fichero $ALFRESCO_DIR/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication/alfrescoNtlm/alfresco-authentication.properties

alfresco.authentication.allowGuestLogin=false

** Es posible que tengas que crear algunos subdirectorios intermedios. Yo lo tuve que hacer.

Referencias:

  1. Información sobre los subsistemas de Alfresco: http://wiki.alfresco.com/wiki/Alfresco_Authentication_Subsystems
  2. Configurando LDAP: http://docs.alfresco.com/4.1/concepts/auth-ldap-intro.html

 


Sistema de archivo remoto accesible mediante SSH

Si queremos compartir o acceder a un directorio de un equipo al que ya accedemos mediante SSH, una buena opción es usar el mismo servicio (ssh) para conseguir este objetivo. Para ello necesitamos:

  • Que el núcleo incluya FUSE. Si no lo está: basta con instalar fuse-source e instalarlo con module-assistant.
  • Que el usuario local pertenezca al grupo fuse.
  • Instalar sshfs: apt-get install sshfs.
  • Tener correctamente configurado el servidor SSH en el equipo en el que queremos montar el directorio.

Hecho lo anterior ya podemos montar cualquier directorio y utilizarlo en nuestro equipo como si fuera un directorio local. La orden debería seguir el patrón:

sshfs [email protected]_del_sevidor:<directorio a exportar> <directorio local>

  • usuario será el del servidor al que tenemos que acceder,
  • ip del servidor en el que se encuentra el directorio a exportar,
  • y directorio local será el punto de montaje a partir del cual estarán disponibles los ficheros del directorio exportado del servidor desde el punto de vista del “cliente”

Si queremos que esté disponible en el arranque, tenemos que configurar el montaje en el fichero /etc/fstab. Para ello, debemos añadir una línea al fichero /etc/fstab que siga la siguiente sintaxis:

sshfs#[email protected]:<directorio a exportar>   <directorio local>   fuse   defaults 0 0

  • donde, al igual que con la orden dada anteriormente, tenemos que indicar el usuario del servidor con el que debemos conectarnos para acceder al directorio, el directorio y el punto local de montaje.
  • Aquí debemos indicar también el tipo de sistema de archivo (fuse). Como opciones de montaje podemos dejar las “defaults” o utilizar cualquier otra de las que disponemos (ro, rw, nosuid, async, noexec, noauto, …).
  • El penúltimo campo (dump) indica si se quiere o no realizar un volcado de los errores (0 ó 1) .
  • El último indica si no queremos (0) realizar un chequeo del sistema de archivos o y, en este caso, 1, 2, marcará el orden en el serán comprobados*. En nuestro caso, creo que es mejor usar la opción 0 y no chequear (ya lo haremos, en todo caso, en el propio servidor donde se encuentra el directorio).

Una vez introducida la línea en /etc/fstab, para probarla sin necesidad de reiniciar, podemos ejecutar mount -a.

Debemos tener en cuenta que si queremos montar automáticamente en el arranque, lo más lógico es autenticar mediante clave pública** para que se monte correctamente en el inicio del equipo y que no tenga que pedirnos la contraseña, además de guardar la clave pública del servidor en el fichero known_hosts de ssh para que no solicite confirmación.

Para desmontar/desasociar el directorio, debemos ejecutar la orden

 fusermount -u directorio_local

¡Ojo! Este mecanismo NO te cifra el directorio. Te da privacidad en la comunicación estableciendo una conexión cifrada. ¡Y tampoco lo puedes usar con Dropbox!

Todas las técnicas de protección que usemos para el servidor SSH, influirán positivamente en la seguridad de nuestro “servicio de disco”, pero esto, lo dejamos para otro día.

Referencias:

  1. Hardening de servidores GNU/Linux, de Carlos Álvarez Martín y Pablo González Pérez
  2. Administración de sistemas operativos Windows y Linux. Un enfoque práctico, de Juan Antonio Gil, Julio Gómez y Nicolás Padilla.

* Normalmente se utiliza 1 para el sistema de archivos raíz, 2 para el resto. La comprobación, por defecto, se realiza cada 29 desmontajes y se puede modificar por sistema de archivo (ver la orden tune2fs).

** Debemos copiar la clave pública de los usuarios al servidor (la podemos generar mediante la orden ssh-keygen) en la ruta que esté indicada por la directiva AuthorizedKeysFile del fichero /etc/ssh/sshd_config Por defecto, indica que está en el directorio HOME del usuario ($HOME/.ssh/authorized_keys) Es importante para la automatización, que NO activemos un PIN a la clave privada.


Benchmark: Diseño de pruebas

Saber cómo se va a comportar un servidor, por ejemplo, un Apache, exige someterlo a una pruebas específicas que nos den una idea de lo que es capaz. Por ejemplo, un objetivo claro es determinar el número de peticiones de servicio por segundo que nuestro servidor es capaz de soportar/atender dentro de ciertas restricciones, como no esperar (los clientes) más de X segundos (5-8 segundos es un buen valor para X) y el rendimiento no baja de 320.000 bits por segundo (SPECweb99: http://www.spec.org/osg/web99/). Conocer esta información es importante, por ejemplo, para que nuestro servicio no muera de éxito, es decir, que un crecimiento demasiado rápido del volumen de carga de una plataforma web (mantenido o con picos puntuales) pueda producir lentitud o incluso cortes en el servicio, con las consiguientes pérdidas en oportunidades de negocio e imagen.

Otro objetivo puede ser el número de conexiones simultáneas que soporta sin errores y sin enviar una petición no válida: debe generar un mensaje de respuesta. Y también, por supuesto, el rendimiento entendido como el número de bytes transmitidos por unidad de tiempo.

¿Cómo lo hacemos?

Leer más


Las cookies nos permiten ofrecer nuestros servicios. Al utilizar nuestros servicios, aceptas el uso que hacemos de las cookies. Más información.