Hace algunos meses contacte con Jaime (DragonJar) sobre la posibilidad de distribuir el libro 25 Técnicas aplicadas a campañas de Red Team y Hacking en Colombia, ya que algunas personas que contactaron conmigo me habían expresado la dificultad de conseguir el libro por Amazon. Finalmente, el paquete ha llegado y se encuentra disponible para la venta. Si vives en Colombia y quieres obtener tu copia contacta con ellos directamente por correo electrónico, escribe un mensaje a contacto@dragonjar.org para reservar tu copia. Te recomiendo que lo hagas rápido ya que he enviado solo unos pocos ejemplares y seguro que se agotan pronto.
Lo cierto es que este paquete ha llegado bastante rápido a su destino, lo cual me alegra, sin embargo no he tenido tanta suerte con otro paquete que he enviado hace más de 4 meses a Chile (y aún no lo entregan). Han habido muchas complicaciones para enviar paquetes allí, supongo que la situación actual no ayuda pero lo cierto es que ahora hay que tener cuidado con las empresas de transporte que realizan pedidos internacionales. Para que os hagáis una idea y no os pase lo mismo que a mi, hace unos meses, el primer intento de envío a Chile fue con la «empresa» TNT, empresa entre comillas, porque lo cierto es que les asignaría etiquetas menos amables. Esta «empresa» una vez recibido el dinero del envío, vinieron por el paquete y 2 semanas después lo devolvieron porque ellos mismos extraviaron un documento. Devolución del dinero del envío -> cero euros. Es decir, que ese dinero salio de mi bolsillo y aún así he tenido que buscar a otro transportista para intentar cumplir con lo acordado con la tienda de 8dot8.
Solamente espero que algún día llegue a su destinatario, ahora estamos teniendo otro problema con la empresa de transporte allí en Chile que tiene un retraso importante en la entrega, pero al menos ya está en el país y continuamos presionando para que finalmente entreguen el paquete. Siento mucho el retraso para todas aquellas personas que viven en Chile y ya han reservado un ejemplar, hacemos todo lo que podemos.
Tanto las copias que he enviado a Colombia como las que pronto estarán disponibles en la tienda de 8dot8 en Chile se encuentran dedicadas y en este caso, quería que fuesen dedicatorias más personales y no tanto una dedicatoria estándar (el mismo mensaje para todos los libros). Quería imprimir un toque personal en dichas copias escribiendo algunas de las cosas que pienso y algunos principios con los que oriento mi forma de vivir. Supongo que algunas personas se sentirán identificadas o les podrá servir en momentos en los que posiblemente, no se encuentren en una buena situación. He tomado fotos de algunas de esas dedicatorias antes de enviarlas, para compartirlas con todos vosotros aquí.
Con este post me despido por algunas semanas. Espero que disfrutes del verano y que sigas avanzado. Pronto escribiré más artículos en este blog para continuar con el ritmo de publicaciones que he mantenido en los últimos meses.
En la primera parte de esta serie de corta de dos post que puedes leer aquí, se explicaba cómo instalar el SDK de Python para interactuar con un servicio de Docker y consultar características básicas de dicho servicio así como la posibilidad de listar contenedores, imágenes y volúmenes. A continuación, se hablará sobre algunas de las cosas que se pueden hacer con un objeto DockerClient
Gestionar Contenedores
Como se ha visto en la primera parte de estos posts, la clase Containers a la que se puede acceder desde el cliente de Docker, permite listar, crear, eliminar y modificar contenedores de una forma muy simple. De hecho, si se sabe cómo utilizar el cliente de Docker para Linux, entender los métodos disponibles en dicha clase resultará algo natural y bastante sencillo ya que es muy similar a lo que se puede hacer con el cliente de Docker. La documentación disponible del SDK de Python ayuda a comprender los métodos y parámetros disponibles.
El primer método que merece la pena analizar es run el cual simplemente permite ejecutar un contenedor con los parámetros indicados. Dichos parámetros incluyen cosas como el nombre de la imagen, recursos que se van a asignar al contenedor en términos de CPU y memoria, volúmenes, servidores DNS personalizados, conexiones con otros contenedores por medio de una red existente, puntos de montaje, puertos internos y externos y hasta un listado de capabilities en Linux. Por ejemplo:
El objeto que devuelve la invocación del método run permite acceder a información del contenedor, pero no solo eso, permite también gestionar su estado y acceder a la información de los logs que se van registrando.
Como se puede apreciar utilizando la instancia del objeto Container se pueden hacer muchas cosas, todas ellas se encuentran debidamente documentadas en resultan fáciles de implementar.
Gestionar imágenes
Del mismo modo que ocurre con los contenedores, es posible gestionar imágenes utilizando el SDK de Docker para Python. Es posible construir imágenes desde cero con el método build o hacer un pull de una imagen existente, algo que de hecho, también se hace de forma automática cuando se crea un contenedor con el método run o simplemente cuando se intenta crear un contenedor y la imagen especificada no se encuentra disponible localmente en el servicio de Docker.
Todas las operaciones que se aprecian en la imagen anterior se encuentran disponibles en la documentación correspondiente a la clase Images. Con métodos sencillos se pueden hacer cosas como listar, modificar o eliminar imágenes, además la clase Image cuenta con varios métodos que permiten descargar el contenido de la imagen localmente en un fichero en formato tar.gz o crear nuevas tags. Lo mismo que se hace con el cliente de Docker.
Gestionar redes.
Las redes en Docker representan uno de los elementos más básicos y potentes en el mundo de los contenedores utilizando esta tecnología y por supuesto, permiten conectar contenedores entre sí o aislarlos siguiendo una serie de criterios previamente establecidos. Nuevamente, el objeto DockerClient permite realizar todas las gestiones relacionadas con las redes por medio de la clase Networks
Se pueden crear redes, eliminarlas y conectarlas con contenedores que se encuentren previamente creados. Es equivalente a utilizar el comando docker network en el cliente de Docker para Linux.
Gestionar volúmenes.
Otra característica muy común en el mundo de Docker es precisamente la posibilidad de almacenar información de manera persistente por medio de los volúmenes. Los contenedores se caracterizan por ser efímeros y precisamente por ese motivo, los volúmenes representan una solución efectiva al problema de la persistencia en dichos entornos. Se pueden crear de dos formas si utiliza el cliente de Docker, o bien de forma implícita en el proceso de creación de contenedores o de forma explicita por medio del comando «docker volume«. En el caso del SDK de Python para Docker, este comportamiento se conserva. Es decir, en el momento en el que se invoca el método client.Containers.run si se indica que se debe crear un volumen, éste se creará durante el proceso de creación del contenedor y si se utiliza la clase client.Volumes será posible crear volúmenes de forma explicita los cuales luego se pueden vincular a un contenedor.
En este segundo post se ha podido comprobar lo fácil que puede ser gestionar un servicio de Docker utilizando el SDK de Python, algo que puede venir muy bien a la hora de gestionar contenedores o cualquier otro componente disponible en el servicio de Docker.
Como muchos ya sabéis, Docker es una tecnología que ha tenido muy buena aceptación a la hora de virtualizar entornos y hacer que el trabajo de configurar ciertas herramientas y aplicaciones sea una tarea más sencilla gracias al uso de imágenes y ficheros Dockerfile que ya vienen preparados con todo lo necesario para «descargar y ejecutar». Se trata de una tecnología cuyo uso básico no es complejo, pero tiene características que le convierten en una solución muy potente y flexible, lo que implica también cierto nivel de dificultad a la hora de aplicar ciertas configuraciones.
Dicho esto, en los siguientes dos artículos explicaré cómo crear scripts en Python que permitan automatizar el proceso de creación de contenedores y su posterior gestión. Se trata de labores que normalmente se hacen desde el cliente de Docker para Linux, por ejemplo, pero en ocasiones resulta conveniente ejecutar dichas operaciones de forma programática y aunque sería una solución perfectamente valida utilizar batch, no es una alternativa tan limpia y potente como la posibilidad de realizar todo el proceso desde un script en Python.
NOTA:Antes de continuar, si no tienes conocimientos en Docker y te interesa aprender los fundamentos de esta tecnología (algo que te recomiendo) hace algunos meses he publicado un curso en Udemy en el que se explica desde cero cada una de las cuestiones a tener en cuenta para utilizarlo correctamente. Docker y DevOps: De novato a experto.
Bien, ahora para poder interactuar con un servicio de Docker hay varias alternativas disponibles, aunque las más comunes consisten en ejecutar las instrucciones utilizando la clase Popen de Python e ir manejando el stderr, stdin y stdout de forma manual (casi que artesanal) o un enfoque más limpio que consiste en utilizar el SDK de Docker para Python. Evidentemente esta última alternativa será la que se explicará en estos dos artículos.
Instalar el SDK de Docker para Python.
En primer lugar, el SDK de Python es una librería muy completa que tiene todo lo que se necesita para aprovechar las características disponibles en un servicio de Docker. Dichas funcionalidades van desde la creación de contenedores, hasta la gestión de volúmenes e imágenes. Su potencia no es nada despreciable y es la alternativa número 1 si se necesita controlar Docker de forma programática desde Python. Cabe aclarar que hay SDKs para otros lenguajes de programación, en el caso de que sea necesario utilizar otro lenguaje por el motivo que sea. La documentación del SDK de Docker para Python se encuentra disponible en el siguiente enlace y como se puede ver en la página de introducción, se encuentra disponible en Pypi por lo tanto es tan simple como ejecutar el comando de instalación típico pip install docker. No obstante hay que tener en cuenta un detalle importante y es que si el servicio se ha configurado para aceptar conexiones seguras vía TLS, el cliente debe tener la CA del servicio y opcionalmente, en el caso de que se requiera Mutual TLS, un certificado creado para efectos de autenticación en el cliente. Además de esto, también sería necesario instalar pip install docker[tls]
Una vez instalado el SDK en un VirtualEnv o directamente sobre el interprete de Python ubicado en el PATH del sistema, es el momento de comprobar que funciona correctamente. Es tan simple como ejecutar la importación del paquete correspondiente e intentar ejecutar una conexión contra el servicio de Docker.
En la imagen anterior se aprecian varias cosas, en primer lugar se crea una instancia del cliente de Docker para Python que se encuentra en el SDK y partiendo de dicha instancia, se crea un contenedor. Si se sabe utilizar el cliente de Docker para Linux no habrá ningún problema en entender la instrucción que crea dicho contenedor. En resumen, es equivalente a ejecutar el comando docker run con la imagen «alpine», cuyo nombre será «testing_from_python» en modo «detach» y con la posibilidad de generar una shell TTY. Finalmente, se crea un volumen en donde el directorio «/root» en el sistema anfitrión se montará en el directorio «/mnt/voltest» en el contenedor y dicho volumen será de lectura y escritura desde dicho contenedor. Fácil, no? esto queda perfectamente aclarado en el curso de Docker y DevOps: De novato a experto. disponible en Udemy.
Utilidades básicas del SDK de Docker para Python.
Como se ha podido comprobar, crear contenedores resulta una labor sencilla utilizando el SDK de Docker, pero esto no es todo lo que se puede hacer. Entre otras cosas, es posible gestionar el propio servicio de Docker, volúmenes, imágenes, contenedores, redes y todo lo que normalmente se puede hacer desde el cliente de Docker para Linux. En lo que queda de este post y en el siguiente, se explicarán algunas de estas características disponibles en el SDK de python.
Información del proceso Docker.
Con una instancia del cliente de Docker es posible ejecutar el método info() el cual simplemente devuelve un diccionario con toda la información disponible sobre el servicio de Docker. De hecho, esto es equivalente a ejecutar el comando docker info desde la terminal.
Devuelve un diccionario completo con toda la información del proceso con la ventaja de que evidentemente, se puede procesar para extraer solamente las propiedades que sean necesarias en un momento determinado para ejecutar algún tipo de operación, validación o un bloque de código en el programa que requiera de estos valores.
Entorno del cliente de Docker.
En el momento en el que se crea una instancia del cliente de Docker utilizando el método «from_env()» lo que está ocurriendo es que se leen una serie de variables de entorno muy especificas que de no encontrarse establecidas, la librería asumirá nos valores por defecto. Dichas variables incluyen el host y puerto en el que se encuentra en ejecución el servicio de Docker. No obstante, hay otras formas de instanciar el cliente, por ejemplo sería perfectamente valido crear una instancia de la clase DockerClient e indicar, por ejemplo, la ubicación del socket Unix correspondiente al servicio o indicar manualmente la IP/Dominio y puerto en el que se encuentra en ejecución.
Como se puede apreciar, se ha utilizado el parámetro «base_url» que apunta a un socket de red o uno de Unix tal como se ha indicado anteriormente. Crear un objeto cliente perfectamente funcional se puede conseguir con 2 líneas de código.
Listado de imágenes, contenedores y volumenes.
Para finalizar este post introductorio, se explicarán algunas funciones sencillas disponibles en el cliente de Docker para el listado de imágenes, contenedores y volúmenes que se encuentran actualmente registrados en el servidor. Cada una de estas características (así como otras más) se encuentran debidamente separadas en clases independientes, las cuales no solamente permiten el listado de los objetos disponibles en el servidor de Docker, sino que además permite su gestión. Por ejemplo, tal como se ha visto antes, es posible crear un contenedor que quedará registrado en el servicio de Docker gracias al método run que se encuentra definido en la clase Containers
Como se puede ver, el objeto DockerClient contiene todo lo necesario para acceder a los elementos principales del servidor. En la imagen anterior simplemente se listan los contenedores, imágenes y volúmenes que en este momento se encuentran registrados en el servicio de Docker pero sería posible crear nuevas imágenes con configuraciones muy completas, así como crear volúmenes y contenedores partiendo de alguna imagen (tal como se ha visto anteriormente).
Como en todas las librerías disponibles en Python que sigue la filosofía del lenguaje, o como muchos suelen llamar: «pythonic», se trata de una librería que cuenta con componentes fáciles de utilizar y que con pocas instrucciones permiten realizar labores que en otras circunstancias o con otros lenguajes de programación requeriría más esfuerzo.
Este primer post es muy sencillo y se pueden apreciar las características básicas del SDK de Python. En el siguiente se verán más cosas que se pueden hacer con esta librería y a lo mejor, te puede ser útil para integrarla en tus proyectos con Docker.
Continuando con lo que se ha explicado en el primer post de Buenas prácticas en Docker – Parte 1 de 2 se listarán ahora algunas buenas prácticas adicionales que representan los conocimientos mínimos que se deben de tener para utilizar esta tecnología de forma efectiva.
Evitar la ejecución de contenedores con root.
La mejor forma de evitar ataques de elevación de privilegios desde el interior de un contenedor es configurar las aplicaciones que se ejecuten en él con privilegios de usuarios regulares (sin privilegios administrativos de ningún tipo). El cliente de docker cuenta con la opción “-u” o “–user”para especificar un nombre de usuario o ID, esto es importante tenerlo en cuenta ya que por defecto todos los contenedores se ejecutan con privilegios de root y aunque el contenedor está debidamente aislado, un atacante tendrá pleno control sobre dicho contenedor en el caso de que consiga comprometerlo.
Utilizar la instrucción USER en los ficheros DockerFile.
En el diseño de imágenes la instrucción USERen el fichero DockerFile permite especificar un usuario distinto a “root” en un momento concreto de la ejecución. De ésta forma, es posible ejecutar instrucciones como “root” en el DockerFile cuando sea necesario y posteriormente cambiar de usuario a uno sin privilegios con dicha instrucción. Por ejemplo:
En el caso anterior, es necesario contar con privilegios de root para instalar paquetes y otras cuestiones de configuración, pero una vez dicha operación termina, se cambia el contexto de usuario para ejecutar los contenedores que se creen partiendo de la imagen anterior con un usuario concreto (definido por su identificador).
Especificar únicamente las capabilities necesarias y evitar la flag “privileged”.
Por defecto, todos los contenedores en Docker son “no privilegiados”. Esto quiere decir que por ejemplo, dentro de un contenedor no es posible ejecutar otro servicio Dockerd o manipular características importantes del sistema host. Sin embargo, un contenedor privilegiado, es aquel que tiene acceso a todos los dispositivos y puede manipular características importantes del sistema anfitrión como la configuración de SELinux o AppArmor, lo que le permitirá al contenedor tener prácticamente el mismo nivel de acceso sobre el sistema host.
Para crear un contenedor privilegiado se utiliza la flag “–privileged” y por defecto permite el acceso a todos los dispositivos del host anfitrión. Para limitar dicho nivel de acceso se puede combinar con la flag “–device”
docker run –privileged –device=/dev/snd:/dev/snd docker run –device=/dev/sda:/dev/xvdc –rm -it ubuntu fdisk /dev/xvdc docker run –device=/dev/sda:/dev/xvdc:r –rm -it ubuntu fdisk /dev/xvdc docker run –device=/dev/sda:/dev/xvdc:w –rm -it ubuntu fdisk /dev/xvdc
Además de la opción “–privileged”, en Docker también existe la posibilidad de controlar las “capabilities” de Linux por medio de las opciones “–cap-add” y “–cap-drop”, lo cual permite tener un control muy fino sobre lo que se puede y no se puede hacer dentro del contenedor. La mejor política de seguridad consiste precisamente en eliminar todas las capabilities y añadir solamente aquellas que sean necesarias:
docker run –cap-drop=ALL –cap-add=NET_ADMIN –cap-add=CAP_NET_BIND_SERVICE
Limitar el acceso a recursos desde el contenedor (memoria y CPUs).
Por defecto, no hay restricciones de forma implícita en los recursos que puede consumir un contenedor y aunque gracias a cgroups es posible evitar condiciones de denegación de servicio, es altamente recomendable utilizar las opciones disponibles en Docker para poner limites de forma explicita a los contenedores creados. Las principales opciones se listan a continuación:
Gestión de la memoria.
-m or –memory=
Memoria máxima que el contenedor podrá usar. El valor mínimo para esta opción es 4m (4 megabytes).
–memory-swap*
La cantidad de memoria que el contenedor puede “swapear” al disco.
–memory-reservation
Permite especificar un límite blando (soft limit) más pequeño que el valor indicado con la opción «-m». Este límite se activa cuando Docker detecta contención o poca memoria en el sistema host.
–kernel-memory
Indica la cantidad máxima de memoria del kernel que podrá usar el contenedor. El valor minimo permitido es de 4M.
Gestión de la CPU.
–cpus=<value>
Especifica la cantidad de recursos disponibles en la CPU puede usar el contenedor. Por ejemplo, si el host tiene 2 CPUs y se establece la opción con –cpus=»1.5″, el contenedor tendrá garantizado el uso de al menos uno y medio de CPUs.
–cpuset-cpus
Especifica los cores concretos que el contenedor puede usar. Cada CPU está numerada desde 0. Es posible indicar que el contenedor puede usar los cores de 0 a 4 con el valor “0-3” o que el contenedor puede usar los cores 2 y 4 especificando los valores “1,3”.
En este post has podido ver algunas de las buenas prácticas a la hora de crear y gestionar contenedores en Docker, sin embargo pueden haber muchas más. Puedes dejar un comentario en este post con las que sueles utilizar para que todos aprendamos un poco más.
Desde hace algunos años, Docker se ha convertido en una tecnología de uso habitual para cualquier profesional IT. Programadores, administradores de sistemas y profesionales de la seguridad suelen utilizarlo con frecuencia. Sus beneficios son innegables y ha ayudado a definir las bases de que hoy en día conocemos como la «arquitectura basada en microservicios«. Si bien se «parece» a las tan extendidas y conocidas máquinas virtuales, existen diferencias notables, especialmente relacionadas con el rendimiento y el uso que se le suele dar a un contenedor. De hecho, la siguiente imagen ilustra bastante bien las diferencias entre una máquina virtual clásica y un contenedor en Docker.
Las máquinas virtuales dependen de un Hypervisor y sobre éste, se van montando diferentes sistemas operativos con todo lo que esto implica (librerías, aplicaciones, etc). En el caso de Docker, cada contenedor es gestionado por el servicio de Docker y éste se aprovecha de las características del sistema operativo subyacente.
Esta breve introducción probablemente ya te la conoces y no es el objetivo de este post explicar cómo utilizar las funcionalidades básicas de Docker sino comentar algunas de las mejores prácticas o «tips» para utilizar esta tecnología. No obstante, si estás interesado en aprender las bases y todo lo necesario para dominar Docker y Docker-Compose, te recomiendo que le eches un vistazo al curso en Udemy: Docker y DevOps de Novato a Experto.
Usar ficheros .dockerignore.
Cuando se ejecuta el comando “docker build” todos los ficheros del PATH o URL indicada, se envían al servidor de Docker (Docker Engine). Es recomendable usar un directorio vacío, incluir en él solamente aquello que se vaya a necesitar y posteriormente construir la imagen con docker build. Es común encontrarse que el contenido de dicho directorio crezca en la medida que se van desarrollando o implementando nuevas características, en tal caso para mejorar el rendimiento y no enviar al Docker Engineficheros innecesarios se puede utilizar un fichero especial llamado .dockerignore. En este fichero se puede incluir por cada línea, un directorio o fichero que se excluirá de la imagen. Por ejemplo, se podrían excluir ficheros con una extensión concreta o nombre, algo parecido a lo que se hace con otras tecnologías como GIT.
No instalar paquetes innecesarios.
Para reducir la complejidad, dependencias, tiempo de creación y tamaño de la imagen, se debe evitar instalar paquetes y servicios innecesarios. Lo recomendable es comenzar con una imagen mínima, como por ejemplo “scratch” o «alpine» e instalar los paquetes que hagan falta partiendo de ella.
Minimizar el número de capas.
Tal como se ha indicado anteriormente, cada comando en el Dockerfile se encarga de generar una capa, la cual se puede borrar o cachear dependiendo de su uso en el proceso de construcción de la imagen. Es recomendable utilizar el menor número de comandos posible para reducir el número de capas intermedias y por ende, el procesamiento que debe realizar el Docker Engine a la hora de generar la imagen final.
En la medida de lo posible y para facilitar futuros cambios, hay que organizar los argumentos de las instrucciones que contengan múltiples líneas en una sola, esto evitará que durante el proceso de construcción de la imagen se deban construir múltiples capas intermedias y por supuesto, hará que el archivo sea más fácil de leer.
Por ejemplo, es mejor hacer esto:
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y wget RUN apt-get install -y apache2 RUN apt-get install -y php5
Limitar los privilegios.
Cuando se inicia un contenedor, Docker se encarga de crear un grupo de namespaces, los cuales simplemente «acordonan” el contenedor para que no interfiera con procesos del sistema host u otros contenedores. Se trata del mecanismo estándar que incluye Docker para evitar que un contenedor mal configurado o con brechas de seguridad pueda ser utilizado para atacar el sistema host. Aunque los namespaces suponen un mecanismo de seguridad potente en Docker, cuando se habla de seguridad siempre hay que intentar aplicar el principio del “último privilegio”, el cual indica que la arquitectura de un sistema debe tener únicamente las características necesarias para su correcto funcionamiento y que dichas funciones deben de estar debidamente limitadas. Quiere decir que los contenedores y todos los elementos que incluyen deben tener un conjunto muy limitado de funciones, servicios, librerías y herramientas: Únicamente aquello que sea estrictamente necesario para su funcionamiento. Dicho esto, es recomendable ajustar los privilegios del contenedor, en primer lugar evitando que se ejecute como root y en segundo lugar ajustando las “capabilities” con opciones como “–cap-drop” y “–cap-add”.
Esto es todo de momento, en el siguiente post se verán algunas otras recomendaciones de seguridad a la hora de trabajar con Docker.
En el primer post sobre la herramienta PWNDoc que puedes consultar aquí he explicado los detalles de instalación y configuración básicos para poder ejecutar la herramienta. En esta ocasión se verá cómo redactar el informe de auditoría utilizando PWNDoc y los beneficios que aporta.
Configuración de la auditoría en PWNDoc.
En el post anterior se ha creado un objeto auditoría que se ha vinculado con un lenguaje y una plantilla compatible con la herramienta (se ha utilizado la plantilla por defecto que viene incluida en el proyecto y que se puede descargar desde aquí). El siguiente paso consiste en definir las vulnerabilidades que estarán vinculadas al informe de auditoría. Para ello, solo hace falta dirigirse a «Vulnerabilities» y pinchar en el botón que pone «New Vulnerability». Sin embargo, como se puede apreciar no hay ninguna categoría configurada y para mantener un orden y que sea más fácil de gestionar posteriormente, es mejor dirigirse a «Data» -> «Custom Data» y crear los tipos de vulnerabilidades y sus correspondientes categorías, evidentemente dependerá del contexto de la auditoría por lo tanto estos valores se deben introducir manualmente.
Una vez que se han introducido los tipos de vulnerabilidades y categorías, se puede editar la auditoría que se ha creado anteriormente y comenzar a describir los descubrimientos, defectos y vulnerabilidades.
El formulario que se puede apreciar en las imágenes anteriores se encuentra disponible en la sección de»Findings» de la auditoría y una las características más interesantes que tiene PWNDoc en este punto es que permite incluir todos los detalles que sean necesarios, incluyendo capturas de pantalla. Además, en la sección de «DETAILS» permite afinar aún más el descubrimiento/vulnerabilidad con el fin de asignarle un valor en función de su criticidad.
Como se puede apreciar en la imagen anterior, la herramienta determina el «score» siguiendo el modelo CVSSv3 y además, permite incluir contramedidas a aplicar.
A partir de este punto el uso de la herramienta consiste básicamente en hacer el mismo proceso de reportar cada una de las vulnerabilidades o defectos encontrados, introducir los detalles de dichos defectos, asignar de forma automática una puntuación en base al CVSSv3 y definir una serie de contramedidas con una prioridad especifica. Como se puede ver el uso de la herramienta es simple y permite seguir un orden en el trabajo, tener todo bien categorizado y en su sitio.
Cuando se ha terminado de introducir los «Findings» es el momento de volver al menú principal de «Audits» y descargar el informe en formato DOCX.
Como se puede ver en la última imagen aparece toda la información que se ha introducido sobre cada vulnerabilidad. El documento aparece bien ordenado y toda la información que se ha ido introduciendo en cada una de las secciones de la aplicación por lo tanto cumple con su objetivo y permite trabajar de una forma mucho más cómoda, simplemente por el hecho de que puedes crear cada detalle informativo poco a poco y no tienes que molestarte en ajustar formatos o moverte por documentos de texto que probablemente serán extensos debido al uso de imágenes, tablas y otros elementos (que también los soporta PWNDOC, es posible subir imágenes como capturas de pantalla para demostrar una vulnerabilidad).
Se trata de una herramienta que es fácil de manejar y muy útil para labores de auditoría tan comunes como redactar informes. Te recomiendo que la pruebes y compartas tu experiencia para que más personas se animen a probarla.
Anteriormente he escrito un par de artículos sobre algunas pautas para redactar documentos de auditoría que puedes consultar en los siguientes enlaces:
En dichos posts mencionaba recomendaciones que suelo tener en cuenta cuando tengo que presentar un informe y he compartido algunas plantillas que me parecen interesantes y se encuentran disponibles públicamente. En esta ocasión hablaré sobre una herramienta que pretende dar soporte a la creación de informes de una manera interactiva y con algunas ayudas para el pentester, se trata de PWNDoc
Creación de informes con PWNDoc
Tal como describe en el proyecto, se trata de una utilidad que pretende acelerar el proceso de elaboración de informes para que el pentester o equipo de auditores puedan dedicarse a otras cosas más apasionantes, como detectar y explotar vulnerabilidades. La aplicación se encuentra desarrollada con Node.js y permite gestionar cada detalle del informe y aunque al principio puede resultar un poco confuso su uso, con un poco de paciencia se consigue dominar y aprovechar sus funcionalidades.
En primer lugar, el proceso de instalación es sencillo ya que se basa en 3 contenedores Docker que se despliegan fácilmente utilizando Docker-compose, tal como se indica en la guía de instalación disponible aquí. Lo que sí hay que tener en cuenta es que la construcción es un proceso lento y puede tardar algunos minutos. A continuación, solo hace falta acceder con un navegador web por HTTPS al puerto 8443 y lo primero que enseñará la aplicación web es un formulario para crear un usuario, algo bastante simple y directo. Una vez registrado en el sistema, aparecerán los mensajes que se aprecian en la siguiente imagen.
Tal como se puede ver es necesario configurar el lenguaje que se utilizará y el tipo de auditoría.
El lenguaje es algo bastante simple, se debe indicar el nombre del lenguaje y su locale, este segundo valor tal como se indica en la documentación será necesario en el caso de usar la API Rest que tiene el proyecto.
Lo otro que se debe configurar es el tipo de auditoría en la sección «Audit Types» y aquí es en donde se complica un poco el uso de la herramienta ya que es necesario subir una plantilla en formato Docx, pero no cualquier plantilla. Tal como se indica en la documentación la herramienta utiliza una librería en Node.js llamada Docxtemplater que es precisamente la que permite realizar las modificaciones y generación dinámica del documento Docx. Esta librería y por ende, la herramienta, requiere que la plantilla tenga una serie de tags que identifican exactamente en qué parte del documento se debe incluir un contenido o texto y por lo tanto se deben definir dichas tags en el documento. Afortunadamente, en PWNDoc existe una plantilla en formato DOCX llamada Default template.docx que se puede usar para generar informes. Aclarado esto, lo siguiente antes de poder crear un «Audit Type» es precisamente subir dicha plantilla en formato DOCX. Para ello hay que dirigirse a Data -> Templates -> Create template tal como se enseña en la siguiente imagen.
Ahora es posible dirigirse a Data -> Custom data -> Audit Types y cumplir este último requisito de configuración para empezar a usar la herramienta.
Ahora es el momento de empezar a confeccionar el informe como tal, para ello se pueden introducir cada uno de los campos que aparecen en el menú lateral izquierdo: «Colaboradores», «Compañías» y «Clientes». La información que se introduzca en estas secciones aparecerá en el informe final, aunque como es evidente el documento generado es editable y se puede cambiar a posteriori si hace falta.
Si se pretende trabajar en equipo la herramienta permite crear colaboradores y asignarle a cada uno de ellos diferentes tipos de roles y permisos. Es algo que de momento se debe hacer manipulando directamente las estructuras JS del programa pero probablemente será una función que se incorporará al Frontend en un futuro (espero). En todo caso, en la documentación oficial explica cómo asignar permisos a los usuarios creados desde la sección de colaboradores.
Ahora, se puede proceder a crear un objeto auditoría en la herramienta introduciendo los detalles básicos:
Como se puede apreciar se han introducido los datos básicos de la auditoría y además, permite definir el alcance de la misma para que luego sea incluido en el reporte final.
A partir de este punto, se procede a redactar el informe y a configurar otros elementos de la herramienta que son extremadamente útiles. Esto lo explicaré en el siguiente post.
Para ofrecer las mejores experiencias, utilizamos tecnologías como las cookies para almacenar y/o acceder a la información del dispositivo. El consentimiento de estas tecnologías nos permitirá procesar datos como el comportamiento de navegación o las identificaciones únicas en este sitio. No consentir o retirar el consentimiento, puede afectar negativamente a ciertas características y funciones.
Funcional
Siempre activo
El almacenamiento o acceso técnico es estrictamente necesario para el propósito legítimo de permitir el uso de un servicio específico explícitamente solicitado por el abonado o usuario, o con el único propósito de llevar a cabo la transmisión de una comunicación a través de una red de comunicaciones electrónicas.
Preferencias
El almacenamiento o acceso técnico es necesario para la finalidad legítima de almacenar preferencias no solicitadas por el abonado o usuario.
Estadísticas
El almacenamiento o acceso técnico que es utilizado exclusivamente con fines estadísticos.El almacenamiento o acceso técnico que se utiliza exclusivamente con fines estadísticos anónimos. Sin un requerimiento, el cumplimiento voluntario por parte de tu Proveedor de servicios de Internet, o los registros adicionales de un tercero, la información almacenada o recuperada sólo para este propósito no se puede utilizar para identificarte.
Marketing
El almacenamiento o acceso técnico es necesario para crear perfiles de usuario para enviar publicidad, o para rastrear al usuario en una web o en varias web con fines de marketing similares.