de-charleta

De Charleta: “Mobile App Pentesting en Primera Persona” (Gustavo Sorondo)

Hace poco se celebró la DragonJar Security Conference 2.016, así que hoy recomendamos esta interesante charla en la que Gustavo Sorondo (Puky) nos cuenta un proceso de pentesting sobre una app móvil.

Gustavo Sorondo es CTO de «Cinta Infinita – Information Security». En su carrera profesional ha trabajado en más de 100 proyectos relacionados a la seguridad de la información en 6 paises, y ha dictado cursos de Penetration Testing, Seguridad en Aplicaciones Web, Seguridad Wireless y Testing de Mobile Apps. También ha dado charlas y workshops en conferencias de seguridad como ekoparty, OWASP Latam Tours, Segurinfo, RISECON y PampaSeg.

DragonJar Security Conference 2.016.

Español.

Contenedores Linux y seguridad. Docker

Un poco de historia

Las técnicas de para circunscribir un proceso a un espacio aislado dentro de un sistema operativo no es algo nuevo. El primer antecedente, chroot, se remonta a 1979 y fue introducido como un concepto en desarrollo para sistemas Unix que permitía aislar dentro una ruta un proceso y sus hijos de modo que para ellos, esa ruta pareciese ser el directorio raíz. Más adelante,  en 1982, chroot se incorpora a sistemas operativos BSD. En 1991 es utilizado por William Cheswick, un programador e investigador en seguridad de red, para implementar una honeypot y monitorizar comportamientos maliciosos.

Estas semillas iniciales supusieron los primeros pasos de lo que se acabaría consolidando como virtualización de sistemas con la aparición de hypervisores, software que permite la ejecución virtual de sistemas completos emulando tanto el hardware como el sistema operativo.

Dejando a un lado lo que a virtualización de hardware e hypervisores se refiere, en este artículo vamos a ofrecer una visión de los contenedores, una tecnología que,  partiendo de la idea base de chroot, extiende este concepto para conseguir ejecutar entornos aislados del sistema. Con el uso de contenedores, en realidad no se está virtualizando nada sino que se están manteniendo en un espacio aislado (namespace) los procesos y ficheros necesarios mientras se reutiliza el kernel del sistema anfitrión.

La primera aproximación sólida a los contenedores en sistemas *nix aparece  en FreeBSD en el año 2000 con la introducción del comando jail que orienta y amplia las funcionalidades de chroot. A partir de ahí, se empieza a extender a otras plataformas como Solaris, el sistema operativo de Sun Microsystems, que en  2005 incorpora Solaris Zones permitiendo crear subsistemas aislados denominados zonas. De igual forma otros fabricantes como IBM con AIX WPARs,  o HP con HP-UX Containers adoptan implementan soluciones similares.

Finalmente, en 2008, llega a Linux con LXC (Linux Containers) que da soporte al kernel para los namespaces. Los namespaces constituyen el elemento base de los contendores y es una funcionalidad del kernel que proporcionan facilidades para crear una abstracción del sistema de modo que, todo lo que sucede fuera del espacio del contenedor sea invisible al interior.

¿Virtualización? ¿Qué virtualización?

La evolución de los namespaces ha permitido pasar del “enjaulamiento” de rutas de chroot hasta los contenedores que proporcionan espacios aislados en todos los niveles: espacio de usuario, espacio de procesos, de red, puntos de montaje, etc. Esta situación se acerca a estado parecido a la virtualización que quizás podemos entender mejor como una virtualización de sistema operativo o mejor dicho, una “paralelización” puesto que se comparte una arquitectura y un kernel y no se virtualiza ningún elemento hardware o dispositivo lo que contribuye a un mejor rendimiento.

 

Screen Shot 2016-06-21 at 08.10.45

Contenedores vs virtualización

La popularidad y la utilización de los namespaces ha crecido enormemente desde su integración directa, en 2013 en el kernel 3.8 de Linux. Desde entonces se han consolidado y afianzado desarrollos basados en contenedores como por ejemplo  Docker o CoreOS Rkt entre otros.

Contenedores vs hipervisores

Los contenedores frente a la virtualización de hardware mejoran aspectos como:

Velocidad: Compartir el kernel significa cero latencia para levantar con contenedor.

Gestión de disco: El almacenamiento basado en sistemas de ficheros con características Copy on Write (CoW) permiten reutilizar y compartir segmentos de sólo lectura de datos (imágenes base)  entre distintos contenedores y trabajar con deltas (capas de escritura) que cada contenedor puede ir añadiendo y manteniendo de forma independiente. Sistemas de ficheros como Union Filesystems (aufs), OverlayFS o Brtfs permiten este modo de operación.

lobo@SI_$ docker info
Containers: 3
 Running: 2
 Paused: 0
 Stopped: 1
Images: 102
Server Version: 1.11.1
Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 87
 Dirperm1 Supported: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge null host
Kernel Version: 4.0.0-kali1-amd64
Operating System: Kali GNU/Linux 2.0 (sana)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 997.8 MiB

Portabilidad: Un contenedor puede trasladarse a cualquier otro sistema siempre que comparta la misma arquitectura de CPU, sin necesidad de adaptaciones. Esto permite trabajar de forma rápida y cómoda con repositorios que facilitan enormemente tareas de despliegue y desarrollo.
Por otro lado algunos inconvenientes son:
Seguridad: La implementación de los namespaces es relativamente reciente, y esto unido a que el kernel es compartido, incrementa los riesgos de comprometer el host y con ello todos los contenedores que estuviesen en el mismo. Punto único de fallo.
Entornos únicos: La imposibilidad de virtualizar otros sistemas operativos puede ser una desventaja en desarrollos multiplataforma.
Escalado y migración: Aunque existen soluciones de orquestación que permiten la ejecución multicontenedor distribuidos en distintas ubicaciones, la complejidad aumenta notablemente según lo hace el número de hosts. Esto unido a la imposibilidad de migración “en caliente” para mover contenedores supone una desventaja ante soluciones completas de virtualización.

Contenedores y seguridad. Namespaces, cgroups, capabilities y más.

El aislamiento en los contenedores Linux se sustenta principalmente en dos funcionalidades del kernel: los namespaces y cgroups, que haciendo una aproximación sencilla podemos identificar como los mecanismos que proporcionarán la base para el aislamiento a nivel cualitativo y cuantitativo respectivamente. Desde la versión de kernel 2.6, ambas tecnologías se han ido asentando paulatinamente hasta una completa integración en el kernel 3.8. Revisando la configuración del kernel (generalmente existe un fichero de config en /boot) podemos averiguar el grado de soporte en la compilación en uso, como muestran las siguientes imágenes para un kernel 4.0:

lobo@SI_$ grep -E 'NAMESPACES|_NS=y' /boot/config-4.0.0-kali1-amd64
CONFIG_NAMESPACES=y
CONFIG_UTS_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y
CONFIG_NCPFS_NFS_NS=y
CONFIG_NCPFS_OS2_NS=y

lobo@SI_$ grep CGROUP /boot/config-4.0.0-kali1-amd64
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
# CONFIG_CGROUP_HUGETLB is not set
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NET_CLS_CGROUP=m
CONFIG_CGROUP_NET_PRIO=y
CONFIG_CGROUP_NET_CLASSID=y

Desde el punto de vista de la seguridad, los namespaces permitirán espacios aislados para los procesos que contienen, lo que protege el sistema de acciones que suceden en el interior de la sandbox creada. Por otra  parte los control groups (cgroups), permiten gestionar los recursos que se atribuyen a ciertos procesos, siendo posible de este modo asignar límites cuantitativos de CPU, memoria, acceso a disco, etc. Esto es muy útil para asegurar que el sistema no pueda ver comprometidos sus recursos.

Por otra parte, el uso de las capabilities del kernel complementaría la seguridad de los namespaces y los cgroups, restringiendo y evitando acciones privilegiadas dentro del contenedor que podrían establecer una vía de escape de la sandbox.

Todo lo anterior unido a la integración de los contenedores con mecanismos de control de acceso como SELinux completa un entorno de seguridad suficientemente robusto que, como siempre, necesita de un ajuste y una configuración apropiada.

containers_security_layers

Aislamiento en contenedores

Una vez introducidos los mecanismos principales de seguridad de los contenedores: namespaces, cgroups, capabilities y SELinux, vamos a echar un vistazo a su funcionamiento.

Namespaces

Existen 6 tipos básicos de namespaces relacionados con distintos aspectos del sistema:

  • NETWORK namespace. Aislamiento de red. Así, cada namespace de red tendrá sus propios interfaces de red, direcciones de red, tablas de enrutamiento, puertos de red, etc.
  • PID namespace. Aísla el espacio de identificadores de proceso. Un contenedor tendrá su propia jerarquía de procesos y su proceso padre o init (PID 1).
  • UTS namespace. Aísla el dominio y hostname, permitiendo a un contenedor poseer su propio dominio de nombres.
  • MOUNT namespace. Aísla los puntos de montaje de los sistemas de ficheros que puede ver un grupo de procesos. Este namespace fue el punto de partida que nació con chroot.
  • USER namespace. Aísla identificadores de usuarios y grupos. Así dentro un contenedor es posible tener un usuario con ID 0 (root) que se corresponda con un ID de usuario cualquiera en el host.
  • IPC namespace. Aísla la intercomunicación entre procesos dentro del espacio.

Así, sobre un kernel con soporte para namespaces es posible aislar procesos utilizando las llamadas al kernel (clone) con los flags necesarios (CLONE_NEWNET, CLONE_NEWPID, CLONE_NEWUTS, CLONE_NEWNS, CLONE_NEWUSER, CLONE_NEWIPC) según lo deseado. Esta es la  base utilizada por frameworks como Docker para crear contenedores.

Utilizando Docker, verifiquemos en un ejemplo como los procesos dentro de un contenedor tienen namespaces distintos, lo que significa que se mueven en espacios independientes y aislados entre sí. En el escenario mostrado en la imagen siguiente,  podemos ver la ejecución de una shell (sh) dentro un contenedor utilizando Docker. Con el comando “docker ps” mostramos efectivamente, un contenedor con nombre loving_albatanni  que está ejecutando una shell. El pid del contenedor es 11344 desde el punto del host  que, correspondería al proceso 1 dentro del mismo y que identifica al  proceso “sh”,  el primer comando ejecutado en el contenedor.

Podemos verificar los cambios de namespaces con el comando pstree con el flag –S, que nos mostrará la jerarquía de procesos, indicándonos entre paréntesis los cambios de contexto en los namespaces. De forma más directa, inspeccionando /proc identificamos claramente identificadores distintos en los namespaces de proceso 1 del host y el proceso 11344 del contenedor (pid 1 dentro).

Namespace de procesos

Namespace de procesos

lobo@SI_$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c1c14004ad6d debian "bash" 6 days ago Up 6 days nostalgic_leavitt
lobo@SI_$ docker inspect loving_albatanni | grep -i pid
 "Pid": 11344,
 "PidMode": "",
 "PidsLimit": 0,
lobo@SI_$ pstree -gsS 11344
systemd(1)───docker(751,mnt)───docker-containe(828)───docker-containe(13340)───bash(11344,ipc,mnt,net,pid,uts)───s
lobo@SI_$ ls -l /proc/1/ns
total 0
lrwxrwxrwx 1 root root 0 jun 8 11:22 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 jun 8 11:22 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 jun 8 11:22 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 jun 8 11:22 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 jun 8 11:22 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 jun 8 11:22 uts -> uts:[4026531838]
lobo@SI_$
lobo@SI_$ ls -l /proc/11344/ns
total 0
lrwxrwxrwx 1 root root 0 jun 6 08:34 ipc -> ipc:[4026532153]
lrwxrwxrwx 1 root root 0 jun 6 08:34 mnt -> mnt:[4026532151]
lrwxrwxrwx 1 root root 0 jun 6 08:34 net -> net:[4026532156]
lrwxrwxrwx 1 root root 0 jun 6 08:34 pid -> pid:[4026532154]
lrwxrwxrwx 1 root root 0 jun 8 11:22 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 jun 6 08:34 uts -> uts:[4026532152]
lobo@SI_$
lobo@SI_$ docker attach loving_albatanni
root@c1c14004ad6d:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 20244 1960 ? Ss Jun01 0:00 bash
root 17 0.0 0.1 17500 1828 ? R+ 09:26 0:00 ps aux

NOTA: Nótese que no hay cambio en el namespace de usuario ya que este es opcional y debe fijarse al arrancar docker. Al no haber cambio en el namespace de usuario, el usuario dentro del contenedor es el mismo usuario fuera de él. Esto quiere decir que root dentro del contenedor es root fuera, lo que entraña un riesgo de seguridad que conviene evitar configurando oportunamente la ejecución.

Cgroups

Los grupos de control o cgroups son una excelente herramienta para controlar la asignación de recursos hardware. Para ello se definen jerarquías en árbol en las que se agrupan los procesos del sistema apoyándose en una ruta del sistema de ficheros, generalmente ubicado en /sys/fs/cgroup (debian) o /cgroup (redhat). Simplificando, podemos imaginar como el tradicional ulimit pero mucho más extenso y granular. No es objeto de este artículo profundizar en la descripción funcional de los grupos de control, pero si es interesante ver como gracias a ello es posible recortar recursos a un contenedor y por tanto contribuir a aislar su impacto en el sistema.

De nuevo utilizando docker arrancamos dos contenedores uno sin especificar límite de memoria y un segundo aplicando un límite de 64mb utilizando el flag –m 64mb. Para demostrar la restricción de memoria corremos el programa stress para consumir 100Mb de memoria ( stress –vm 1 –vm-bytes 100M )

lobo@SI_$  docker run -it -m 64mb debian bash
WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.
root@39769040071c:/# stress --vm 1 --vm-bytes 100M
stress: info: [6] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

lobo@SI_$ docker run -it debian bash
WARNING: Your kernel does not support swap limit capabilities, memory limited without swap.
root@21e5fd19b14963:/# stress --vm 1 --vm-bytes 100M
stress: info: [6] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd

 

Con el comando systemd-cgtop podemos ver el consumo de recursos por distintos grupos de control y verificamos efectivamente que, uno de los contenedores no es capaz de consumir más de 64Mb:

lobo@SI_$ systemd-cgtop

 

cgroups

Las propiedades del contenedor y sus límites podemos comprobarlas con docker inspect:

cgroups_limit

Capabilities

Las capabilities proporcionan un buen mecanismo para restringir privilegios. En el caso de los contenedores es especialmente útil y por ejemplo en Docker, por defecto cualquier contenedor sufre un recorte de capabilities que impiden numerosas operaciones privilegiadas tales como el montaje de sistemas de ficheros o administración de interfaces de red entre otras.

Verifiquemos con un ejemplo real como se produce este recorte de capabilities comparando una shell en el host y una shell en el contenedor.

Una shell de root en el host tiene todas las capabilities:

lobo@SI_$ echo $$
26599
lobo@SI_$ cat /proc/26599/status | grep ^Cap
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
lobo@SI_$ capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,
cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,
cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,
cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,
cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,
cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,
cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,
cap_wake_alarm,cap_block_suspend,37
lobo@SI_$

Sin embargo, por defecto en un contenedor se restringen capabilities y como se puede ver en la siguiente imagen de un contenedor docker se eliminan todas menos unas pocas:

lobo@SI_$ docker ps
CONTAINER     ID    IMAGE COMMAND CREATED STATUS PORTS NAMES
39769040071c debian "bash" 15 minutes ago Up 15 minutes condescending_lumiere
21e5fd19b149 debian "bash" 17 minutes ago Up 17 minutes sad_blackwell
lobo@SI_$ docker inspect condescending_lumiere | grep -i pid
 "Pid": 26579,
 "PidMode": "",
 "PidsLimit": 0,
lobo@SI_$ cat /proc/26579/status | grep ^Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
lobo@SI_$ capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,
cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,
cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap

Esto se traduce en restricciones dentro del contenedor. Para ilustrar con un ejemplo: obsérvese que se han quitado las capabilities cap_net_admin y cap_sys_time, de modo quelo el kernel denegaría operaciones de cambio de fecha del sistema o manipulación de interfaces de red dentro del contenedor (aun siendo root):

lobo@SI_$ docker exec -it condescending_lumiere bash
root@39769040071c:/#
root@39769040071c:/# date
Wed Jun 8 10:20:25 UTC 2016
root@39769040071c:/# date +Y%m%d -s "20160609"
date: cannot set date: Operation not permitted
root@39769040071c:/# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03
 inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
 inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
 RX packets:65 errors:0 dropped:0 overruns:0 frame:0
 TX packets:43 errors:0 dropped:0 overruns:0 carrier:0
 collisions:0 txqueuelen:0
 RX bytes:234083 (228.5 KiB) TX bytes:3295 (3.2 KiB)

root@39769040071c:/# ifconfig eth0:1 172.17.0.5
SIOCSIFADDR: Operation not permitted
SIOCSIFFLAGS: Operation not permitted
root@39769040071c:/#

Las capabilities necesarias pueden otorgarse o denegarse al arrancar el contenedor según se necesite.
Así por ejemplo podemos comprobar el efecto de quitar la capability NET_RAW necesaria para ejecutar ping:

lobo@SI_$ docker run -it --cap-drop net_raw alpine sh
/ # ping localhost
PING localhost (127.0.0.1): 56 data bytes
ping: permission denied (are you root?)
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(t ape),27(video)

Comprobamos que en las capabilities del contenedor ya no tenemos CAP_NET_RAW:

lobo@SI_$ docker ps
 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
 a57f71180937 alpine "sh" 24 seconds ago Up 22 seconds focused_stallman

 lobo@SI_$ docker inspect focused_stallman | grep -i pid
 "Pid": 27070,
 "PidMode": "",
 "PidsLimit": 0,
 lobo@SI_$ cat /proc/27070/status | grep ^Cap
 CapInh: 00000000a80405fb
 CapPrm: 00000000a80405fb
 CapEff: 00000000a80405fb
 CapBnd: 00000000a80405fb
 lobo@SI_$ capsh --decode=00000000a80405fb
 0x00000000a80405fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,
cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,
cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap
El comando ping necesita de la capability NET_RAW como podemos comprobar con el comando getcap:
 lobo@SI_$ getcap /bin/ping
 /bin/ping = cap_net_raw+ep

Contenedores y aseguramiento del contenido

Los contenedores de Linux y las tecnologías subyacentes tienen un desarrollo suficientemente sólido que han propiciado que su utilización se vaya asentando y teniendo en cuenta cada vez más. No obstante, ha de tenerse en cuenta que la falta de rodaje que conlleva esta relativa inmadurez se hace extensiva a la seguridad se echa en falta aún una base de metodologías para configurar, fortalecer y verificar aspectos que sin la debida atención pueden poner en entredicho la seguridad de sistemas “containerizados”.

security-monkey-netflix

Security Monkey: Controla la seguridad de AWS con Netflix (parte 1)

Supongo que todos conocéis Netflix a estas alturas, el servicio VOD con suscripción mensual que aterrizó en España hace unos meses y ya es todo un éxito.

Pero, además de ser una forma estupenda de ver películas y series, puede ofrecernos mucho que aprender gracias a lo que algunos (yo no :D) llaman pornografía tecnológica.

Netflix es una de esas empresas que se rodea de los mejores ingenieros para poder ofrecer un servicio con calidad por encima de lo normal. En ese sentido, leer de forma regular «The Netflix Tech Blog» es altamente recomendable.

 

Aprendiendo de los mejores

Que profesionales tan altamente cualificados como los que trabajan en Neflix dediquen una parte de su tiempo a contarnos cómo hacen las cosas, es algo de agradecer. Vivimos en un mundo en el que estamos obligados a aprender de forma contínua y este tipo de lecturas nos abren la mente a nuevas formas de hacer las cosas.

Puedes encontrar temas tan interesantes como:

Y sobre todo, en general de elementos de Amazon WS (unos servicios con los que suelo trabajar tal y como os conté en Controla lo que hacen tus usuarios con Amazon WS IAM (parte 1) y Controla lo que hacen tus usuarios con Amazon WS IAM (parte 2)).

aws-summit-1

 

Security Monkey

Revisando esto, me he encontrado con una solución desarrollada por el equipo Netflix que tiene por objetivo monitorizar y analizar la seguridad de los servicios de AWS.

Se trata de un desarrollo propio que ofrecen como open source y que nos permite monitorizar la configuración de los servicios EC2, RDS, S3 e IAM. Cualquier cambio que se realice sobre ellos quedará registrado para que tengamos el control de todo lo que sucede.

Está pensada para correr sobre una máquina Linux y almacenar la información en una PostgreSQL. A nivel tecnológico está escrita en Python utilizando el framework Flask, utilizando datos JSON servidos mediante una API REST.

Casos de uso típicos serían:

  • Visualización de cambios históricos de un elemento (como los cambios en grupos de seguridad).
  • Auditorías de configuraciones incorrectas (como permisos en buckets S3).

Para conseguir esto, Security Monkey cuenta con tres componentes principales:

  • Watcher, es el encargado de observar nuestra cuenta para detectar cambios. Cuando eso ocurre, se almacena esa información en la base de datos interna.
  • Notifier, es el encargado de avisarnos cuando se produce un evento que podemos personalizar.
  • Auditor, es el encargado de realizar pruebas y revisiones sobre los elementos, reglas y políticas. Podemos definir aquello que no queremos que ocurra para que salte una alarma si se encuentra (como grupos de seguridad con puertos abiertos al mundo).

Una vez lo tengamos funcionando podremos acceder mediante su interfaz web, configurar los elementos que queremos monitorizar y ver todo en detalle.

 

¿Te ha gustado tanto como a mi? Entonces descarga el proyecto desde su repositorio y coméntanos qué tal tu experiencia. Yo lo haré en un post en el que os mostraré el proceso de instalación, configuración y uso. De momento, esto es todo, espero que os esté resultando interesante.

Como siempre digo, si ves algún error, no estás de acuerdo con lo que cuento o quieres hacer alguna aportación, no dudes en pasarte por los comentarios.

auditoria-de-codigo

Auditoría de código: algo necesario pero que nunca hacemos (parte 3)

Ha pasado un poco de tiempo desde que empezamos con esta serie de entradas dedicadas a la auditoría de código, pero vamos de nuevo con el último post de la serie.

En la primera parte, hicimos una introducción a la tarea y vimos cómo se trata de algo que cada vez cobra más importancia. En la segunda parte planteamos los primeros pasos, así como la forma en la que organizar el equipo y poder repartir tareas. ¿Seguimos?

Separa “lo blanco” de “lo de color”

Cuando nos pongamos manos a la obra, debemos tener en cuenta que casi siempre podremos hacer auditoría estática (leyendo código) y dinámica (ejecuciones en entorno de prueba). Ser capaz de separar qué parte corresponde a cada caso será vital para acortar tiempos y obtener un resultado positivo.

Para poder hacerlo, nos basaremos en la documentación obtenida en la fase anterior y en una clara enumeración de tecnologías y sistemas. Teniendo toda la información sobre la mesa, podremos otorgar pesos de forma que:

Código candidato a auditoría estática:

  • Partes desarrolladas hace mucho tiempo.
  • Partes generadas de forma automática (sobre plataforma “insegura”).
  • Algoritmos “a medida” y complejos.
  • Partes sin documentar.
  • Zonas de acceso anónimo.
  • Valores y configuración por defecto.
  • Desarrollo en ensamblador.

Código candidato a auditoría dinámica:

  • Partes desarrolladas hace poco tiempo.
  • Partes generadas de forma automática (sobre plataforma “segura”).
  • Algoritmos conocidos o sencillos
  • Partes bien documentadas.
  • Zonas de acceso bajo autenticación de usuario.

Con esta separación podremos realizar varias iteraciones con varios niveles de búsqueda, yendo desde lo más automático hasta lo más manual.

¡Briconsejo!

Muchas veces, la sencilla búsqueda de palabras clave te puede ofrecer una buena lista de cosas a revisar con lupa…

Cosas como pass, root, secret, key, admin, user, db, bug, fix, todo,… son candidatas a tener en cuenta. ¡No olvides hacerte con un buen diccionario de ellas!

¿Y qué podemos encontrar?

Para este tipo de auditorías, suelo revisar el conocido OWASP top 10 y derivados. Te recomiendo que eches un vistazo a estos enlaces de interés:

Ahí podrás ver cómo detectar y mitigar cosas tan habituales como:

A) Funciones inseguras o prohibidas: a menudo te puedes encontrar que esa función que se está usando, la documentación no la recomienda (¿para qué puñetas está?… por compatibilidad..).

void VerificarID(char *usuarioID){
   char buf[10];
   strcpy(buf, usuarioID);
}

El uso de la función strcpy está desaconsejado por problemas derivados de ataques buffer overflow.

 

B) Referencia insegura directa a objetos (Directory transversal): exponer rutas completas de acceso a ficheros puede dejar el camino abierto para acceder a otros lugares que no estaban planteados inicialmente.

public class CrystalImageHandler : WebControl {
   private string tmpdir = null;
   
   protected override void Render(HtmlTextWriter writer) {
      string filepath;
      string dynamicImage = (string)Context.Request.QueryString.Get("dynamicimage");

      if (tmpdir == null) {
         tmpdir = ViewerGlobal.GetImageDirectory();
      }

      filePath = tmpdir + dynamicImage; FileStream imagestream = new FileStream (filePath, FileMode.Open, FileAccess.Read); 

      ... 
 
      File.Delete (filePath);
   }
}

Esto permite a un atacante hacer algo como: http://foo.bar/crystalreportviewers/crystalimagehandler.aspx?dynamicimage=..\..\..\..\..\mydocuments\private\passwords.txt

 

C) Inyección de comandos sql (SQL Injection): cualquier entrada de datos de usuario no filtrada puede convertirse en una puerta para un atacante. Utilizar esa entrada para hacer que se ejecuten determinados comandos es hoy (y desde hace años) uno de los principales problemas de seguridad.

String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") +"'";

Un atacante puede insertar algo como http://example.com/app/accountView?id=’ or ‘1’=’1 y obtener todas las cuentas de usuario.

 

D) Secuencia de comandos en sitios cruzados (Cross-Site Scripting o XSS): cuando se muestra el contenido del usuario por pantalla sin pasar por ningún filtro, se pueden llegar a ejecutar comandos no deseados.

echo $_REQUEST['userinput'];

Un atacante puede introducir como entrada algo tipo <script>alert(«XSS»)</script> y obtener un popup por pantalla que le daría paso a probar cantidad de maldades.

 

Pero no nos olvidemos de otros clásicos derivados de la constante de inutilidad como:

E) Código oculto: partes de código que no deberían estar ahí ni hacer lo que hacen (backdoors).

int main(){

    int x;
    double fact=1;

    printf("Escriba el número: ");
    scanf("%i",&x);

    if(x == -1) {
       OpenBackdoor();
    }

    while(x>1) fact*=x--;

    printf("Factorial =%lf",fact);
}

Será complicado encontrar y podría superar un análisis automático.

 

F) Mala gestión de errores: mostrar mensajes de error con todo lujo de detalles por pantalla o no gestionar determinadas excepciones son prácticas habituales.

try{
   SaveToDB();
}
catch(Exception ex){
   // Esto no falla nunca, no hay problema.
}

¿Eres de los que haces pruebas en producción?

 

G) Contraseñas en código: para no tener que tirar de BD, a veces incluso se meten contraseñas “a fuego”, algo que se puede obtener con un sencillo decompilador.

String user_pass = Request.Form("UserPass");

String pass = "User_Pass_123!";

if(user_pass.Equals(pass)){
   OpenConnection();
}

No pienses que nadie va a mirar tu código, dejar ahí información no es para nada una buena práctica.

 

Por supuesto, debemos llevar un seguimiento de todas las evidencias y errores que vayamos encontrando mediante el uso de nuestras herramientas favoritas de gestión de bugs o documentación, teniendo en cuenta:

  • Debemos destinar un tiempo diario para escribir resultados.
  • Debemos guardar capturas de pantalla y referencias de todo lo relevante, tanto si son resultados satisfactorios como si no lo son.
  • Debemos facilitar la continuidad del trabajo para otros auditores.

Una vez tengamos documentado todo, tendremos que generar dos informes que hablarán de lo mismo, pero con dos enfoques diferentes.

El informe técnico

informe-tecnico

Se trata de un informe de alto detalle en el que mostraremos todo lo que se ha encontrado. Está realizado por informáticos y va a ser revisado por informáticos, no tengas miedo a usar lenguaje técnico.

Y, aunque parezca una chorrada, permíteme que te recuerde que no debemos recrearnos en errores ajenos. La serenidad, elegancia y diplomacia son factores básicos.

El informe ejecutivo

informe-ejecutivo

Se trata de un informe de bajo detalle en el que mostraremos, de una forma ágil, el resultado de la auditoría. Debe alejarse de tecnicismos, no deberás hablar de herramientas o técnicas.

Cuanto más expresivo, mejor, no tengas miedo a usar cifras, iconos y ser cuantificable. El objetivo es que sea rápido de leer por personas de dirección que no tienen tiempo para entrar en demasiado detalle.

Sobre todo, ten en cuenta que el informe es el reflejo de una auditoría y permite medir la calidad de la misma. Una auditoría puede fracasar por un mal informe.

Y hasta aquí la entrada de hoy, espero que los consejos que te he dado sean de utilidad para tus auditorías de código. Si ves algún error, no estás de acuerdo con lo que cuento o quieres hacer alguna aportación, no dudes en pasarte por los comentarios.

Herramientas de Seguridad para entornos Microsoft

En innumerables ocasiones nos hemos encontrado con que debemos de realizar una auditoría de seguridad, analizar vulnerabilidad o simplemente detectar algún malware o código malicioso en entornos microsoft, llámese servidores o estaciones de trabajo.

En esta entrega quiero compartir con todos vosotros tres herramientas que nos ayudarán a realizar esta labor de una manera sencilla y quitándonos mucho tiempo en buscar alternativas que en ocasiones no sirven para nada.

La primera herramienta es PROCESS EXPLORER:

Process Explorer es una herramienta de la suite de sysinternals de Microsoft que nos permite identificar todos los procesos que se están ejecutando en Windows (Servidores o estaciones de trabajo) dando como resultado tanto los procesos legítimos como ilegítimos o sospechosos.

Aunque algunas personas lo confunden con el «administrador de tareas de Windows» hay que decir que NO es asi.

A través del Process Explorer podemos hacer un dump, ver el ID del proceso que está ejecutando la herramienta, matar (kill) el proceso en caliente, identificar la ruta donde esta instalado el proceso, ver el nivel de permisos a nivel de NTFS que tiene el proceso, entre muchas otras cosas.

Como bono extra de la herramienta nos da las estadisticas en tiempo real de consumo de memoria, CPU y Disco Duro.

2015-12-09_23-06-49

Esta formidable herramienta fue desarrollada por Mark Russinovich actual CIO de Azure en Microsoft.

Para descargar dar clic aquí:

https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx

 

La segunda herramienta es el Microsoft Baseline Security Analyzer (MBSA):

https://technet.microsoft.com/es-es/security/cc184924.aspx

Es una herramienta muy útil que se utiliza para realizar auditoría de seguridad y escaneo de vulnerabilidades en entornos Microsoft.

Su enfoque es para ayudar a las pequeñas y medianas compañías que no cuentan con un departamento de tecnología especializado en seguridad pero desean tener sus sistemas operativos blindados con las recomendaciones por parte de Microsoft que incluyen:

  • Actualizaciones y parches de seguridad
  • Recomendaciones de Seguridad
  • Detección de vulnerabilidades de seguridad
  • Auditoría de seguridad

woorden-wdb-gif-mbsa

Es importante destacar que se puede escanear múltiples ordenadores lo que hace muy simple el poder ver como esta el estado de seguridad de mis servidores o estaciones de trabajo.

Los sistemas operativos soportados por MBSA son:

Windows 2000, Windows 7, Windows 8, Windows 8.1, Windows Server 2003, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Vista, Windows XP .

Puedes descargar la herramienta dando clic aquí:

https://www.microsoft.com/en-us/download/details.aspx?id=7558

 

La tercera herramienta es Microsoft Malicious Software Removal Tool (MSRT):

microsoft-malicious-software-removal-tool

Esta última herramienta nos permite detectar y eliminar software y codigos maliciosos (malware) en nuestros servidores y ordenadores con sistemas operativos.

  • Microsoft Windows XP Professional
  • Microsoft Windows XP Home Edition
  • Microsoft Windows Server 2003, Standard Edition (32-bit x86)
  • Microsoft Windows Server 2003, Enterprise Edition (32-bit x86)
  • Windows Vista Home Basic
  • Windows Vista Home Premium
  • Windows Vista Business
  • Windows Vista Enterprise
  • Windows Vista Ultimate
  • Windows Server 2008 Standard
  • Windows Server 2008 Enterprise
  • Windows 7 Enterprise
  • Windows 7 Enterprise N
  • Windows 7 Home Basic
  • Windows 7 Home Premium
  • Windows 7 Home Premium N
  • Windows 7 Professional
  • Windows 7 Professional N
  • Windows 7 Starter
  • Windows 7 Starter N
  • Windows 7 Ultimate
  • Windows 7 Ultimate N
  • Windows 8
  • Windows 8 Enterprise
  • Windows 8 Pro
  • Windows Server 2012 Datacenter
  • Windows Server 2012 Essentials
  • Windows Server 2012 Foundation
  • Windows Server 2012 Standard
  • Windows 8.1 Enterprise
  • Windows 8.1 Pro
  • Windows 8.1
  • Windows Server 2012 R2 Datacenter
  • Windows Server 2012 R2 Standard
  • Windows Server 2012 R2 Essentials
  • Windows Server 2012 R2 Foundation
  • Windows 10

Esta herramienta he de confesar que me ha salvado en muchas ocasiones como por ejemplo cuando la crisis en su momento del malware Conficker, realizando un sencillo script que permitía ejecutar la herramienta de manera silenciosa en los ordenadores y servidores se pudo eliminar y controlar el malware.

Muchos administradores de sistemas siguen utilizando este script en el inicio de sesión de los usuarios, es una manera efectiva de mantener los ordenadores limpios de codigos maliciosos.

Para más detalles podemos ir al siguiente enlace, donde adicionalmente podemos descargar la herramienta.

https://support.microsoft.com/en-us/kb/890830

Hasta la próxima…..