Mostrando entradas con la etiqueta hardening. Mostrar todas las entradas
Mostrando entradas con la etiqueta hardening. Mostrar todas las entradas

04 septiembre 2015

SUIDGuard, extensión de seguridad para OSX

SUIDGuard es una extensión (modulo de kernel) de OSX Yosemite y que implementa varias mitigaciones genéricas en este sistema operativo.

El autor, Stefan Esser, es un hacker muy reputado por sus exploits para IOS y en el mundo del PHP, para el que creó un parche "Suhosin" que previene de las vulnerabilidades más típicas de este lenguaje.

En cuanto a SUIDGuarda, las protecciones  de las que dispone son:

  • Proteger los ficheros binarios SUID/SGID de las variables de entorno del tipo DYLD_ modificando la cadena de caracteres por XYLD. Por aclarar a los foráneos de OSX, estas variables son el dynamic linker, equivalente a las LD_PRELOAD del mundo Linux. Un exploit funcional (ya parcheado) lo creo el propio autor de esta herramienta. DYLD_PRINT_TO_FILE.
  • Proteger el flag O_APPEND para que no sea deshabilitado por otro usuario, este flag es generalmente utilizado por aplicaciones que almacenan registros y que cada vez que abren un manejador no sobreescriben su contenido.
  • Deshabilitar la ejecución de los binarios ejecutables sin segmento __PAGEZERO, que evitará un determinado tipo de exploits (kernel NULL derefs) como por ejemplo tpwn.
La forma más sencilla de instalar la extensión es descargar el paquete DMG disponible en su GitHub y ejecutarlo. Ya que al ser un módulo de kernel, si se compila, habrá que lidiar con la protección del propio sistema operativo para añadir módulos no firmados.

Una vez instalado, se puede comprobar con el comando "kextstat" y si detecta algún exploit aparecerá en el registro de "dmesg" una línea como la que se muestra en la imagen avisando de que ha neutralizado una ejecución.

Comprobación del funcionamiento de SUIDGuard.

Leer más...

19 mayo 2015

Buenas prácticas de seguridad en Docker



Docker es una plataforma abierta que permite construir, portar y ejecutar aplicaciones distribuidas, se basa en contenedores que corren en Linux y funcionan tanto en máquinas físicas como virtuales simplemente usando un runtime. Está escrito en Go y usa librerías del sistema operativo así como funcionalidades del kernel de Linux en el que se ejecuta. Consta de un engine con API RESTful y un cliente que pueden ejecutarse en la misma máquina o en máquinas separadas. Es Open Source (Apache 2.0) y gratuito.

Los contenedores existen desde hace muchos años, Docker no ha inventado nada en ese sentido, o casi nada, pero no hay que quitarles mérito, están en el momento adecuado y aportan las características y herramientas concretas que se necesitan en la actualidad, donde la portabilidad, escalabilidad, alta disponibilidad y los microservicios en aplicaciones distribuidas son cada vez más utilizados, y no sólo eso, sino que también son mejor entendidos por la comunidad de desarrolladores y administradores de sistemas. Cada vez se desarrollan menos aplicaciones monolíticas y más basadas en módulos o en microservicios, que permiten un desarrollo más ágil, rápido y a la vez portable. Empresas de sobra conocidas como Netflix, Spotify o Google e infinidad de Start ups usan arquitecturas basadas en microservicios en muchos de los servicios que ofrecen.

Te estarás preguntando ¿Y no es más o menos lo mismo que hacer un chroot de una aplicación? Sería como comparar una rueda con un coche. El concepto de chroot es similar ya que se trata de aislar una aplicación, pero Docker va mucho más allá, sería un chroot con esteroides, muchos esteroides. Por ejemplo, puede limitar y controlar los recursos a los que accede la aplicación en el contenedor, generalmente usan su propio sistema de archivos como UnionFS o variantes como AUFS, btrfs, vfs, Overlayfs o Device Mapper que básicamente son sistemas de ficheros en capas. La forma de controlar los recursos y capacidades que hereda del host es mediante namespaces y cgroups de Linux. Esas opciones de Linux no son nuevas en absoluto, pero Docker lo hace fácil y el ecosistema que hay alrededor lo ha hecho tan utilizado. 

Adicionalmente, la flexibilidad, comodidad y ahorro de recursos de un contenedor es mayor a la que aporta una máquina virtual o un servidor físico, esto es así en muchos casos de uso, no en todos. Por ejemplo, tres servidores web para un cluster con Nginx en una VM con una instalación de Linux CentOS mínima ocuparía unos 400MB, multiplicado por 3 máquinas sería total de uso en disco de 1,2 GB, con contenedores serían 400MB las mismas 3 máquinas corriendo ya que usa la misma imagen para múltiples contenedores. Eso es sólo por destacar una característica interesante a nivel de recursos. Otro uso muy común de Docker es la portabilidad de aplicaciones, imagina una aplicación que solo funciona con Python 3.4 y hacerla funcionar en un sistema Linux con Python 2.x es complicado, piensa en lo que puede suponer en un sistema en producción actualizar Python, con contenedores sería casi automático, descargar la imagen del contenedor y ejecutar la aplicación de turno. 

Solo por ponernos en situación de la envergadura Docker, unos números alrededor del producto y la compañía (fuente aquí):
  • 95 millones de dólares de inversión.
  • Valorada en 1.000 millones de dólares.
  • Más de 300 millones de descargas en 96 releases desde marzo de 2013
Pero un contenedor no es para todo, ni hay que volverse loco “dockerizando” cualquier cosa, aunque no es este el sitio para esa reflexión. Al cambiar la forma de desarrollar, desplegar y mantener aplicaciones, también cambia en cierto modo la forma de securizar estos nuevos actores.

Docker aporta seguridad en capas, aísla aplicaciones entre ellas y del host sin usar grandes recursos, también se pueden desplegar contenedores en máquinas virtuales lo que aporta otra capa adicional de aislamiento (estaréis pensando en VENOM pero eso es otra película que no afecta directamente a Docker). Dada la arquitectura de Docker y usando buenas prácticas, aplicar parches de seguridad al anfitrión o a aplicaciones suele ser más rápido y menos doloroso.

Buenas Prácticas de Seguridad:

Aunque la seguridad es algo innato en un contenedor, desde Docker Inc. están haciendo esfuerzos por la seguridad, por ejemplo, contrataron hace unos meses a ingenieros de seguridad de Square, que no son precisamente nuevos en el tema. Ellos, junto a compañías como VMware entre otras, han publicado recientemente un extenso informe de sobre buenas prácticas de seguridad en Docker en el CIS. Gracias a este informe tenemos acceso a más de 90 recomendaciones de seguridad a tener siempre en cuenta cuando vamos a usar Docker en producción. En la siguiente tabla podemos ver las recomendaciones de seguridad sugeridas, algunas son muy obvias pero un check list así nunca viene mal:

1. Recomendaciones a nivel de host
1.1. Crear una partición separada para los contenedores 
1.2. Usar un Kernel de Linux actualizado 
1.3. No usar herramientas de desarrollo en producción
1.4. Securizar el sistema anfitrión 
1.5. Borrar todos los servicios no esenciales en el sistema anfitrión
1.6. Mantener Docker actualizado 
1.7. Permitir solo a los usuarios autorizados controlar el demonio Docker
1.8. Auditar el demonio Docker  (auditd)
1.9. Auditar el fichero o directorio de Docker - /var/lib/docker 
1.10. Auditar el fichero o directorio de Docker - /etc/docker 
1.11. Auditar el fichero o directorio de Docker - docker-registry.service 
1.12. Auditar el fichero o directorio de Docker - docker.service 
1.13. Auditar el fichero o directorio de Docker - /var/run/docker.sock 
1.14. Auditar el fichero o directorio de Docker - /etc/sysconfig/docker 
1.15. Auditar el fichero o directorio de Docker - /etc/sysconfig/docker-network 
1.16. Auditar el fichero o directorio de Docker - /etc/sysconfig/docker-registry 
1.17. Auditar el fichero o directorio de Docker - /etc/sysconfig/docker-storage 
1.18. Auditar el fichero o directorio de Docker - /etc/default/docker 

2. Recomendaciones a nivel de Docker Engine (daemon)
2.1 No usar el driver obsoleto de ejecución de lxc 
2.2 Restringir el tráfico de red entre contenedores 
2.3 Configurar el nivel de logging deseado 
2.4 Permitir a Docker hacer cambios en iptables 
2.5 No usar registros inseguros (sin TLS)
2.6 Configurar un registro espejo local
2.7 No usar aufs como driver de almacenamiento
2.8 No arrancar Docker para escuchar a  una IP/Port o Unix socket diferente
2.9 Configurar autenticación TLS para el daemon de Docker
2.10 Configurar el ulimit por defecto de forma apropiada

3. Recomendaciones a nivel de configuración de Docker
3.1 Verificar que los permisos del archivo docker.service están como root:root 
3.2 Verificar que los permisos del archivo docker.service están en 644 o más restringidos 
3.3 Verificar que los permisos del archivo docker-registry.service están como root:root 
3.4 Verificar que los permisos del archivo docker-registry.service están en 644 o más restringidos
3.5 Verificar que los permisos del archivo docker.socket están como root:root 
3.6 Verificar que los permisos del archivo docker.socket están en 644 o más restringidos
3.7  Verificar que los permisos del archivo de entorno Docker (/etc/sysconfig/docker o /etc/default/docker) están como root:root 
3.8 Verificar que los permisos del archivo de entorno Docker (/etc/sysconfig/docker o /etc/default/docker) están en 644 o más restringidos
3.9 Verificar que los permisos del archivo /etc/sysconfig/docker-network (si se usa systemd) están como root:root 
3.10 Verificar que los permisos del archivo /etc/sysconfig/docker-network están en 644 o más restringidos
3.11  Verificar que los permisos del archivo /etc/sysconfig/docker-registry (si se usa systemd) están como root:root
3.12 Verificar que los permisos del archivo /etc/sysconfig/docker-registry (si se usa systemd) están en 644 o más restringidos
3.13 Verificar que los permisos del archivo /etc/sysconfig/docker-storage (si se usa systemd) están como root:root 
3.14 Verificar que los permisos del archivo /etc/sysconfig/docker-storage (si se usa systemd) están en 644 o más restringidos 
3.15 Verificar que los permisos del directorio /etc/docker están como root:root 
3.16 Verificar que los permisos del directorio /etc/docker están en 755 o más restrictivos 
3.17 Verificar que los permisos del certificado del registry están como root:root 
3.18 Verificar que los permisos del certificado del registry están en 444 o más restringidos 
3.19 Verificar que los permisos del certificado TLS CA están como root:root 
3.20 Verificar que los permisos del certificado TLS CA están en 444 o más restringidos 
3.21 Verificar que los permisos del certificado del servidor Docker están como root:root 
3.22 Verificar que los permisos del certificado del servidor Docker están en 444 o más restringidos 
3.23 Verificar que los permisos del archivo de clave del certificado del servidor Docker están como root:root 
3.24 Verificar que los permisos del archivo de clave del certificado del servidor Docker están en 400 
3.25 Verificar que los permisos del archivo de socket de Docker están como root:docker 
3.26 Verificar que los permisos del archivo de socket de Docker están en 660 o más restringidos 

4. Imágenes de Contenedores y Dockerfiles
4.1 Crean un usuario para el contenedor
4.2 Usar imágenes de confianza para los contenedores 
4.3 No instalar paquetes innecesarios en el contenedor
4.4 Regenerar las imágenes si es necesario con parches de seguridad

5. Runtime del contenedor
5.1 Verificar el perfil de AppArmor (Debian o Ubuntu) 
5.2 Verificar las opciones de seguridad de SELinux (RedHat, CentOS o Fedora) 
5.3 Verificar que los contenedores esten ejecutando un solo proceso principal
5.4 Restringir las Linux Kernel Capabilities dentro de los contenedores 
5.5 No usar contenedores con privilegios   
5.6 No montar directorios sensibles del anfitrión en los contenedores
5.7 No ejecutar ssh dentro de los contenedores
5.8 No mapear puertos privilegiados dentro de los contenedores
5.9 Abrir solo los puertos necesarios en un contenedor
5.10 No usar el modo “host network” en un contenedor 
5.11 Limitar el uso de memoria por contenedor 
5.12 Configurar la prioridad de uso de CPU apropiadamente 
5.13 Montar el sistema de ficheros raíz de un contenedor como solo lectura
5.14 Limitar el tráfico entrante al contenedor mediante una interfaz específica del anfitrión
5.15 Configurar la política de reinicio 'on-failure' de un contenedor a 5 
5.16 No compartir PID de procesos del anfitrión con contenedores
5.17 No compartir IPC del anfitrión con contenedores 
5.18 No exponer directamente dispositivos del anfitrión en contenedores
5.19 Sobre-escribir el ulimit por defecto en tiempo de ejecución solo si es necesario

6. Operaciones de Seguridad en Docker
6.1 Realizar auditorías de seguridad tanto en el anfitrión como en los contenedores de forma regular
6.2 Monitorizar el uso, rendimiento y métricas de los contenedores
6.3 Endpoint protection platform (EPP) para contenedores (si las hubiese) 
6.4 Hacer Backup de los datos del contenedor 
6.5 Usar un servicio centralizado y remoto para recolección de logs
6.6 Evita almacenar imágenes obsoletas, sin etiquetar correctamente o de forma masiva.   
6.7 Evita almacenar contenedores obsoletos, sin etiquetar correctamente o de forma masiva.

En algunos casos, hay recomendaciones que merecen un artículo por si solas. Si quieres profundizar más en este tema recuerda que los pormenores de estos aspectos de seguridad y auditoría los ampliaremos durante el curso online de Securízame "Hardening de Windows, Linux e Infraestructuras" en el que colaboraré junto a Lorenzo Martínez, Yago Jesús, Juan Garrido y Pedro Sanchez, todo un lujo de curso en el que aportaré mi granito de arena con seguridad en Docker completando el módulo de Hardening Linux. Más información aquí: https://www.securizame.com/curso-online-hardening-sistemas-windows-linux-infraestructuras/

Para otros posibles artículos en el futuro me parece interesante ver algunas consideraciones de seguridad en Docker Hub y otros componentes relacionados, así como auditorías de contenedores con Lynis.

Recursos y referencias:


Contribución por Toni de la Fuente (@toniblyx y blyx.com)


Leer más...

18 mayo 2015

Tunelizar conexiones de manera selectiva en Windows


El trabajo de un auditor, administrador de seguridad, etc.., requiere que en su día a día tenga que estar conectado, y siempre hablando de determinados escenarios, a varias redes, establecer conexiones con un origen específico, uso de conexiones VPN, etc..
El otro día, hablando con Jose Selvi vía telefónica sobre cosas mundanas y terrenales, me comentaba que en su portátil con Windows había tenido que configurar este tipo de cosas.
Es interesante destacar que, como hemos comentado en anteriores párrafos, en determinados escenarios puede ser interesante encaminar cierta parte de nuestro tráfico a través de distintas redes. Como principal ejemplo Selvi me comentaba que esto lo hacía cuando no gestionaba el EndPoint – por ejemplo una VPN que no controlamos – y que no le gustaba que cierto tráfico de su propiedad se pudiese ver “comprometido” o dar facilidades de acceso al mismo a un tercero.
Hay muchas opciones y muchos escenarios en donde también es interesante habilitar este tipo de configuraciones, como por ejemplo si necesitamos utilizar la salida de una determinada herramienta para alimentar a otra y no queremos andar “parseando” tráfico local nuestro. Otro ejemplo se puede dar cuando en determinadas auditorías exigen que se entregue una bitácora de peticiones – por ejemplo en formato PCAP – a modo de auditoría.
En Linux esto es posible realizarlo a través de netfilter/iptables y con las opciones de PREROUTING. Para hacerlo en Windows necesitamos entender cómo se gestionan y se crean conexiones de tipo VPN para luego poder encaminar los datos que necesitemos.
Cuando Windows genera una conexión VPN y nos conectamos a través de ella, el sistema operativo crea una ruta por defecto en la que se indica que todo nuestro tráfico lo encaminará a través de dicha conexión, y será el servidor final el que tendrá que realizar una acción de forwarding en caso de que se utilice también como conexión a Internet. Esto se puede verificar una vez conectados a la VPN con un simple route print.

Imagen 1. Información en la tabla de rutas
En caso de que no queramos que todo el tráfico pase por la VPN, en Windows pasa por configurar la nueva conexión de acceso remoto y desmarcar las opciones de Default Gateway en IPv4 e IPv6. Para ello, y en tus conexiones de red, debes configurar esta opción en la pestaña Networking de tu conexión de acceso remoto.
Imagen 2.- Conexiones de acceso remoto en Windows

Una vez desmarcada esta opción, usaremos la flexibilidad del comando route, y generaremos las entradas necesarias para encaminar el tráfico deseado por la conexión VPN. Para ello necesitamos conocer varios elementos:
  • Dirección - Rango de direcciones – Redes completas a encaminar
  • Número de interfaz
El número de interfaz se puede averiguar con el propio comando route print, o también a través del instrumental de administración de Windows.



Imagen 3.- Extracción de InterfaceIndex a través de WMI

Una vez tengamos estos datos, podremos utilizar la flexibilidad que nos otorga la creación de rutas para generar la nuestra. En el caso de que necesitemos generar una ruta para una dirección IP concreta, se podrá utilizar el siguiente comando:


Imagen 4.- Creación de ruta en Windows
En caso de necesitar que la ruta fuese persistente, se puede hacer uso del flag –p. Una vez realizado este paso para cada una de las direcciones IP o redes concretas, la próxima vez que nos conectemos a través de esa red VPN, todas las conexiones realizadas desde nuestro equipo a esas direcciones IP, se encaminarán a través de la conexión remota. El resto de peticiones se realizará con nuestra conexión local.
Si se desea realizar esto de manera masiva – por ejemplo a través de Directorio Activo y a un número determinado de equipos – se puede realizar a través de PowerShell y políticas de grupo. Para los interesados Microsoft ha generado un documento con scripts de ejemplo, el cual puedes descargar desde la siguiente dirección:
Los servicios y aplicaciones Microsoft permiten determinados tipos de configuraciones y vías de fortificación con mucha flexibilidad y a través de múltiples vías. Para los que estéis interesados en este tipo de tips y escenarios de fortificación avanzados, Lorenzo Martínez, uno de los editores de SecurityByDefault, me ha invitado a dar unas sesiones en el curso de Hardening de Sistemas Windows, Linux e Infraestructuras, y del cual estoy encantado de participar junto a buenos ponentes y amigotes, como Pedro Sánchez o Yago Jesús. Si quieres más información, así como un índice del mismo, puedes consultar el siguiente enlace:
Referencias adicionales
https://technet.microsoft.com/nl-nl/library/ee431701(v=ws.10).aspx
                                                                                                                             Juan Garrido (@tr1ana)
                                                                                                                             MVP Enterprise Security


Leer más...

08 mayo 2015

Para aquel que esté interesado en los deportes, es MUY probable que haya escuchado hablar del 'combate del siglo' que enfrentaba a Mayweather y Pacquiao, tal vez dos de los mejores púgiles del boxeo actual.

El combate en sí era un enfrentamiento entre dos tipos de boxeo muy bien diferenciados. Se enfrentaba un púgil altamente defensivo, estratega, con una gran capacidad para esquivar, y otro que representaba lo contrario: ataque, brega y presión.

El ganador del combate fue Mayweather, el boxeador que actuó de forma defensiva, y claro, para mucha gente eso le resultó una decepción. No obstante, criticar a Mayweather, un boxeador que va camino de pulverizar récords de imbatibilidad, es bastante injusto. Él lo tiene claro: cuanto mejor sea defendiendo, menos golpes recibe, en mejor estado afronta el combate y tiene muy claro que cuando se retire no va a terminar 'sonado' como le ha sucedido a otros boxeadores.

Esta pequeña introducción, alejada del tema principal del blog, me sirve para hacer una analogía bastante buena con respecto al mundo de la seguridad. Claramente hay dos disciplinas o dos tipos de seguridad muy bien diferenciadas. La que busca sobrepasar y la que intenta no ser sobrepasada.

Y es bastante obvio que es tan importante la una como la otra. Por eso me complace informar que, desde Securizame, se ha creado un curso destinado a defender, a saber crear una infraestructura a lo ' Mayweather' que sea capaz de resistir a todos los Pacquiaos que vengan puño en alto a intentar romperla.

El curso, en el que participa mi compañero Lorenzo, así como Juan Garrido o Pedro Sánchez consta del siguiente temario:

Módulo I – Introducción y Seguridad Perimetral  – 8 horas – Profesor: Lorenzo Martínez

Módulo II – Hardening de sistemas operativos Windows  – 8 horas – Profesor: Juan Garrido

Módulo III – Hardening de sistemas operativos GNU/Linux  – 8 horas – Profesor: Lorenzo Martínez

Módulo IV – Hardening de aplicaciones Microsoft  – 8 horas – Profesor: Juan Garrido

Módulo V – Hardening de servicios GNU/Linux. Hardening Mac OS X, IOS y Android – 8 horas – Profesor: Lorenzo Martínez

Módulo VI – Correlación, detección y bloqueo de amenazas de red  – 8 horas – Profesor: Pedro Sánchez

Módulo VII – Criptografía aplicada a la empresa  – 8 horas – Profesor: Yago Jesus

En el que voy a participar con un módulo con alto contenido PKI en el que intentaré, de la mano de la criptografía, explicar cómo configurar tanto sistemas Linux y sistemas Microsoft para aprovechar todas las ventajas que la criptografía ofrece a la seguridad.

EL curso empieza el 1 de Junio, así que si estás interesado, ve corriendo aquí y apúntate !
Leer más...

13 noviembre 2014

Cifrando los logs de Apache con libCryptoLog

En muchas ocasiones sucede que es necesario tener una política de cifrado de logs y no siempre es fácil 'convencer' a los servidores para que guarden la información cifrada.

Para abordar ese tipo de escenarios he liberado la versión 0.1 (mini-beta?) de libCryptoLog que permite manipular 'al vuelo' la forma en la que cualquier servidor guarda los logs. Y digo cualquiera porque en realidad, si bien este post va de Apache, el método que voy a explicar sirve para cualquier otro servicio (Postfix, Nginx ...).

De lo que se trata es de 'convencer' al servidor en cuestión de que toda información que vuelque al fichero que nos interese cifrar se almacene cifrada desde el minuto 0.

Después de pensar y re-pensar una forma que me convenciese para abordar este problema, programé libCryptoLog con la idea de que fuese 'plugeable', es decir, en vez de hardcodear en la librería las rutinas de cifrado, he decidido que eso caiga en un 'helper' externo para que cualquiera pueda adaptarlo fácilmente a sus requerimientos.

El funcionamiento es fácil: Por lo general, cuando Apache o cualquier otro servidor van a escribir a disco, suelen emplear dos funciones: fprintf() o write(), en el caso de Apache el 'meollo' está en write().

Como muchos de vosotros en este punto ya habréis deducido, lo que estoy haciendo es 'hookear' ambas funciones y alterar la forma en la que procesan los datos que van a almacenar a fichero.

El procedimiento es muy fácil de entender:

1- fprintf() y write() toman una cadena y la vuelcan a un fichero

2- libCryptoLog intercepta esas llamadas y extrae la cadena de texto

3- Esa cadena de texto se le pasa a un programa externo para que la cifre, le ponga colores o lo que sea

4- libCryptoLog toma el resultado de ese programa y ES ESO lo que almacena empleando fprintf o write

De esa forma los logs, antes de que 'toquen disco' ya están cifrados.

Este modelo permite que cualquiera, en cualquier lenguaje, programe sus propios helpers para decidir como transformar la cadena de texto. Junto con la librería van unos cuantos helpers para cifrar logs con RSA.

Vamos a ver un ejemplo con Apache en Centos 6.5:

Lo primero es descargar la librería desde aquí y descomprimirla con:

# tar -xvzf libCryptoLog.tgz

Para usar los helpers escritos en Perl, es necesario tener disponible la librería perl-Crypt-RSA, la instalamos

# yum -y install perl-Crypt-RSA

Una vez instalada, ya podemos generar nuestras claves publica y privada, es MUY CONVENIENTE que la clave privada no esté en el sitio donde vamos a cifrar por razones más que obvias. Esa clave es la llave para acceder al contenido de los logs por lo que se ha de guardar en un sitio externo donde se vayan a descifrar los logs.

Ejecutando:

# perl rsacreate.pl

Vemos que en el directorio han aparecido dos nuevos ficheros: key.public y key.private

Copiamos key.public a /usr/local/etc/

# cp key.public /usr/local/etc/

Igualmente copiamos el 'helper' a /usr/local/bin

# cp rsacrypt.pl /usr/local/bin/

Este es el script que se encargará de cifrar los logs 'al vuelo' usando la clave pública.

Con esto hecho, toca compilar la librería. Aquí hay una parte que se debe configurar. La función write() toma un ID como parámetro para saber en que descriptor debe escribir. No se puede manipular todas las llamadas a write() porque esa función se usa para muchas cosas, es necesario determinar los IDs que corresponden a los ficheros que vamos a cifrar.

Para obtener esta información debemos buscar un PID de Apache y consultar con lsof los IDs de los ficheros que tiene abiertos.

# ps aux | grep -i httpd

root      1508  0.0  1.6 135832 17328 ?        Ss   09:26   0:00 /usr/sbin/httpd
apache    1540  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1541  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1542  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1543  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1544  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1545  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1546  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd
apache    1547  0.0  0.6 135832  6932 ?        S    09:26   0:00 /usr/sbin/httpd

Y luego

# lsof -p 1508

httpd   1508 root    0r   CHR    1,3      0t0   3903 /dev/null
httpd   1508 root    1w   CHR    1,3      0t0   3903 /dev/null
httpd   1508 root    2w   REG  253,0     3522 398650 /var/log/httpd/error_log
httpd   1508 root    3r   CHR    1,9      0t0   3908 /dev/urandom
httpd   1508 root    4u  sock    0,6      0t0  10395 can't identify protocol
httpd   1508 root    5u  IPv6  10396      0t0    TCP *:http (LISTEN)
httpd   1508 root    6r  FIFO    0,8      0t0  10489 pipe
httpd   1508 root    7w  FIFO    0,8      0t0  10489 pipe
httpd   1508 root    8w   REG  253,0   265970 398649 /var/log/httpd/access_log

Justo al final podemos ver qué /var/log/httpd/error_log y
/var/log/httpd/access_log tienen asociados los IDs 2 y 8. Esto se puede ver en la cuarta columna en formato numero+w, en este caso 2w y 8w

Como solo queremos que estos dos ficheros queden cifrados (son los que guardan la información sensible ...) editamos el fichero libCryptoLog.c y en la parte de:

int filedesyes[2] = {3, 10};

La cambiamos a 

int filedesyes[2] = {2, 8};

Para que la librería sepa cuales llamadas a write debe modificar y cuales simplemente las debe dejar pasar sin hacer nada.

Una vez hecho eso, compilamos:

# gcc -Wall -fPIC -shared -o libCryptoLog.so libCryptoLog.c -ldl -lssl

Y copiamos nuestra flamante nueva librería en /usr/local/lib

# cp libCryptoLog.so /usr/local/lib/

¡¡ Ya casi casi estamos !!

Ahora, para que se produzca el 'hooking' tenemos que instruir al fichero de arranque de Apache para que defina la variable LD_PRELOAD correctamente en los procesos que genere.

# vi /etc/init.d/httpd

En la parte de start localizamos algo como

start() {
        echo -n $"Starting $prog: "
        LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch ${lockfile}
        return $RETVAL
}

Y debemos modificarla para que quede algo así (he puesto en negrita lo que he añadido)

start() {
        echo -n $"Starting $prog: "
        LD_PRELOAD=/usr/local/lib/libCryptoLog.so LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch ${lockfile}
        return $RETVAL
}

Y si todo ha ido bien, en cuanto hagamos un stop / start nuestros ficheros de log pasarían a quedar cifrados.

# service httpd stop
# service httpd start

Si hacemos un tail a /var/log/http/error.log ya podemos ver que Apache está guardando la información cifrada:

BEGINCRYPTO
gRNmfi/yS9Vaya37VJ7sM+iZtoYDG976SWPa4XTLnPGccBTd56J8Bk0uLZyK86vopcjdKp2JPDr7
oHWk/TKA00IStIgvTofUH9DeZGepqikIkjJg9wylAJ0ROjpcerozOX1LQWuj+ZoOxRu7K+UIeQmc
389SjDAyqNs/U8UHc75ntbVHy/A1e95fWUAHnkcD/1au463ugNHQmCJoSHA4NgwhDmwUJLafWSKr
T/L6BaOsruxDtkUqu0gBfROadVuc9oALSdRSc5WqA3T5HuS10a49szZ5zedqtQJiQFjikJCRo/v6
tzYHHs3Es+8yfpZti/l3pChW8+zHCxuPRKNccg==
ENDCRYPTO
BEGINCRYPTO
VB68V3MyG7yNHfYc8UR69ZbaC4ztBkOigWnKZzlKTMiXNdSBFEJ++TPKQXUFo4j8AfrgQPL6DQQ8
nd0yoMSaA3ojq+MvBY5cSLstVeEGaIJSXRboZMGyq6UpfOAqvWLvd48w63ND9cKKDBkEQcfUM3a7
S5KPss/qqSKYcsSHsqk=
ENDCRYPTO
BEGINCRYPTO
DN0d0oa8DJrVj7GGuiGUuhRMc8bDIPGUL39Ae51YFwZl1mRoq5EgipcTxyPThTngw7rOobUGrCaS
YY/MlO4FV4HGAsBWsQksfqYzsgbC7Lv+Ek4oe+01rhJ2L70BKPWPiRdr9oQHsWcL8aTDtLj8X/H4
R3XJ76mvNUSOPAPjijE2WZiAIRYmU+0fzTrbJTYaV3GrGYm2rWkoFQu7aImQHqWRsnSs9k9RmLij
3KoX/MpBBd+a0hOhBsZQmLf915VJgp5E2zrqXMwutdyS3+UJ7o+lesK8LfC2jl40aYvVZXZXNPv+
uDsNbkPJIRzXpfmwnR5KtMFcNOdEJ+1378BRrQ==
ENDCRYPTO

 
Ahora queda la parte final ¿y como revierto el cifrado para tener el log original? Para eso, hay un script llamado rsadecrypt.pl que toma como parámetro un fichero entrada y otro salida, en este caso entrada sería error.log y salida error2.log, quedando en este último el formato descifrado.

# perl rsadecrypt.pl /var/log/httpd/error_log error2.log

Si hacemos un tail en error2.log

[Fri Jun 06 09:55:34 2014] [notice] suEXEC mechanism enabled (wrapper: /usr/sbin/suexec)
[Fri Jun 06 09:55:34 2014] [notice] Digest: generating secret for digest authentication ...
[Fri Jun 06 09:55:34 2014] [notice] Digest: done
[Fri Jun 06 09:55:34 2014] [notice] Apache/2.2.15 (Unix) DAV/2 PHP/5.3.3 mod_perl/2.0.4 Perl/v5.10.1 configured -- resuming normal operations

Vemos que lo que antes era base64 cifrada, ahora es plain text :)

Evidentemente no todo es gratis, el añadir este 'extra' de cifrado penaliza bastante el rendimiento porque las operaciones RSA son 'pesadas' y además desde un script aun más. 

Hay que tener mucho cuidado en qué servidores se activa esta medida de seguridad y si tienen la capacidad adecuada para soportar el cambio.

Como última cosa, reiterar que en este ejemplo se están usando mis scripts para tratar los logs, en el código de la librería se puede ver el comando definido 

char *command = "perl /usr/local/bin/rsacrypt.pl \"";

Pero ahí puede ir cualquier cosa que trate el texto de los logs.
Leer más...