Últimamente me estoy acercando más a la ciberseguridad, tanto en mi carrera profesional como en mi tiempo libre. He participado en algunos CTFs con Scavenger Security. Aparte, estoy haciendo el curso de desarrollo de software de Biko para, entre otras cosas, ampliar mis conocimientos en las muchas tecnologías que envuelven el mundo del desarrollo web: librerías de JavaScript como React y frontend en general, TypeScript y Node.js en el backend… Si unimos todo esto a la importancia que siempre le he dado (y cada vez más) a la documentación, parece que era cuestión de tiempo que un día me metiera en harina con HackMD.

/índice:

Historia de forks: ¿HackMD? ¿CodiMD? ¿HedgeDoc?

TL;DR: Ahora HackMD es la marca enterprise, y HedgeDoc, la versión desarrollada por la comunidad. CodiMD se ha quedado como la versión que libera el equipo de HackMD, con funcionalidades limitadas.

La historia de HackMD es la de otra herramienta abierta cuyo desarrollo se divide en el momento justo en el que se plantean cómo rentabilizar el negocio. Según explican, dos años después de su lanzamiento se separaron en la versión CE (Comunity Edition) y EE (Enterprise Edition). La versión privada se reescribe entonces en TypeScript y se comercializa en hackmd.io, orientándose más hacia el modelo freemium y lo social-media. La comunidad en 2018 renombró su proyecto como CodiMD, para evitar confusiones. Por tanto, su fork pasó a estar en github.com/codimd/server. Pero el equipo de HackMD mantuvo también un repositorio de CodiMD bajo su organización (github.com/hackmdio/codimd), así que la gente no se aclaraba con la diferencia entre HackMD y CodiMD. Total, que en 2020 la comunidad vuelve a elegir un nuevo nombre, HedgeDoc, y también reescriben el código en TypeScript.

La verdad es que HackMD se quedaron con el nombre bueno, para qué engañarnos.

Funcionalidades

HackMD tiene muchas funcionalidades que ya detallan ellos en su tutorial de introducción. Yo destaco las dos ventajas clave que le veo frente a apuntar en un bloc de notas:

  1. Puedes subir pantallazos simplemente con copiarpegar

  2. Puedes compartir una url y editar colaborativamente

¿Eso no lo puedo hacer con Google Docs? Sí, y con Microsoft Word, que son los procesadores de texto WYSIWYG más conocidos. Pero escribir texto mientras peleas con la maquetación en una hoja de papel simulada no es lo que buscamos con los editores de Markdown. Utilizamos Markdown para escribir con formato enriquecido mediante un lenguaje de marcado muy sencillo, conservando los aspectos de formato más útiles (títulos, tablas, enlaces, etc.) y desechando los más prescindibles (alineación del texto, fuente, colores, saltos de páginas)1. También puede interesarte alojar tú mismo la herramienta, y así controlar hasta dónde la expones.

Además, el formato Markdown está extendido por todas partes. Por ejemplo, si luego te quieres llevar la nota que has redactado a un sitio web estático generado digamos con Jekyll (como este mismo blog, o como el de Scavenger Security), puedes añadirla tal cual está. Incluso puedes automatizar esa exportación (incluida la manipulación de etiquetas, títulos e imágenes) con un script como este hackmd2writeup.py.

Instalación

Entre todos los sabores de HackMD, vamos a elegir HedgeDoc, por estar más activo y abierto a la comunidad. Hay varios métodos de instalación. Para entender qué estamos haciendo, lo recomendable es la instalación manual. Con esta configuración mínima:

$ cat config.json
{
  "production": {
    "host": "localhost",
        "db": {
          "dialect": "sqlite",
          "storage": "./db.hedgedoc.sqlite"
       }
  }
}

Ya podemos probar a levantar HedgeDoc:

$ export NODE_ENV=production
$ yarn start
yarn run v1.22.15
$ node app.js
warn: Neither 'domain' nor 'CMD_DOMAIN' is configured. This can cause issues with various components.
Hint: Make sure 'protocolUseSSL' and 'urlAddPort' or 'CMD_PROTOCOL_USESSL' and 'CMD_URL_ADDPORT' are configured properly.

Pero, si vamos a http://localhost:3000 en un navegador y abrimos la consola de “Herramientas para desarrolladores”, vemos la consecuencia del warning que nos está dando HedgeDoc en sus logs:

¿Qué pasa? Que se está aplicando Content Security Policy, un mecanismo que ayuda a prevenir algunos ataques tipo XSS. Como por ahora solo queremos servírnoslo en local, podemos desactivar el uso de SSL y permitir los orígenes “localhost” y “hedgedoc.org” para que carguen los ficheros CSS y Javascript:

$ cat config.json
{
  "production": {
    "domain": "localhost",
    "urlAddPort": true,
    "useSSL": false,
    "allowOrigin": ["localhost", "hedgedoc.org"],
    "host": "localhost",
        "db": {
          "dialect": "sqlite",
          "storage": "./db.hedgedoc.sqlite"
       }
  }
}

También podemos externalizar la autenticación usando OAuth. Pongamos que lo hacemos con Github, por simplificarnos este tema:

$ cat config.json
{
  "production": {
    "domain": "localhost",
    "urlAddPort": true,
    "useSSL": false,
    "allowOrigin": ["localhost", "hedgedoc.org"],
    "github": {
      "clientID": "3747d30eaccXXXXXXXXX",
      "clientSecret": "2a8e682948eee0c580XXXXXXXXXXXXXXXXXXXXXX"
    }
    "host": "localhost",
        "db": {
          "dialect": "sqlite",
          "storage": "./db.hedgedoc.sqlite"
       }
  }
}

Guay, ya tenemos un HackMD (bueno, un HedgeDoc) funcional para nosotros mismos. ¿Y si ahora lo queremos compartir con alguien en remoto?

Proxy reverso

¿Qué es un proxy? Creo que la traducción sería “apoderado”, aunque es un término que no se suele traducir. Pero el concepto sería ese: alguien que actúa en tu nombre. Un proxy hace peticiones en tu nombre y luego te las hace llegar. Un proxy reverso se basa en la misma idea: el proxy hará de intermediario. La diferencia es que con un proxy normal tú haces de cliente (eres el que pide), mientras que, si tienes delante un proxy reverso, será porque tú tienes el rol de servidor. Es decir, es a ti a quien le quieren hacer peticiones los clientes. Al poner un proxy reverso, los clientes solo hablan con el proxy, y él es quien hace llegar las peticiones al servidor correspondiente.

¿Ventajas? Puede tener sentido para varios objetivos: conseguir una protección adicional mediante el filtrado de peticiones o la anonimización del servidor destino, trasladar la carga de establecer conexiones cifradas a la máquina que ejerza de proxy, cachear el contenido (especialmente el estático)… Las funcionalidades que ofrece un proxy son diversas. Además, cualquier servidor web es capaz de implementarlas.

En este caso, hasta ahora solo tenemos un servicio que estamos levantando para nosotros en localhost (la dirección IP de loopback 127.0.0.1, alcanzable solo desde el mismo dispositivo). Lo que vamos a hacer es configurar Nginx para que juegue este papel de proxy reverso: cuando reciba peticiones, se encargará de devolver el HackMD que tenemos escuchando en localhost. La razón principal de poner este paso intermedio aquí es que es bastante fácil integrar con Nginx el tema de los certificados y la capa de SSL sobre HTTP, sobre todo si usamos Certbot.

Certbot

Hoy en día, todas las conexiones van cifradas. Con proyectos tan sencillos de usar como Certbot, no hay excusa para no obtener un certificado y servir nuestra web por HTTPS. ¡Incluso se pueden renovar automáticamente!

Necesitamos abrir los puertos 80 y 443 en nuestro router y, en su panel de configuración, hacer portforwarding de nuestro servidor hasta el router. Así, lo que sirvamos por esos puertos será alcanzable desde internet.

También deberíamos asegurarnos de que en nuestros registros DNS (que normalmente gestionamos desde la web del proveedor al que le compramos nuestro dominio) hay una entrada “A” que une nombre con dirección IP:

Además, tenemos que arrancar Nginx con esta configuración:

$ grep -v -e '^#' -e '^$' /etc/nginx/sites-enabled/hedgedoc
map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
}
server {
        server_name hedgedoc.example.com;
        location / {
                proxy_pass http://localhost:3000;      # donde hemos levantado hedgedoc con `yarn start`
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }
    listen 80 default_server;      # para que certbot pueda hacer su verificación (luego se puede cerrar este puerto)
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    ssl_certificate /etc/letsencrypt/live/md.jartigag.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/md.jartigag.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}

Y hay que acordarse de retocar los parámetros de configuración de HackMD (este es mi config.json definitivo).

Con estos pasos previos listos y Certbot instalado, solo queda dejarle hacer su magia:

Y ya tenemos HTTPS en el sitio web:

¡Todo listo! Podemos crear una nota como esta, compartirla, pegar imágenes, definir plantillas

Si no quieres complicarte tanto, siempre puedes usar las instancias de hackmd.io o demo.hedgedoc.org

Otras alternativas interesantes

CTFNote

CTFNote es una herramienta de colaboración para ayudar a los equipos a organizar su trabajo durante los CTFs. Se integra con CTFTime, de manera que importa los datos básicos de cualquier evento registrado en esta plataforma. También cuenta con un campo para guardar las credenciales del equipo en cada evento.

Dentro de los eventos, se registran tareas. Empiezas cada una pegando a mano el enunciado o automáticamente, usando la respuesta de la API del CTF, si se ha montado con el framework CTFd. Una vez tenemos las tareas, el botón “Open task” de cada una nos abre un HackMD embebido para trabajar simultáneamente sobre un mismo documento.

Realmente cualquiera de los miembros del equipo en CTFNote invitados2 al evento puede modificar ese documento, pero alguien puede indicar de forma más explícita que está trabajando en una tarea activando “Start working on [task]”. Al conseguir una flag, se pega dentro de “Enter flag” (lógicamente CTFNote no comprueba que sea la flag válida) y esa tarea queda marcada como resuelta.

En resumen, ese es el flujo de trabajo principal. Incluye alguna funcionalidad adicional como el calendario de los CTFs que el equipo haya importado en CTFNote, pero vaya. Al final no es más que una serie de vistas con las que estructurar la edición de distintos writeups de forma colaborativa. CTFNote tan solo amplía la utilidad básica de HackMD al enriquecer la información sobre los eventos en los que se participa, sumada a unificar la gestión de usuarios.

Puede venir bien si el equipo suele elaborar el writeup según va avanzando en un reto o si prima la comunicación escrita (directamente sobre el documento), pero para casos en los que se mantiene una comunicación por voz y/o se comparte pantalla, CTFNote no aporta tanto. Tampoco potenciará las capacidades del equipo cuando lo habitual sea trabajar por separado, más allá de que los writeups estén disponibles internamente, clasificados en tareas y eventos.

Sobre los detalles técnicos, el frontend está implementado con Quasar, un framework basado en Vue.js. El backend es Express.js. Han preparado una serie de scripts y ficheros de Docker que facilitan mucho el despliegue, además de recoger una documentación bastante decente en el propio README. Es de agradecer :)

En cuanto al desarrollo, lo llevan los franceses “The Flat Network Society”. En octubre de 2021 alcanzaron la versión 2.0 (arreglaba un bug de la v1.0 que afectaba a las versiones anteriores a marzo de 2021, pero prepararon una guía de migración para subsanarlo).

Obsidian

La herramienta que más uso últimamente para tomar apuntes de todo tipo es Obsidian. En el trabajo, en mi portátil personal, en el móvil… Para documentar y para cualquier tipo de contenido escrito, lo mejor es que acabe guardado en texto plano. Eso permite llevar un registro de cambios fácilmente, sincronizar, editar, etc., todo sin atarte a una herramienta para siempre. Aunque, si quieres anotar cosas sobre la marcha, yo ahora mismo recomendaría Obsidian con “Vim key bindings” y algunos plugins, especialmente el de tablas, el de vimrc y el de git.

La exportabilidad del texto plano también permite transformar el contenido al formato que mejor se adecúe en cada situación: PDF, Word, HTML… Por ejemplo, he generado esta web con mis notas del curso de Biko usando Github Pages y mdbook, con los comandos recogidos en este Makefile. No sé, quizá en un futuro traslade algunas guías a un Wiki.js… Las posibilidades son inagotables.

Lo que sí sé es que tengo mucho más que contar sobre Obsidian de lo que cabe en este post 😂, así que aquí lo dejamos por hoy.

  1. Esto no significa que en un .md no puedan usarse estas propiedades (porque para algo está el soporte de HTML y CSS), pero no son parte fundamental del lenguaje Markdown. 

  2. Es decir, tanto aquellos con rol “Member” o superior, como aquellos con rol “Guest” que han sido invitados por un “Manager” o un “Admin”.