Shortcuts: comandos OpenSSL para generar claves, certificados y testear conexiones

OpenSSL es una herramienta extremadamente potente, la cual permite hacer todo tipo de manejos relacionados a TLS/SSL, desde creación de claves y certificados, realizar conexiones tipo telnet a servicios que se ejecutan sobre SSL, hasta generar hashes de archivos, entre otras cosas.
A continuación les dejo un listado de comandos útiles a realizar con OpenSSL. La mayoría se centran en la creación y manipulación de claves y certificados, algo que todo administrador ha tenido que hacer alguna vez.
Ya había escrito sobre la creación de certificados en el artículo Certificados Digitales, donde podrán encontrar una explicación más detallada sobre ello. En éste la idea es dejar un acceso rápido a comandos que nos serán muy útiles, además de proveer varios comandos adicionales a los descriptos anteriormente.
Cabe mencionar que muchos de estos comandos los aprendí gracias al artículo The Most Common OpenSSL Commands y los completé con el excelente OpenSSL Command-Line HOWTO y Creating an SSL Certificate of Authority.


Claves

Generar clave RSA de 4096 bits encriptada con 3des:
  $ openssl genrsa -des3 -out superkey.key 4096

Desencriptar la clave privada
  $ openssl rsa -in superkey.key -out super-decrypted.key

Extraer la clave privada de un archivo en formato PKCS#12:
  $ openssl pkcs12 -in certificad.pfx -out clave.pem -nodes -nocerts

Verificar clave RSA:
  $ openssl rsa -in interbankingtestmil-open.pkcs -check

 
Convertir formatos

Convertir clave de formato tradicional a pkcs8:
  $ openssl pkcs8 -in key.pem -topk8 -out pkcskey.pkcs

Convertir un certificado PEM y una clave privada en un archivo formato PKCS#12 (.pfx o p12)
  $ openssl pkcs12 -export -out certificado.pfx -inkey clave.pem -in certificado.crt -certfile certificadoCA.crt
 
 
Certificados

Crear una CA Propia con validez de 10 años y clave RSA de 4096 bits:
  $ openssl req -new -x509 -days 3650 -extensions v3_ca -newkey rsa:4096 -keyout private/newca.pem -out newca.crt //-config /etc/ssl/openssl.cnf

Generar un request de certificado:
  $ openssl req -new -key superkey.key -out certrequest.csr

Autofirmar request de certificado (CSR):
  $ openssl x509 -req -days 3650 -in cert-request.csr -signkey ca.key -out certificado.crt
 
Firmar request con CA:
  $ openssl ca -in cert-request.csr -out certificado.crt -days 3650

Crear clave y certificado autofirmado en un solo paso:
  $ openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt

Extraer el certificado incluído en un contenedor PKCS#12:
  $ openssl pkcs12 -in certificad.pfx -out certificado.crt -nodes -nokeys

Ver los campos de un request de certificado:
  $ openssl req -noout -text -in certrequest.csr

Ver campos del certificado:
  $ openssl x509 -in certificado.crt -text -noout
 
Ver campos de un contenedor PKCS#12:
  $ openssl pkcs12 -info -in certificado.pfx


Otras utilidades

Conectar a un servicio que se ejecuta sobre SSL (por ejemplo HTTPS):
  $ openssl s_client -connect servidor:443

Calcular el hash MD5, SHA1, SHA2, etc de un archivo y de un texto
  $ openssl dgst [-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1] archivo
  $ echo "texto" | openssl dgst [-md5|-md4|-md2|-sha1|-sha|-mdc2|-ripemd160|-dss1]

Nagios: monitoreo remoto de dispositivos + agentes Linux + agentes Windows
Desde hace un par de semanas vengo trabajando con Nagios para tener, al instante, el estado de los
servicios de la red (i.e. monitoreo).
Existen varias herramientas para este tipo de trabajo, estando entre las mejores (según he leído y por recomendaciones) Cacti y Zabbix. Mi elección de Nagios se debe a su integración con OSSIM, y a que ya había trabajado con ella en otra ocasión y me resultó muy buena. Esto no implica que Nagios sea la mejor herramienta, pero sí una excelente. Una comparación interesante que encontré sobre herramientas de monitoreo libres es Tired of Nagios and Cacti? Try Zabbix, la cual, obviamente se enfoca en Zabbix, pero nombra los pro y los contra de cada herramienta.

Las características que encuentro más importantes en Nagios, son:
- Compatibilidad. Existen agentes tanto para Linux como para Windows que permiten monitorear una gran variedad de recursos.
- Flexibilidad. Se pueden definir comandos nuevos para chequeos que no estén incluidos, o para mejorar alguno existente.
- Extendibilidad. El protocolo de comunicación entre agentes y servidor es abierto y está documentado para que cualquiera pueda desarrollar sus propios agentes. Además, como veremos, es posible utilizar varios protocolos.
- Configuración a través de archivos de texto. Si bien algunos no les gusta, para mi es mucho más rápido definir hosts y servicios a chequear mediante simples archivos de texto, que haciendo muchos clicks en una interfaz web.
- Visualización del estado de la red en una sola pantalla. Es fácil y rápido detectar cuando algo anda mal.
- Intervalos para chequear un host/servicio configurables.
- Reporte de alertas por mail y SMSs.
- Sistema de detección de cambios de estado (flapping). Si un host se detecta caído, al minuto normal, al minuto caído, no está bueno recibir 300 alertas, dado que el host está en un estado inestable. Nagios detecta esto y previene futuras alertas hasta que se estabilice.
- Variedad de plugins predefinidos.
- Hay una gran comunidad detrás, así como mucha documentación.


What's all about?

La idea de este artículo no es hablar de las bondades o puntos bajos de Nagios, sino explicar la forma de armar una configuración básica que permita chequear el estado de hosts y servicios remotamente, así como chequear recursos mediante agentes tanto en Windows como en Linux.
Información de Nagios hay mucha, este artículo pretende aportar una explicación resumida del funcionamiento básico y una configuración que abarca la mayoría de los chequeos típicos. Añadir chequeos no debería ser mayor problema una vez conocida las bases.
Para completar esta información, recomiendo leer la documentación oficial en Nagios Core Documentation.


Definición de objetos

Nagios se configura mediante archivos de texto, los cuales deben tener la extensión .cfg. La configuración se basa en objetos, que son los elementos involucrados en la logística de monitoreo y notificación.
Los objetos básicos son:
  - comandos: definen qué programas ejecutar.
  - servicios: son los recursos a testear (CPU, disco, protocolos de red, etc)
  - hosts: definen los hosts que se van a monitorear.
  - contactos: son las personas a las que se va a notificar cuando ocurre una alerta.
  - tiemeperiods: definen en qué horarios se puede chequear un host y en qué horarios se puede notificar a un contacto.
Estos objetos se pueden agrupar mediante los siguientes objetos:
  - hostgroups: permiten agrupar hosts.
  - servicegroups: agrupan servicios.
  - contactgroups: agrupan contactos.

Como se puede observar en la sección de definición de objetos del manual de Nagios, cada objeto puede tener definidos varios atributos, aunque sólo unos pocos (sobre todo si utilizamos la herencia) son obligatorios. Los objetos se definen mediante la cláusula "define" y sus atributos se encierran entre llaves.
Los atributos que utilizaremos para cada tipo de objeto, y que les servirán para la gran mayoría de los casos, son los siguientes:
  comandos:
    - command_name: nombre del comando (por ej check_http)
    - command_line: la línea de comando que se ejecutará para el chequeo (ejemplo: /usr/lib/nagios/plugins/check_http -I $HOSTADDRESS$ -p $ARG1$)

    Como se puede observar en el ejemplo, existen variables predefinidas que se pueden utilizar como argumentos pasados al programa en la línea de comandos (Nagios las denomina macros). La lista completa de macros se encuentra aquí. En el ejemplo $HOSTADDRESS$ es la dirección del host que se está chequeando. También es posible utilizar variables cuyo valor será reemplazado cuando se llame el comando desde la definición de un servicio (o host), las cuales se denominan a partir de $ARG1$ hasta $ARGN$.
 
  servicios:
    - use: directiva que permite heredar atributos de servicios definidos previamente. Es posible definir un servicio base y luego extenderlo mediante esta directiva. En las definiciones de servicios, se suele heredar de "generic-service".
    - service_description: una breve descripción del servicio.
    - hostgroup_name/host_name: asigna el servicio a un grupo de hosts o a hosts específicos. No es mandatorio utilizar este parámetro, dado que se pueden asignar servicios a hosts desde la misma definición de los hosts. Es posible asignar más de un hostgroup o host separándolos con comas.
    - check_command: el nombre del comando, previamente definido, que se utilizará para chequear el servicio. Algo a tener en cuenta es que cuando se llama al comando, los parámetros se pasan separados con signos de admiración. Estos luego se reemplazarán en $ARG1$... $ARGN$, según se definió en el comando.
    Por ejemplo, en la definición de check_tcp encontramos que el comando ejecutado es el siguiente:
      /usr/lib/nagios/plugins/check_tcp -H $HOSTADDRESS$ -p '$ARG1$' -4
    donde $ARG1$ se reemplazará por el puerto TCP que se desea chequear cuando se llame el comando.
    La forma de llamar el comando es la siguiente:
      check_command check_tcp!50000
    donde 50000 es el parámetro utilizado para el puerto.

    NOTA: si no se hereda la definición de generic-service, deberán definirse otros atributos adicionales que son mandatorios (max_check_attempts, check_interval, retry_interval, check_period, notification_interval, notification_period, contacts, contact_groups).

  hosts:
    - use: al igual que en los servicios, esta directiva permite heredar los atributos de un host previamente definido. El caso más común es heredar la definición de "generic-host"
    - host_name: es lo que el nombre indica, el hostname del host.
    - address: dirección IP del host.
    - alias: una breve descripción de la funcionalidad del host.
    - hostgroups: listado de hostgroups a los que el host pertenece. Este atributo no es mandatorio, además es posible asignar los hosts a un hostgroup desde la misma definición del hostgroup.
    - check_command: tiene la misma utilidad que cuando se define un servicio, con la diferencia que se utiliza para chequear si un host está online. Por defecto se utiliza ping (definido en generic-host) como chequeo, pero se puede reemplazar por otro si es que el host no admite pings.
 
    NOTA: si no se hereda la definición de generic-host, deberán definirse otros atributos adicionales que son mandatorios (max_check_attempts, check_period, notification_interval, notification_period, contacts, contact_groups).
 
  hostgroups:
    - hostgroup_name: el nombre del hostgroup que estamos definiendo.
    - alias: una breve descripción de la funcionalidad del hostgroup.
    - members: listado de hosts, separados por coma, que pertenecen a este hostgroup. Este atributo es opcional.

  contactos:
    - contact_name: nombre del contacto.
    - alias: un alias para el mismo.
    - service_notification_period: indica en qué horarios se puede contactar en caso de caída de servicios.
    - host_notification_period: indica en qué horarios se puede contactar en caso de caída del host.
    - service_notification_options: listado de estados de servicio que deben reportarse. Los estados se definen con letras y se separan con comas: u (UNKNOWN), c (CRITICAL), r (RECOVERY - OK), f (FLAPPING), y n (NONE).
    - host_notification_options: listado de estados de host que deben reportarse. También se definen con letras separadas por coma: d (DOWN), u (UNREACHABLE), r (RECOVERY - UP), f (FLAPPING), s (comienza el downtime programado), n (NONE).
    - service_notification_commands: cómo notificar al contacto en caso de servicio caído (email, sms, etc).
    host_notification_commands: cómo notificar al contacto en caso de host caído (email, sms, etc).
    - email: dirección de email del contacto.
    - contactgroups: grupo al que pertenece el contacto.

 
Agentes Nagios

Una gran parte del monitoreo se puede hacer remotamente. Todo servicio publicado en la red, se puede monitorear sin necesidad de instalar nada en el host monitoreado. Sin embargo hay recursos que no se pueden monitorear remotamente, como por ejemplo:
- espacio libre en disco
- memoria en uso
- carga de CPU
- servicios activos
- cantidad de usuarios logueados
Para ello es necesario instalar agentes. Estos agentes, mediante plugins, chequean el estado de los recursos y envían los datos al servidor Nagios. El tipo de conexión es pull, es decir, el servidor Nagios contacta cada cierto intervalo de tiempo a los agentes, les indica qué comandos ejecutar y obtiene los resultados.
Existen varios protocolos utilizados para la comunicación entre agentes y Nagios:
- NRPE - Nagios Remote plugin Executor. Es el protocolo más utilizado y recomendado por Nagios. Se accede mediante el plugin check_nrpe.
- NSCA - Nagios Service Check Acceptor.
- NSCP: protocolo nativo de NSClient++
- NRDP: reemplazo NSCA.
- Syslog: protocolo estándar para transmisión de logs en Unix.
- SNMP: Simple Network Management Protocol. Protocolo estándar para administración y monitoreo de dispositivos de red.

En este artículo se utilizará el protocolo NRPE, para lo cual se instalarán agentes en Linux y Windows que lo soporten.


Instalación del servidor

Instalar el servidor de Nagios es muy simple, está en los repositorios de la mayoría de las distribuciones.
Por ejemplo, en debian, basta con ejecutar:
  # apt-get install nagios3 nagios-nrpe-plugin

La instalación en debian solicita que se introduzca una clave de administración web (usuario nagiosadmin). Pueden elegir no ingresar clave, e ingresarla después. Lo más cómodo es asignarla en esta instancia, aunque queda a elección. La autenticación de la interfaz web la realiza Apache, así que agregar o quitar usuarios se puede realizar con la utilidad htpasswd. También instalamos aquí los plugins para comunicarnos con los agentes mediante NRPE (ver más adelante).

El servicio de Nagios se ejecutará, por defecto, a nombre del usuario nagios y grupo nagios. Esto es para limitar los privilegios, dado que el sistema no necesita permisos de root para ejecutarse, y sería muy riesgoso.


Si utilizan debian, otros datos interesantes acerca de la instalación son:
  - Los plugins default de Nagios (paquete nagios-plugins) se instalan en /usr/lib/nagios/plugins
  - Los comandos (ver más adelante que son) default están definidos en /etc/nagios-plugins/config
  - Por defecto, nagios carga toda la configuración incluida en /etc/nagios3/conf.d, así que lo más conveniente es incluir los archivos con las definiciones de hosts, servicios, comandos, etc, allí.
  - El archivo de configuración de apache para la interfaz web de Nagios se encuentra en /etc/apache2/conf.d/nagios3.conf
  - Por defecto la interfaz web se accede mediante la URL http:///nagios3. Este alias se puede cambiar en el archivo citado en el punto anterior.
  - El archivo de autenticación para la interfaz se encuentra en /etc/nagios3/htpasswd.users


Arquitectura de ejemplo

Para poder explicar la configuración de Nagios de forma más didáctica, utilizaremos la siguiente arquitectura de red como ejemplo:
En esta simple estructura traté de cubrir los casos más frecuentes, al menos cubre todos los casos con los que me he topado. La red cuenta con:
  - un servidor Nagios que monitoreará todo (192.168.0.100).
  - un servidor Linux (linuxagent - 192.168.0.3) con el agente de Nagios instalado, que posee un servicio Web (puerto 80).
  - un servidor Windows (winagent - 192.168.0.4) con el agente de Nagios instalado, que presta servicio de fileserver (CIFS puerto 445), y Web service en el puerto 81. En este servidor chequearemos que el servicio de Firewall de Windows esté iniciado (MpsSvc).
  - un servidor al cual no se le instaló agente (noagent - 192.168.0.20), pero que presta un servicio no estándar en el puerto 4444.
  - un servidor web colocado en internet (itfreekzone - 10.0.0.10, claro está que la IP no es una IP de internet válida, sólo se usa de ejemplo).
Los hosts de la red interna son alcanzables mediante ping, mientras que el servidor Web de internet no.

Si tienen algún caso que no entre en alguna de estos posibles, dejen su comentario y trato de añadirlo :)


Servidor Linux con agente

Arranquemos con la configuración del monitoreo de un servidor linux para el cual utilizamos un agente. Como se indicó anteriormente, NRPE es el protocolo elegido para la ejecución remota de comandos, así que el agente a instalar debe soportarlo. En debian existe un paquete denominado nagios-nrpe-server.

En el servidor Linux, instalaremos entonces los siguientes paquetes (buscar equivalentes en distribuciones no debian):
  # apt-get --no-install-recommends install nagios-nrpe-server nagios-plugins-basic
El paquete nagios-plugins-basic provee el set básico de plugins para los chequeos.

La configuración del agente NRPE se realiza desde el archivo /etc/nagios/nrpe.cfg. Las variables a tener en cuenta en este archivo son:
server_port=5666 #define en qué puerto (TCP) escuchará el agente. Por defecto es el 5666, pero se puede setear cualquiera.

server_address=192.168.0.3 # indica en qué dirección IP escuchará el agente, en caso que el servidor posea más de una IP.

allowed_hosts=192.168.0.100 # define qué IPs tienen permitido conectarse al agente en busca de datos. Es un parámetro de seguridad mínimo para limitar desde qué máquinas se conectan al agente.

dont_blame_nrpe=0 # mi variable favorita (por su nombre, claro). Esta variable indica si se permite que el agente reciba comandos con parámetros (por ejemplo, en la ejecución "check_disk -w 20%" el parámetro es "-w 20%"). Es muy mala idea permitir que hosts remotos envíen al agente parámetros, dado que podrían utilizarse para explotar alguna vulnerabilidad (qué pasa si se recibe "check_disk -w <muchos bytes...="">" ???). Por ello, se recomienda crear alias de comandos, como por ejemplo "command[check_disk]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -x sda", donde el servidor sólo necesitará llamar "check_disk" (sin parámetros) para obtener los datos de espacio libre y alertas.

command[check_users]=/usr/lib/nagios/plugins/check_users -w 5 -c 10 # alias check_user para obtener la cantidad de usuarios logueados y alertar si hay más de 5 logueados al mismo tiempo.
command[check_load]=/usr/lib/nagios/plugins/check_load -w 15,10,5 -c 30,25,20 #alias check_load para obtener la carga de CPU
command[check_disk]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -x sda #alias check_disk para obtener el espacio disponible en el disco /dev/sda y alertar si queda menos de 20% de espacio en alguna partición.
Como se ve, los alias son muy importantes, y se pueden agregar tantos como se desee. Estos definen un acceso a información con parámetros predefinidos, de modo que el servidor sólo debe llamar el comando sin parámetros, y disminuir el riesgo (el atributo lo dice, no le eches la culpa a NRPE si se te rompe todo por usar parámetros - dont_blame_nrpe). Sólo listé tres (check_disk, check_load, y check_users) pero podría haber creado todos los que quisiera.

Una vez configurado el agente, reiniciarlo para que tome los cambios:
  # /etc/init.d/nagios-nrpe-server restart


Servidor Windows con Agente

Para monitorear recursos en Windows, existe el demonio NSClient++ (http://www.nsclient.org). El demonio soporta todos los protocolos mencionados anteriormente, pero como comenté, utilizaremos NRPE.
La instalación es muy simple, bajan la última versión del instalador y la ejecutan. Pueden elegir la instalación típica y dar todo next, sin chequear nada, dado que luego reemplazaremos el archivo nsclient.ini con la información que les dejo a continuación. Si desean utilizar las opciones del instalador, verán que permite habilitar algunas cosas, como si utilizar NSCP (check_nt) y/o NRPE (check_nrpe), un password de acceso para el caso de check_nt (el cual no utilizaremos), los hosts que tienen permitido acceder a la información (allowed_hosts), checks WMI, y los check plugins.

Toda la configuración se guarda en el archivo C:\Program Files\NSClient++\nsclient.ini (o C:\Archivos de Programas\NSClient++\nsclient.ini). Si no tildaron nada durante la instalación, verán que está vacío, a excepción de unos comentarios.
NSClient no utiliza el mismo formato de configuración que el visto en el host Linux, es más, varía bastante. Para empezar, la configuración se divide en secciones (formato estándar de los .ini). Por otra parte, los plugins se deben habilitar antes de ser utilizados. Además los plugins se llaman con ejecutables diferentes (CheckCpu. CheckDriveSize, etc), y los alias se definen de otra manera. Para estandarizar, en la configuración utilicé los mismos alias que en el host Linux, así es posible realizar grupos de hosts que incluyan tanto servidores Linux como Windows, y ejecutar los mismos comandos en ambos.
La configuración que utilizaremos será la siguiente:
[/modules]
; habilitamos el uso de NRPE
NRPEServer = 1

; habilitamos plugins a utilizar. Como se ve, los plugins se agrupan por tipo.
CheckSystem=1
CheckDisk=1
CheckExternalScripts=1

; creamos los mismos alias que en la definición del host Linux, y agregamos un alias para chequear servicios
[/settings/external scripts/alias]
check_load=CheckCpu MaxWarn=80 time=5m ; alias para chequear la carga de CPU. Si sobrepasa el 80% en un intervalo de 5 minutos, nos alertará.
check_disk=CheckDriveSize ShowAll MinWarnFree=10% MinCritFree=5% ; alias para chequear el espacio en todos los discos del servidor
check_firewall_service=CheckServiceState MpsSvc; alias para chequear el servicio del firewall de Windows (llamado MpsSvc).

[/settings/default]
; permitimos el acceso al servidor Nagios para las consultas.
allowed hosts = 192.168.0.100

Configuración de los checks en el servidor Nagios

Bien, con los agentes instalados y configurados, volvemos al servidor Nagios. Utilizamos el directorio /etc/nagios3/conf.d para poner nuestra configuración, tal vez adentro de un directorio nuevo, para que quede más ordenado y no se mezcle con el resto.

Observando el directorio conf.d encontramos varias definiciones, como las citadas generic-host y generic-service. También se agrega por defecto la definición de los servicios a chequear en localhost, algo que nos puede servir como ejemplo. En /etc/nagios-plugins/config encontramos la definición de varios comandos, que nos servirán para la mayoría de los casos, aunque habrá algunos que tendremos que definir nosotros.

Para comenzar, definimos un comando nuevo que utilice check_http, pero que nos permita chequear servicios Web en cualquier puerto. En /etc/nagios-plugins/config/http.cfg existen varios comandos predefinidos para llamar a check_http, pero no encontré ninguno que permita hacer un simple check a un puerto diferente al 80. Si quieren ser prolijos, podríamos incluir los comandos en un archivo commands.cfg dentro de nuestro directorio de configuración.
El comando se define de la siguiente manera:
define command {
  command_name check_http_port
  command_line /usr/lib/nagios/plugins/check_http -I $HOSTADDRESS$ -p $ARG1$
}
Cuando se llame el comando, deberá entregarse un puerto como argumento y realizará el chequeo HTTP.

A continuación me parece bien definir un grupo de hosts para agrupar los hosts que tienen instalado el agente, lo denominaremos remote-agent.
define hostgroup {
  hostgroup_name remote-agent
  alias Hosts que tienen el agente de Nagios instalado
}
De esta forma, podemos definir servicios que se chequeen en todos los host que tengan el agente instalado, tan solo agregando los hosts al grupo remote-agent y asignando los servicios al mismo.
Para los checks remotos, debemos utilizar el comando check_nrpe_1arg (/etc/nagios-plugins/config/check_nrpe.cfg), al cual se le entrega como parámetro el nombre del comando a ejecutar en el host remoto. El “1arg” indica que se le entrega un parámetro (el nombre del comando a ejecutar). Los comandos que llamaremos son los alias que definimos en cada host anteriormente.
En los hosts con el agente realizaremos checks de CPU y disco:
#checkear CPU
  define service {
    use generic-service # hereda los atributos de generic-service
    hostgroup_name remote-agent # indicamos que se aplica al hostgroup remote-agent
    service_description Load average # describimos lo que se testea
    check_command check_nrpe_1arg!check_load #llamamos a check_nrpe_1arg y le indicamos que debe ejecutar check_load
  }

  #checkear discos
  define service{
    use                             generic-service # heredamos
    hostgroup_name                  remote-agent # aplicamos al grupo remote-agent
    service_description             Disk Space # describimos lo que testeamos
    check_command                   check_nrpe_1arg!check_disk # indicamos que debe ejecutarse el alias check_disk
  }
Ya tenemos los checks genéricos que haremos en los hosts con agentes.
Dado que el resto de los servicios los chequearemos por host, pasemos a la definición de los hosts.
# host linux con agente
define host {
  use generic-host
  host_name linuxagent
  alias Web Server Linux con agente instalado
  address 192.168.0.3
  hostgroups remote-agent,http-servers
}
Acá aparece el grupo predefinido http-servers. El mismo se encuentra definido en /etc/nagios3/conf.d/hostgroups_nagios2.cfg y nos permite chequear Web servers que escuchen en el puerto 80.
# host windows con agente
define host {
  use generic-host
  host_name winagent
  alias Windows Server, File Server y Web service
  address 192.168.0.4
  hostgroups remote-agent
}

# host sin agente
define host {
  use generic-host
  host_name noagent
  alias Servidor sin agente
  address 192.168.0.20
}

# host en internet
define host {
  use generic-host
  host_name itfreekzone
  alias Web server en internet
  address 10.0.0.10
  hostgroups http-servers
  check_command check_http
  check_interval 5
}
Nótese que en el servidor itfreekzone agregué el atributo check_command. Dado que el firewall no nos permite realizar pings a internet, es necesario encontrar una alternativa para detectar que el host está online, por ello utilicé check_http. También definí un nuevo intervalo de chequeos (por defecto era 1), para incrementar la distancia entre sucesivos checks y así no estar enviando requests continuamente a Internet.

La definición anterior ya nos alcanza para los chequeos en linuxagent e itfreekzone, pero todavía nos queda trabajo por hacer para monitorear al resto. Pasemos a definir los servicios que nos faltan.

Como comenté anteriormente, en winagent deseamos chequear que el servicio MpsSvc está levantado. Agregamos entonces la siguiente definición:
define service {
  use generic-service
  service_description Check Firewall Windows
  check_command check_nrpe_1arg!check_firewall_service
  host_name winagent
}
En la definición se ve que el servicio se aplica solamente al host winagent, y se llama el alias predefinido check_firewall_service.
Ahora, en el host windows, resta chequear CIFS y el Web Service:
define service {
  use generic-service
  service_description Check Web service en puerto 81
  check_command check_http_port!81
  host_name winagent
}

define service {
  use generic-service
  service_description Check CIFS
  check_command check_tcp!445
  host_name winagent
}
Como se observa, para chequear el web service utilizamos el comando que definimos anteriormente (check_http_port), mientras que para chequear CIFS, simplemente realizamos una conexión TCP al puerto 445. Existen plugins específicos para un chequeo más a fondo del servicio CIFS, pero para nuestro ejemplo alcanza.

Qué resta? chequear el serivicio NN en el host noagent. En este caso también utilizaremos check_tcp, nada mágico:
define service {
  use generic-service
  service_description Check Servicio NN
  check_command check_tcp!4444
  host_name noagent
}
Ok, tenemos los hosts y los servicios a chequear. Ahora, a quién y cómo enviamos las alertas?
Por defecto las alertas se envían al grupo admins (ver /etc/nagios3/conf.d/generic-host_nagios2.cfg), el cual las envía por mail al contacto root@localhost (ver /etc/nagios3/conf.d/contacts_nagios2.cfg). Definamos un nuevo contacto que pertenezca al grupo admins, pero al cual se le envíen solamente estados críticos y recoveries:
define contact {
  contact_name demasiadovivo # mi nombre
  alias d3m4s1@d0v1v0 # mi alias
  service_notification_period 24x7 # indico que ante caída de servicios me notifique en cualquier momento de la semana
  host_notification_period 24x7 # indico que ante caída del host me notifique en cualquier momento de la semana
  service_notification_options c,r # solo notificarme servicios en estados críticos (c) y recoveries (r)
  host_notification_options d,r # solo notificarme host caído (d) y recoveries (r)
  service_notification_commands notify-service-by-email # notificarme cambios en los servicios por mail
  host_notification_commands notify-host-by-email # notificarme cambios en el host por mail
  email demasiadovivo@itfreekzone.com # mi dirección de mail
  contactgroups admins # me agrego al grupo de contacto admins.
}
Con esto terminamos la definición. Un restart del servicio Nagios para que tome la nueva configuración y ya estamos:
  # /etc/init.d/nagios3 restart

En caso que algo haya quedado mal definido, Nagios lo indicará con un error y el servicio no iniciará.

Fue difícil? bueno, hasta que aprendemos la terminología, la estructura de objetos y la forma de definir todo, puede que si. Luego es tan simple como agregar definiciones. Por suerte es bastante intuitivo =)


Referencias

- Nagios Core Documentation
- about NSClient++
- Using NSClient++ from nagios with check_nrpe
- Installing Nagios On Debian Lenny And Monitoring A Debian Lenny Server
Tips: recibir mensajes SMS online
Desde hace tiempo, la mayoría de los sites requieren una dirección de email válida para poder registrar un usuario, a la cual envían un código de confirmación para terminar la validación. Si bien esto sigue siendo igual en la mayoría de los casos, cada vez más sitios empiezan a requerir algo más... un número de celular. Estos sites envían al número ingresado un código de confirmación, el cual hay que ingresar para validar al usuario.
En diferentes sites el número de celular es opcional y permite autenticación de dos vías, lo cual refuerza el sistema de autenticación, pero en otros es mandatorio colocar el número.

Los paranoicos como yo (o los usuarios que todavía desean poseer un mínimo de privacidad), no deseamos colocar el condenado número para que después la página pueda, como mínimo, enviarnos SPAM. Por ello me puse a buscar alguna alternativa que me permita recibir mensajes en un número online. Así fue como llegué al excelente artículo How to receive SMS online to bypass SMS verification? 
El artículo resume cuáles páginas permiten la recepción de SMSs online. Las mismas proveen una serie de números, controlados por ellos, los cuales están aptos para recibir SMSs internacionales. Cuando se recibe un mensaje, el mismo es agregado en la web para que pueda ser leído.
Las alternativas más simples de utilizar (digo simples porque no necesitan creación de usuario) son Receive-SMS-Online y ReceiveSMSOnline. De estas, la que a mi me funcionó es la primera, utilizando los números de Noruega. En el resto de los números no pude recibir mensajes. La ventaja adicional de la primera es que separa los SMS recibidos en cada número en páginas diferentes.
La tercer página citada en el artículo es Pinger, la cual pintaba bien en su descripción, pero tampoco pude recibir mensajes. La cuarta requiere justamente lo que no quería originalmente, un número de celular. No se por qué el autor colocó ésta en la lista, siendo que no es la idea del artículo. La última citada es para recibir faxes y mensajes de voz, ya alejandose de los SMS, así que no la probé.

Adicionalmente a las del articulo, encontré Receive-SMS, similar a ReceiveSMSOnline en la cual se muestran los mensajes de todos los números en una misma págna.

Estas páginas son de mucha utilidad, pero no siempre servirán, dado que los sites no son tontos (bueno, no todos) y muchos controlan los números de cel que ya validaron códigos y no permiten que sean utilizados nuevamente.

Me pareció interesante listar estas páginas porque, si bien existen cientos de páginas para el envío de mensajes online, no existen muchas para recibirlos.
Encriptar directorios con eCryptfs
Cuando uno transporta información sensible en medios removibles, o bien necesita resguardar los datos contenidos en su máquina, debe recurrir a algún sistema de encripción. Hasta hace un tiempo utilizaba TrueCrypt para realizar esta tarea, el cual es excelente, pero me interesé por probar algo más estándar y libre. Así fue como llegué a eCryptfs, un sistema que permite encriptar fácilmente directorios, que es lo que estaba necesitando. Además eCryptfs es POSIX-compliant, libre y se encuentra integrado en el kernel de Linux desde hace tiempo.

En este post les mostraré los pasos necesarios para instalar y utilizar eCryptfs. Mi configuración inicial se basó en el artículo How To Encrypt Directories/Partitions With eCryptfs On Debian Squeeze.

En debian y derivados existe un paquete de utilidades para utilizar ecryptfs, el cual se instala ejecutando:
  # apt-get install ecryptfs-utils
Otras distribuciones tienen paquetes similares, sólo hay que buscar el equivalente.

Encryptar un directorio es tan simple como montarlo utilizando el tipo ecryptfs:
  # mount -t ecryptfs /data/crypt /data/crypt

Cada vez que se monte el directorio, ecrypfs consultará cuáles parámetros utilizar:
1- Tipo de clave:
  1) passphrase
  2) tspi
  eCryptfs permite utilizar tanto passphrase como TSPI (TCG Service Provider Interface).
2- Algoritmo para cifrar:
  1) aes: blocksize = 16; min keysize = 16; max keysize = 32
  2) blowfish: blocksize = 8; min keysize = 16; max keysize = 56
  3) des3_ede: blocksize = 8; min keysize = 24; max keysize = 24
  4) twofish: blocksize = 16; min keysize = 16; max keysize = 32
  5) cast6: blocksize = 16; min keysize = 16; max keysize = 32
  6) cast5: blocksize = 8; min keysize = 5; max keysize = 16
3- Tamaño en bytes de la clave a utilizar:
  1) 16
  2) 32
  3) 24
4- Decidir si se permitirá utilizar archivos sin encriptar dentro del directorio (plaintext passthrough). En la gran mayoría de los casos se elige que no, a menos que exista alguna razón muy específica para no hacerlo.
5- Decidir si encriptar los nombre de archivos (filename encryption). Si no se desea que se pueda saber ni siquiera el nombre de los archivos contenidos en el directorio, debe seleccionarse sí en esta opción.
6- En el último paso se genera un "Filename Encryption Key (FNEK) Signature", el cual para un uso default (y avanzado también?) no es necesario cambiar.

Cuando se monta el directorio por primera vez, el sistema indicará que no encuentra el signature en la máquina y preguntará si desean almacenarlo. Si no se desea que cada vez que se monte el directorio el sistema pregunte esto, elegir que se almacene el signature.

Una vez montado el directorio, los archivos se acceden de la misma manera que cualquier otro archivo del filesystem. Si se desmonta, los archivos se ven con nombres codificados y no se pueden acceder.


eCryptfs también provee la posibilidad de automontar directorios o particiones editando fstab. Para hacerlo debe colocarse la passphrase en un archivo, el cual se utiliza como parámetro en las opciones de montaje. Algo interesante es que de esta forma se puede copiar el archivo con la clave en un pen drive, con lo cual se podrá acceder a los archivos utilizando el pen-drive. La forma de hacerlo está muy bien explicada en el HowTo de referencia.

Algo a destacar es que este tipo de encripción no protege completamente los datos. Como se observa en la imagen de arriba, si bien los nombres de los archivos no se ven, si se distingue entre directorios y archivos, y los atributos no cambian (fecha de creación, owner, etc). El simple hecho de contar con esta información puede ser suficiente en algunos casos.
Mi resumen de la ekoparty 2012
Después de 2 años deseando ir, por fin se me dio y pude asistir a mi primer ekoparty, la recientemente finalizada ekoparty 2012, y la verdad que volví muy satisfecho. Si bien ya fui sabiendo que las charlas que se realizan en este evento son de muy buen nivel, la verdad es que superaron ampliamente mis expectativas. Los disertantes fueron de lujo y las charlas de muy buen contenido, mostrando vulnerabilidades nuevas, no publicadas en ningún lugar, así que fue un honor poder estar allí para presenciarlo.
No he ido a ninguna otra conferencia de este estilo, así que no tengo punto de comparación, pero por lo que he visto siguiendo otras como Black Hat y Defcon, creo que tenemos localmente un congreso de muy buen nivel.
Fui a todas las presentaciones, y por supuesto que tengo mis favoritas, así como algunas que no me llegaron tanto, ya sea porque yo no tenía el background suficiente para seguirlas, o porque al disertante le costaba transmitir las ideas, pero en general todas fueron muy buenas.
Algo que me sorprendió gratamente es la cantidad de investigación del tema que se realiza en Argentina, mostrando que si se nos da la posibilidad (económica y/o laboral) somos capaces de lograr muy buenos resultados. Los disertantes argentinos estuvieron en un gran nivel.

En fin, para los que no pudieron asistir, les dejo un pequeño resumen de las charlas que más me gustaron, lo cual no quiere decir que el resto fueran malas, sino que yo no pude sacarles tanto el jugo. Igualmente como verán, me gustaron casi todas =P

Cyberwar para todos: Cesar Cerrudo hizo un buen resumen y análisis (con muy buen humor) de lo que conocemos como Cyberwars. La presentación pretendía demistificar un poco las acusaciones continuas sobre quién ataca a quién, tratando de que tomemos conciencia que si bien los países se acusan entre sí sobre los ataques cybernéticos, es casi imposible determinar el origen real de los mismos. Además habló sobre el (nulo?) nivel de seguridad informática que tenemos en Argentina, esperanzado de que en algún momento quienes nos gobiernan tomen conciencia de la necesidad de contar con mecanismos para defendernos ante un eventual cyberataque.

Inception of the SAP Platform's Brain: Attacks to SAP Solution Manager: si bien no manejo mucho SAP, conozco la infraestructura y funcionamiento básico de este sistema, por lo cual esta charla me resultó muy útil. Juan Perez Etchegoyen nos habló de cómo tomar el control de SAP partiendo del componente que nuclea todas las conexiones: SolMan. A través de la presentación demostró cómo partiendo de un mandante sin privilegios y utilizando cuentas default o alguna vulnerabilidad específica, podía conectarse a SolMan mediante conexiones confiables (trusted) y tomar el control del mismo, para luego acceder al ambiente productivo. La joyita de la presentación (a mi gusto) fue utilizar Bizploit (herramienta de Onapsis) para tomar el control de un server *nix donde se encontraba instalado SAP =)

One firmware to monitor 'em all: Andrés Blanco y Matias Eissler hicieron un excelente trabajo de ingeniería inversa para poder inyectar código malicioso en firmware de placas wireless Broadcom, utilizadas por diferentes marcas en sus dispositivos (Apple, Samsung, Nokia, etc). Los muchachos partieron de un pedazo del driver instalado en el sistema de archivos del dispositivo para luego tomar control e instalar su propio código en el firmware de diferentes dispositivos. Debido a que el driver de estas placas es similar en todos los dispositivos, con lograr diseccionar el de uno, les es posible infectar a todos.

HTExploit - Bypassing your htaccess and beyond!: Esta turbo talk fue una de las que más me sorprendió debido a las implicaciones de lo que encontraron tomando como base algo muy simple. Maximiliano Soler y Matias Katz nos trajeron una herramienta (HTExploit) que mostraron en el último BlackHat de Las Vegas, la cual les permite acceder a páginas PHP cuyo acceso está restringido mediante archivos .htaccess. La falla que explota esta herramienta es que muchos archivos htaccess limitan el acceso utilizando la sentencia "Limit GET, POST", lo cual si bien limita el acceso mediante estos métodos, no restringe otros. Dado que PHP asume el método GET siempre que se utilice un método que desconozca, si un atacante utiliza, por ejemplo, el método PEPE, el mismo podrá bypassear el control de Apache y obtener las páginas... un lujo.

Bitcoin, MavePay and the future of cryptocurrencies: esta charla presentada por Sergio Lerner (creo que nada que ver con Alejandro Lerner...) me gustó porque desconocía este sistema de pagos P2P. Como fanático de sistemas P2P, conocer este Bitcoin me interesó mucho como un posible área de investigación. Sergio habló sobre distintos ataques que se pueden realizar para robar "dinero virtual" (Bitcoins) en esta red, además mostró distintas modificaciones sobre las que está trabajando (MavePay) para hacer al sistema más resistente a ataques, desmotivando el robo, favoreciendo el buen uso del sistema para obtener dinero de forma legal.

Fuzzing DTMF Input Processing Algorithms: si hay algo que me encanta son los ataques "locos", y este es uno de ellos. Rahul Sasi demostró cómo realizar ataques contra sistemas de reconocimiento de voz o pulsaciones de teclado, utilizados en telefonía (DTMF). Si bien no demostró como hacerlo, eventualmente podría realizar inyecciones SQL haciendo un simple llamado telefónico, o bien voltear todo un sistema bancario o de atención al cliente... realmente muy loco.

Cryptographic flaws in Oracle Database authentication protocol: en esta presentación, Esteban Fayo demostró vulnerabilidades en los protocolos nativos de autenticación en bases de datos Oracle 10 y 11. Cuando se elige utilizar la autenticación nativa de Oracle, es posible obtener, en dichas versiones de base de datos, el hash de las contraseñas almacenado en el session key enviado por el servidor en el handshake. Para hacerlo, debe contarse con el nombre de una base de datos y un nombre de usuario, que deberá obtenerse mediante otra técnica. Una vez que se obtiene dicho hash, es posible obtener la contraseña mediante un ataque offline, ya sea por diccionario o fuerza bruta. Con esto se reduce el trabajo de obtener una contraseña a romper un hash. La forma de obtener dichos hashes varía dependiendo de si se utiliza la versión 10 o la 11, según demostró Esteban en su presentación.

Satellite baseband mods: Taking control of the InmarSat GMR-2 phone terminal: probablemente la presentación con más humor de toda el congreso, donde Alfredo Ortega y Sebastián Muñiz mostraron los resultados obtenidos al jugar con un teléfono satelital, realizando ingenería inversa sobre el mismo de modo de modificar el firmware y así para poder sniffear e inyectar tráfico enviado entre el teléfono y el satélite. Realmente un trabajo excelente el realizado por este par que lograron el interés de todos a través de una presentación con mucho humor de por medio, algo que siempre ayuda a distender y llegar mejor a la audiencia.

Welcome to your secure /home, $user: un gusto personal el haber podido conocer a uno de los editores del blog Security By Default, Lorenzo Martinez Rodriguez, blog que sigo desde hace tiempo. Lorenzo presentó, también con muchísimo humor de por medio, las modificaciones que realizó sobre los sistemas instalados en su propio hogar para obtener en 2012 la casa del futuro. Mostró cómo es posible tener un hogar más seguro mediante grabación de videos en los momentos adecuados, detección de movimiento, detección facial para reconocer a las personas que ingresan en el hogar (OpenCV haar classifier cascade), detección de presencia mediante bluetooth, interacción con la alarma mediante internet, así como automatizar ciertas tareas llevadas a cabo diariamente. Sin dudas, una de las presentaciones más entretenidas de la jornada.

SinFP3: More Than A Complete Framework for Operating System Fingerprinting: si bien el fingerprinting es algo bastante conocido, me resultó interesante conocer, de la mano de alguien que lleva varios años en el tema, cómo se trabaja para distinguir y lograr la mejor precisión posible detectando sistemas operativos, tanto pasiva como activamente. Patrice Auffret es alguien que trabaja desde hace tiempo con SinFP3, una herramienta que vi en Backtrack en algún momento pero que reconozco nunca utilicé. Esta fue una de esas charlas que te dejan con ganas de contribuir y trabajar un poco en este tipo de detecciones.

4140 ways your alarm system can fail: presentación realizada por Babak Javadi y Keith Howell que nos introdujo al mundo de los sistemas de alarma, esos que utilizamos en nuestros hogaras y en los que deberíamos (?) confiar.  Al introducirme en un mundo que desconocía, realmente me dejaron con un sentimiento de mucha inseguridad (y eso que trabajo en seguridad...) al mostrarnos lo fácil (y cuando digo fácil, es FACIL) que es deshabilitar un sistema de alarmas una vez que se conoce su funcionamiento. Estos muchachos mostraron en vivo como podían desactivar alarmas mediante diferentes técnicas, como realizar fuerza bruta sobre los códigos del centro de mandos, puenteo de terminales, e inyección de tráfico wireless, entre otras cosas. Otra de las tantas buenas presentaciones de este congreso, que dejan mucho información interesante al asistente.

VGA Persistent Rootkit: Nicolás Economou y Diego Juarez nos mostraron el resultado de su trabajo con placas de video que tiene implicancias muy perturbadoras, dado que es poco y nada lo que podremos hacer si un atacante nos infecta. El trabajo realizado fue inyectar código malicioso en el firmware de las placas de video (mediante un upgrade utilizando programas provistos por los fabricantes), de forma que el malware tomará el control de nustra máquina antes de que se cargue cualquier otro sistema... creepy! Nicolás y Diego realizaron ingeniería inversa para agregar código en el bloque de memoria libre de las placas y llamarlo desde el código "legal" del controlador. Además trabajaron para hokearse en la interrupción 10h y lograr que el BIOS no elimine lo inyectado al cargar el sistema operativo. Todo esto fue mostrado en vivo, con algunos mínimos contratiempos ;) y nos dejaron muy sorprendidos. Un aplauso para estos muchachos.

Dirty use of USSD Codes in Cellular Network: otra charla de las que categorizo como "locas" con implicancias TERRIBLES para la telefonía móvil. Ravi Borgaonkar nos introdujo al mundo de los códigos USSD, muy utilizado en Europa y en su India natal, aunque no tannnn conocido en Argentina. Describiría los USSD Codes como similares a los web services, donde mediante un mensaje de texto una persona puede obtener servicios de distintos proveedores. Ravi demostró un exploit que le permite bloquear tarjetas SIM de smartphones Android (todas las versiones), tan solo visitando un link! Como si esto no fuera poco, también demostró como formatear a su estado de fábrica un celular con Android mediante un link, y cómo hacerlo mediante la lectura de un tag NFC! Un lujaso contar con este investigador que nos dejó a todos asombrados con su trabajo. Una de las charlas más aplaudidas de la jornada, algo muy merecido.

The CRIME Attack: la frutilla del postre fue la charla de Juliano Rizzo y Thai Duong quienes una vez más pudieron contra SSL/TLS, logrando obtener cookies en de una conexión encriptada, con un ataque similar al que presentaron el año pasado (BEAST). En esta ocasión, Juliano y Thai explotaron una vulnerabilidad introducida al utilizar compresión en TLS, la cual también está presente al utilizar el protocolo SPDY (reemplazo de HTTP introducido por Google) que también comprime el contenido de las conexiones. El exploit se basa en realizar un session hijack de la víctima para generar tráfico desde la misma contra una página web que utilice TLS (como por ejemplo twitter) y observar el tamaño de los paquetes comprimidos enviados por el servidor. Dado que los paquetes enviados están especialmente armados por el atacante, mediante la observación del tamaño de diferentes request comprimidos, es posible inferir de a un byte el contenido de la cookie encriptada. Los muchachos demostraron en vivo cómo obtener una de las cookies de twitter en pocos minutos, aunque debido a una modificación introducida a último momento por Thai antes de la presentación, no les permitió obtener la otra cookie necesaria para lograr una autenticación exitosa. Igualmente el exploit quedó demostrado al poder obtener una de las cookies y seguramente liberarán el código actualizado para poder llevar a cabo un ataque completo. Un gustaso poder ver a estos dos en acción luego de seguir su trabajo en las últimas dos ekoparty.

Resumiendo, me vine muy MUY contento con lo visto en el congreso y espero poder volver el año que viene. Quién sabe, tal vez alguna día tendré el honor de asistir como speaker =)
Apache kerberizado - Single Sign On (AD y MIT Kerberos)

Una funcionalidad que se está utilizando mucho en las empresas es el Single Sign On (SSO), esto es, permitir que los usuarios se logueen una vez y accedan a todos los sistemas que necesiten, sin tener que ingresar nuevamente sus credenciales. Más allá de las graves implicaciones de seguridad que esto acarrea, es algo que se está utilizando mucho y que los administradores deben conocer.
El SSO no es otra cosa que kerberizar servicios, es decir, autenticar el usuario, obtener un ticket, y luego solicitar servicios con el ticket de sessión. En el caso de los servicios Web, MS integra fácilmente IIS con la autenticación de Active Directory. Apache, por su parte, también brinda esta posibilidad.
En este artículo mostraré los pasos necesarios para kerberizar Apache, es decir, permitir que un usuario acceda a un sitio web sólo si antes se autentica utilizando kerberos. La configuración mostrada es sobre un servidor GNU/Linux, y describe los pasos para kerberizar Apache tanto en una red con AD, como en una de MIT Keberos.
Se asume que el lector tiene ciertos conocimientos básicos de kerberos. Sino pueden leer los artículos que escribí anteriormente sobre el tema:
- Instalación de MIT Kerberos
- Configurar PAM para utilizar kerberos
- Autenticar con kerberos y almacenar información de usuarios con LDAP en GNU/Linux
- OpenLDAP kerberizado

Yendo al grano, los pasos de configuración son los siguientes:

1. Crear un usuario en el dominio que servirá como principal para el servicio HTTP (solicitud de tickets de servicio). El uso es como el de una cuenta de máquina.
  En AD:
    - Abrir Active Directory Users and Computers (ADUC)
    - Ir al dominio donde se creará el usuario.
    - Click derecho en Users
    - Elegir New -> User
    - Completar los datos y finalizar.

  En MIT Kerberos:
      # kadmin.local
      Authenticating as principal root/admin@DVPEM.ORG with password.
      kadmin.local: addprinc -randkey HTTP/apache.dvpem.org@DVPEM.ORG
      WARNING: no policy specified for HTTP/apache.dvpem.org@DVPEM.ORG; defaulting to no policy
      Principal "HTTP/apache.dvpem.org@DVPEM.ORG" created.
      donde -randkey permite generar un password random.

2. Mapear el servicio HTTP con el usuario recién creado y exportar el keytab para ser utilizado en el servidor:
    En AD:
      ktpass -princ HTTP/apache.dvpem.org@DVPEM.ORG -mapuser DVPEM\pruebaapache -ptype KRB5_NT_PRINCIPAL -pass prueba -out C:\apache.keytab
    donde:
      -princ indica el nombre que tendrá el principal (servicio HTTP)
      -mapuser indica el usuario con el que se mapea el servicio
      -ptype especifica el tipo del principal
      -pass asigna un password para el principal. Si utilizan un asterisco (*) el sistema pregunta el password.
      -out especifica el nombre del archivo keytab a generar
    Dependiendo del tipo de encripción soportado por el servidor y el cliente, puede ser necesario especificar el uso de encripción débil. Esto se realiza con:
      -mapop set +desonly
      -crypto all o bien -crypto DES-CBC-MD5

    En MIT Kerberos:
      kadmin.local: ktadd -k /root/apache.keytab HTTP/apache.dvpem.org
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type ArcFour with HMAC/md5 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type Triple DES cbc mode with HMAC/sha1 added to keytab WRFILE:/root/apache.keytab.
      Entry for principal HTTP/apache.dvpem.org with kvno 5, encryption type DES cbc mode with CRC-32 added to keytab WRFILE:/root/apache.keytab.

3. Copiar el keytab al servidor donde se encuentra Apache instalado. Cambiar el dueño del archivo y restringir los permisos. Si por ejemplo se copia el archivo a /etc/apache2/apache.keytab, ejecutar lo siguiente:
    chown www-data:www-data /etc/apache2/apache.keytab
    cmod 400 /etc/apache2/apache.keytab

4. Instalar en el servidor web las utilidades de kerberos y el módulo de Apache, y habilitar el módulo:
    # apt-get install krb5-{config,user} libapache2-mod-auth-kerb
    # a2enmod mod_auth_kerb

5. Configurar los valores de realm, KDCs, y dominios para kerberos. Esto es, editar las siguientes líneas del archivo /etc/krb5.conf
  - En la sección libdefaults setear el nombre del realm:
      default_realm = DVPEM.ORG
  - En la sección realms, indicar cuáles son los servidores KDC para nuestro realm:
      DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }
  - En la sección domain_realm, agregar los mapeos de dominio con realms:
      .dvpem.org = DVPEM.ORG
      dvpem.org = DVPEM.ORG

6. Testear si kerberos funciona correctamente. Para ello, solicitar un ticket de usuario, para un usuario válido del dominio:
    $ kinit demasiadovivo@DVPEM.ORG
    $ klist

7. Agregar la siguiente configuración a apache para el directorio que se desea autenticar con kerberos. En este ejemplo, la intención es autenticar el directorio /var/www/mipagina
    <Directory /var/www/mipagina>
      AuthType Kerberos
      AuthName "Kerberos Login"
      KrbMethodK5Passwd Off
      KrbMethodNegotiate On
      KrbAuthRealms DVPEM.ORG
      KrbServiceName HTTP
      Krb5KeyTab /etc/apache2/apache.keytab
      require valid-user
    </Directory>
donde:
  AuthType Kerberos: especifica el tipo de autenticación
  KrbMethodNegotiate On: habilita el uso de SPNEGO (GSSAPI-SASL)
  KrbMethodK5Passwd Off: deshabilita el uso de password para la autenticación. Esto puede causar problemas con browsers que no soportan SPNEGO, o máquinas que no se encuentran unidas al dominio. En estos casos puede setearse este valor en On, pero esto permite el uso de autenticación BASIC (muy insegura).
  KrbAuthRealms DVPEM.ORG: especifica el realm (o dominio)
  KrbServiceName HTTP: nombre del servicio
  Krb5KeyTab /etc/apache2/apache.keytab: donde se encuentra el keytab
  require valid-user: fuerza a que el usuario sea validado antes de acceder.

8. Chequear que el ticket provisto por el servidor contiene un tipo de encripción que es consistente con los valores configurado en el keytab:
  Obtener un ticket de servicio y listar los tipos de encripción:
    kvno HTTP/apache.dvpem.org@DVPEM.ORG
    klist -e
  Mostrar los tipos de encripción configurados en el keytab:
    klist -e -k -t /etc/apache2/apache.keytab
Si los valores no coinciden, el servicio no podrá ser utilizado.
NOTA: Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar errores en la autenticación.

9. Reiniciar Apache y probar la configuración accediendo a la página Web protegida con Kerberos.
Algo muy importante es que debe utilizarse el nombre DNS especificado en el keytab como nombre del servicio, dado que si se utiliza la IP o un alias, la autenticación no funcionará.

10. Errores, posibles causas y soluciones. A continuación se listan los errores con los que me topé al configurar el servicio y una explicación sobre cómo lo solucioné. Además incluí soluciones alternativas.
  krb5_get_init_creds_password() failed: Cannot resolve network address for KDC in requested realm
    - Verificar que tanto el registro A como el registro PTR del servidor se encuentren registrados. Si por ejemplo el nombre del servidor apache es apache.dvpem.org, debe ingresarse el registro PTR correspondiende a la IP de dicho servidor.
    - El parámetro KrbAuthRealms de Apache debe estar seteado correctamente. Recordar que en este parámetro se especifica el realm (dominio) en mayúsculas:
KrbAuthRealms DVPEM.ORG
    - Los kdc del dominio se encuentran seteados correctamente en el archivo /etc/krb5.conf. Un ejemplo de esta configuración es:
DVPEM.ORG = {
 kdc = kdc01.dvpem.org:88
 admin_server = kdc01.dvpem.org
 }

  failed to verify krb5 credentials: Server not found in Kerberos database
    - El principal utilizado esta mal configurado en el keytab creado o en el atributo KrbServiceName de la configuración de Apache.
    - Al acceder a la página debe utilizarse el nombre del servidor registrado en el keytab. Es decir, si el principal está designado para apache.dvpem.org, en el navegador debe utilziarse la dirección apache.dvpem.org.
   
  failed to verify krb5 credentials: KDC has no support for encryption type
    - El tipo de encripción aceptada por el servidor no es compatible con la encripción aceptada por el cliente, o bien los tipos de encripción configurados en el keytab no son compatibles con el servidor. Verificar obteniendo un ticket de servicio y la encripción soportada en el keytab:
      kvno HTTP/apache.dvpem.org@DVPEM.ORG
      klist -e
      klist -e -k -t /etc/apache2/apache.keytab
      Hay que tener en cuenta que Windows 7 y 2008 dejaron de aceptar por defecto la encripción con DES, algo que puede causar el error mencionado si se utilizan estos sistemas.
   
  gss_acquire_cred() failed: Unspecified GSS failure.  Minor code may provide more information (, )
    - Revisar si no se encuentra seteado el valor "Use Kerberos DES encryption for this account" en la cuenta del usuario utilizada para el pricipal.

 
Referencias

- Kerberos Module for Apache - Configuration
- Configure Apache to use Kerberos authentication
- Kerberos authentication with Apache in a multi-domain Active Directory
- Single Sign On with Kerberos using Debian and Windows Server 2008 R2
- Kerberos-Based SSO with Apache
- Using mod_auth_kerb and Windows 2000/2003/2008R2 as KDC
- Apache on Linux and Single-Sign-On with Active Directory
- Active Directory and Apache Kerberos authentication
- JBoss Doc - Chapter 5. Configuring Microsoft Active Directory
- Ktpass
Auditar grupos críticos y alertar por mail en Active Directory
Es muy importante para todo administrador de seguridad conocer en todo momento quienes tienen cuentas de usuario con privilegios elevados y "vigilarlos". A partir de esto se desprende que es todavía más importante saber cuando se otorgan privilegios a usuarios.
En todo dominio existen grupos de usuario utilizados por administradores o helpdesk que cuentan con mayores privilegios que los usuarios comunes, por obvias razones. El problema es cuando se asignan estos privilegios y no todos (o ninguno) los administradores están informados. El caso más riesgoso es cuando un atacante logra escalar privilegios gracias a algún exploit o vulnerabilidad conocida (se acuerdan de pass-the-hash?).
Active Directory posee grupos bien definidos con privilegios elevados, siendo "Domain Admins" el Dios supremo. Cada organización puede definir sus propios grupos, pero "Domain Admins" estará siempre presente como la autoridad máxima, así que debe estar auditado. Otros grupos de importancia son "Enterprise Admins", "Schema Admins" y "Backup Operators".
Este artículo brinda los pasos necesarios para auditar grupos en Active Directory y enviar mensajes de alerta por mail cuando un grupo crítico esté siendo modificado. De esta forma los responsables de Seguridad de la Información estarán notificados al instante cuando ocurra una brecha de seguridad donde un usuario escale privilegios en el dominio. Lo que se auditará serán inserciones y eliminaciones de usuarios en los grupos que corresponda.


Habilitar auditoría de grupos en AD

La auditoría de usuarios/grupos/workstations en AD se realiza de la misma manera que la auditoría de directorios. Para hacerlo hay que utilizar la herramienta "Active Directory Users and Computers" (ADUC). En esta debe dirigirse a View y tildar "Advanced Features" para poder ver las propiedades avanzadas de los objetos.
Con la opción habilitada, resta dirigirse a la unidad organizativa (OU) donde se encuentran los grupos a auditar. Tal vez deseen habilitar la auditoría para todos los usuarios, o para usuarios/grupos particulares. Para esta explicación habilitaremos la auditoría a todos los objetos de la OU Users. Entonces, dirigirse a la OU Users y abrir las propiedades, allí dirigirse a la pestaña Security y en esta dar al botón Advanced. En esta ventana dirigirse a la pestaña Auditing, dar al botón "Add...", escribir Everyone y dar Ok. En la lista de propiedades a auditar, tildar todo menos "Full control", "List contents", "Read all properties" y "Read Permissions" (las lecturas generan demasiados logs y no son de demasiada utilidad)

Lo que se hace con esta configuración es que cada vez que cualquier usuario (por eso se elige Everyone) modifique un objeto de la OU Users se genere una entrada en el log de Windows.

Probablemente se encuentren con que esta auditoría ya se encuentra habilitada y heredada de la configuración del dominio, pero si no es así, con los pasos anteriores podrán configurarla.


Hook al evento y envío de mail

Cuando el evento que deseamos auditar se dispare deberemos realizar alguna acción. Como comenté al principio, nuestra acción será enviar un mail a los encargados de la seguridad, y en el mismo colocaremos el contenido de la entrada de log que generó el evento.
Si bien es muy simple generar una tarea que envíe un mail avisando del evento, la información que puede contener el mismo es muy escueta y no sirve de mucho más que estar informado. Lo mejor es contar con un script que lea la entrada del log y envíe el mail con el contenido de la misma.


Script en PowerShell

En la mayoría de los blogs explican cómo utilizar la herramienta wevtutil para enviar la información de los logs en el mail cuando se ejecuta el evento. Wevtutil permite parsear los logs y obtener información, para lo cual es muy útil, pero para este caso, no lo es tanto. El problema es que estas soluciones se basan en crear un script que lee la última entrada del log que cumple con las condiciones del evento buscado, y de esta forma puede ocurrir que si dos o más eventos con las mismas características se generan en corto intervalo de tiempo, perdamos información.

La mejor solución que encontré es la explicada en el artículo Trigger a PowerShell Script from a Windows Event, a partir de la cual generé el siguiente script (luego de pelear un buen rato con PS), denominado eventreporter.ps1:

  # Script by demasiadovivo
  param($eventRecordID,$eventChannel)

  $event = Get-WinEvent -Logname $eventChannel -FilterXPath "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>"

  $smtp_server = "mailserver.ejemplo.com"
  $msg = New-Object Net.Mail.MailMessage
  $msg.From = "security_alert@ejemplo.com"
  $msg.To.Add("demasiadovivo@ejemplo.com")
  $msg.subject = "ALERTA! se hicieron cambios en grupo crítico"

  $data =$event.Message
  $data = [String]::join([environment]::NewLine, $data)
  $msg.body = $data

  $smtp = new-object Net.Mail.SmtpClient($smtp_server)
  $smtp.Send($msg)

Vayamos por partes para comprender su funcionamiento. El script primero obtiene los parámetros eventRecordID y eventChannel, donde eventRecordID es el valor que identifica la línea del log donde se encuentra el evento que disparó la acción, y eventChannel es el log donde se encuentra (System, Security, Application, etc). No confundir eventRecordID con eventID. El primero es el identificador de la entrada del evento, algo así como el número de línea dentro del log, mientras que eventID es el identificador que utiliza Windows para distinguir el tipo de evento (por ejemplo Logon). Estos valores los envía la tarea programada que se dispara con el evento, como veremos después.
El siguiente paso es obtener la entrada del log correspondiente al evento. Para ello se utiliza el comando Get-WinEvent y los valores de eventRecordID y eventChannel. El evento se obtiene con la consulta "<QueryList><Query Id='0' Path='$eventChannel'><Select Path='$eventChannel'>*[System[(EventRecordID=$eventRecordID)]]</Select></Query></QueryList>" que se encuentra en formato XML y utiliza el lenguaje XPath (http://en.wikipedia.org/wiki/XPath). Se utiliza XPath en las consultas porque internamente los logs se guardan en formato XML. Para entender un poco mejor cómo se arman consultas en este lenguaje, leer MSDN XPath Syntax.
Finalmente el script arma un mail con el contenido obtenido del log ($event.Message) y lo envía a las direcciones designadas. Una línea que puede llamar la atención es "[String]::join([environment]::NewLine, $data)". Me llevó más de 3 horas encontrar cómo hacer que el mensaje del log original conserve los enters, lo cual se logra a través de esa línea... en bash todo esto sería mucho más fácil...

Recuerden que para poder ejecutar scripts de PowerShell, primero deben cambiar la política de ejecución de la máquina. Esto se realiza ejecutando lo siguiente:
  Set-ExecutionPolicy RemoteSigned


Asignar una tarea al evento

Bien, ya activamos la auditoría de los grupos y tenemos el script a ejecutar cuando el evento ocurra. El siguiente paso es asignar la ejecución del script con el evento. Esto se hace a través de la herramienta "Computer Management". Hay que tener en cuenta en este punto que la tarea deberá agregarse en todos los controladores de dominio (DC), dado que las modificaciones de grupos podrían realizarse en cualquiera de ellos.

Como todo en el mundo MS, nada es tan directo y uno termina teniendo que utilizar algunas artimañas para lograr lo que desea. Para poder entregar al script los argumentos eventRecordID y eventChannel hay que hacer algunas modificaciones manuales a una tarea, como veremos a continuación.

Primero hay que crear la tarea que se ejecutará al producirse el evento. Para ello, dirigirse a "Task Scheduler -> Task Scheduler Library" dentro de "Computer Management". Allí dando click derecho se elige "Create Task..." y se obtiene la ventana de configuración de la tarea. A la misma habrá que asignar un nombre y opcionalmente una descripción. Como queremos que se ejecute en modo batch, hay que cambiar el usuario con el que se ejecutará la tarea, así que clickear el botón "Change User or Group..." y escribir "SYSTEM" (o bien crear un usuario con los privilegios suficientes para leer logs).
En la pestaña "Triggers" se agrega la condición que debe darse para que se ejecute el script. En ella debe crearse un nuevo Trigger con "New..." y elegir la opción "On an event" como disparador de la tarea. Luego elegir "Custom" en las settings y dar a "Edit Event Filter...". En esta ventana ir a la pestaña "XML", seleccionar "Edit query manually" y utilizar el siguiente código:
  <QueryList>
    <Query Id="0" Path="Security">
      <Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select>
    </Query>
  </QueryList>
Como se puede observar, la consulta es similar a la utilizada en el script, en formato XML y utilizando el lenguaje XPath para seleccionar los siguientes eventos:
- 4732/4733 se agregó/eliminó un usuario a un grupo local. Se utilizan en conjunto con el grupo "Backup Operators" que es local.
- 4728, 4729 se agregó/eliminó un usuario a un grupo global. Se utilizan en conjunto con los grupos "Domain Admins", "Schema Admins" y "Enterprise Admins" que son globales.
  NOTA 1: si en un futuro desean auditar algún grupo universal, los identificadores de eventos son 4756 para cuando se agrega, y 4757 para cuando se elimina un usuario del grupo.
  NOTA 2: para entender mejor la consulta, pueden observar la estructura XML de los eventos en MSDN Event Schema Elements.
Continuando en la pestaña "Actions", elegir "New" para agregar la ejecución del script. Dentro de la ventana emergente elegir la acción "Start a program", en el nombre del programa/script escribir "PowerShell.exe", y en la sección de argumentos escribir ".\eventreporter.ps1 -eventRecordID $(eventRecordID) -eventChannel $(eventChannel)", reemplazando el path del script por el que corresponda. Con esto ya termina la definición de la tarea y pueden dar OK para terminar.
Como se ve, se utilizan los parámetros eventRecordID y eventChannel en la llamada del script, los cuales se utilizan luego para obtener el identificador de la entrada. Acá es donde entra en juego la "magia" del administrador. Para variar, nada es coherente con las herramientas de MS y no es posible indicar, de forma directa, cómo asignar los valores a los parámetros... gracias MS!!! Por ello es necesario aplicar el siguiente artilugio.
Primero deben dar click derecho sobre la tarea recién creada, elegir la opción "Export" y guardar el XML en alguna ubicación. Supongamos que llamamos a este XML como el nombre de la tarea, "Eventos_criticos.xml". Una vez hecho esto, eliminen la tarea. Sí eliminen, ya la volveremos a crear a partir del XML.
Ahora abrir el XML recién generado con algún editor de texto y buscar la sección "<Triggers>". Dentro de la misma encontrarán la sección "<EventTrigger>". En ella colocar el siguiente código:
      <ValueQueries>
        <Value name="eventChannel">Event/System/Channel</Value>
        <Value name="eventRecordID">Event/System/EventRecordID</Value>
        <Value name="eventSeverity">Event/System/Level</Value>
      </ValueQueries>
es decir, la sección completa debe quedar:
  <Triggers>
    <EventTrigger>
      <Enabled>true</Enabled>
      <Subscription><QueryList><Query Id="0" Path="Security"><Select Path="Security">*[(System/EventID=4732) or (System/EventID=4733)] and *[EventData/Data [@Name='TargetUserName']='Backup Operators'] or *[(System/EventID=4728) or (System/EventID=4729)] and *[(EventData/Data[@Name='TargetUserName']='Domain Admins') or (EventData/Data[@Name='TargetUserName']='Schema Admins') or (EventData/Data[@Name='TargetUserName']='Enterprise Admins')]</Select></Query></QueryList></Subscription>
      <ValueQueries>
        <Value name="eventChannel">Event/System/Channel</Value>
        <Value name="eventRecordID">Event/System/EventRecordID</Value>
        <Value name="eventSeverity">Event/System/Level</Value>
      </ValueQueries>
    </EventTrigger>
  </Triggers>
Salvar los cambios en el XML.
Finalmente volvemos a crear la tarea a partir del XML modificado. Para ello ir a Task Scheduler, dar click derecho y elegir la opción "Import Task", la cual les permitirá buscar el archivo recién creado. Otra forma de hacer esto último es ejecutando desde consola el siguiente comando:
  C:\>schtasks /create /TN "Event Viewer Tasks\Eventos_Criticos" /XML Eventos_criticos.xml

Lo que se hizo aquí es indicarle a la tarea cuáles son los valores que debe utilizar para los parámetros eventChannel (Event/System/Channel), eventRecordID (Event/System/EventRecordID) y eventSeverity (Event/System/Level), que luego entregará al script creado en la sección anterior. No hay forma de hacer esto modificando la tarea desde el GUI, esta es la única manera... lindo verdad?...

En los otros controladores de dominio solamente deberán importar el XML recién creado y copiar el script a una ubicación donde el DC pueda ejecutar.


Acerca de...

Como comentario final solo me resta renegar una vez más contra MS. Algo tan simple como auditar un log, que en algún *nix sería cosa de dos minutos, se convierte en un dolor de cabeza. Siguiendo los pasos que describo en este artículo podrán hacerlo en dos minutos, pero encontrar la información necesaria para poder armar esto me llevó casi dos tardes. Windows es fácil de usar para el usuario final, pero cuando se quiere hacer algo semi-avanzado de administración te hace la vida imposible.
Dirán, me quejo pero lo uso. Y si, no me queda otra, desgraciadamente la gran mayoría de las organizaciones con una infraestructura IT mediana utilizan Active Directory, y para ser administrador de seguridad, necesitas conocer esta tecnología y hacer cosas como la que describí en este artículo. Lo único que espero es que en algún momento se tome conciencia y se deje de utilizar esta bosta para pasar a algo mejor.


Referencias

- Trigger a PowerShell Script from a Windows Event
- AD DS Auditing Step-by-Step Guide
- Getting event log contents by email on an event log trigger
- Email with event log attachment on an event log trigger
- MSDN XPath Syntax
- Event Schema Elements
- Attaching Tasks to Event Viewer Logs and Events
- PowerShell Cookbook - Chapter 23. Event Logs
- PowerShell Cookbook - Appendix C. XPath Quick Reference
Instalación y configuración básica de ModSecurity
Desde hace tiempo tengo ganas de instalar un Web Application Firewall (WAF) y siempre tuve ModSecurity en la mira. Hoy con un poco de tiempo, decidí darle una chance y jugar un rato.
ModSecurity es un módulo para Apache que permite analizar los pedidos en distintas fases del protocolo HTTP. De esta forma, es posible procesar los pedidos antes de ser entregados a la aplicación subyacente (por ejemplo, escrita en PHP), o luego de que se completó la ejecución. Con este sistema es posible prevenir ataques de SQL Injection, XSS, LDAP Injection, File Injection, Session Fixation, etc.
Como es un módulo para Apache, es muy fácil de instalar, aunque requiere algunos pasos para su configuración. En este artículo explicaré cómo instalar, configurar y poner en funcionamiento ModSecurity. La explicación culmina con una configuración básica de ModSecurity trabajando en modo monitoreo, es decir, sólo loggea los eventos, no actúa de forma activa. Por supuesto que la verdadera utilidad de un WAF es la prevención de los ataques, pero para evitar falsos positivos que afecten la funcionalidad de los sites que se encuentren activos, es preferible comenzar en un modo pasivo e ir habilitando reglas a medida que se va conociendo el tráfico.

Instalar ModSecurity en debian, una vez que ya está instalado Apache, es tan simple como ejecutar:
  apt-get install libapache2-modsecurity modsecurity-crs

El paquete modsecurity-crs contiene el conjunto de reglas core creado por OWASP. ModSecurity es simplemente el motor del firewall y todo firewall necesita reglas para funcionar. Las reglas creadas por OWASP abarcan todos los ataques más comunes de la web y por supuesto que son gratuitas de utilizar.

Una vez instalado el módulo, debe activarse ejecutando:
  a2enmod mod-security

En el paquete de debian encontré un error al intentar cargar el módulo, dado que las librerías estaban mal referenciadas en el archivo .load. Para arreglar el problema, debe modificarse la línea Load del archivo /etc/apache2/mods-enabled/modsecurity.load para que quede
  LoadFile /usr/lib/libxml2.so.2
en lugar de "LoadFile libxml2.so.2".

Para probar que el módulo está instalado correctamente, renombrar el archivo de configuración default:
  mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
reiniciar Apache:
  /etc/init.d/apache2 restart
y ejecutar nikto:
  nikto -host http://localhost
Puede utilizarse cualquier otra herramienta que genere tráfico malicioso, nikto es solamente un ejemplo.

Con esto ya debería existir el archivo de auditoría /var/log/apache2/modsec_audit.log, donde deberían estar las entradas generadas por nikto.

Como explicaba al principio, por si solo ModSecurity no hace nada, necesita ser alimentado con reglas, para ello el paquete modsecurity-crs. Si ya está instalado, las reglas se encontrarán en /usr/share/modsecurity-crs/. Este directorio está dividido en 5 subdirectorios:
  activated_rules
  base_rules
  experimental_rules
  optional_rules
  slr_rules
Los nombres explican por si mismos el contenido. La idea es colocar en activated_rules links simbólicos a las reglas que deseemos activar, como por ejemplo "/usr/share/modsecurity-crs/base_rules/modsecurity_crs_41_sql_injection_attacks.conf". Todo dependerá de qué deseen hacer, es una cuestión organizativa.
Para una configuración básica, simplemente incluiremos todo el directorio base_rules, en lugar de incluir activated_rules y agregar de a una las reglas. También debe incluirse el archivo de configuración modsecurity_crs_10_config.conf, que cuenta con seteos básicos. Esto se realiza editando el archivo "/etc/apache2/mods-enabled/mod-security.conf" y agregando las siguientes líneas:
  Include "/usr/share/modsecurity-crs/modsecurity_crs_10_config.conf"
  Include "/usr/share/modsecurity-crs/base_rules/*.conf"
es decir, el archivo debería quedar como a continuación:
<ifmodule security2_module="">
        SecDataDir /var/cache/modsecurity
        Include "/etc/modsecurity/*.conf"
        Include "/usr/share/modsecurity-crs/modsecurity_crs_10_config.conf"
        Include "/usr/share/modsecurity-crs/base_rules/*.conf"
</ifmodule>

Cada vez que realicen un cambio en la configuración deberán cargar nuevamente Apache. Claro que no es necesario reiniciarlo, también es posible hacer un reload más sutil y no matar las conexiones existentes:
  /etc/init.d/apache2 graceful

Un error bastante común al ejecutar las reglas de OWASP es el exceso en el límite de la librería PCRE que viene por defecto en el archivo modsecurity.conf. El error contiene el siguiente mensaje:
  Execution error - PCRE limits exceeded
Estos límites se configuran mediante las directivas SecPcreMatchLimit y SecPcreMatchLimitRecursion (modsecurity - Configuration Directives) y previenen que expresiones regulares mal formadas se salgan de control. Aumenten con cuidado este valor, tratando de que las reglas se ejecuten, pero sin asignar un número exorbitante. Por ejemplo, un valor que a mi me funcionó bien es 5000:
  SecPcreMatchLimit 5000
  SecPcreMatchLimitRecursion 5000

Con esto ya cuentan con ModSecurity habilitado y funcionando en modo "sniffer", dado que sólo revisa el contenido y loggea los ataques. A partir de aquí deberán analizarse dichos logs y decidir qué tipo de prevención aplicar. Hay que tener cuidado con los falsos positivos, dado que pueden influir en el correcto funcionamiento de los sites que intentamos proteger.

Una idea interesante es utilizar ModSecurity en conjunto con el módulo mod_proxy, es decir, utilizar Apache como un reverse Proxy y proteger con una sola instancia de ModSecurity varios web servers que se encuentren detrás.


Referencias

- ModSecurity Reference Manual
- Category: OWASP ModSecurity Core Rule Set Project
- mod_security on Apache