Creando un túnel DNS para navegar saltándose un Firewall.

Buenas tardes,

Hace ya algún tiempo publiqué una entrada haciendo referencia a túneling mediante SSH (https://www.bitsdelocos.es/2015/08/tunnel-ssh-con-raspbian-y-bitvisessh/). En esta entrada, versará sobre túneling sobre DNS (Domain Name Server). El concepto es el mismo: sobre un flujo de peticiones DNS insertar consultas forjadas de un modo conveniente parainyectar información de otro protocolo sobre DNS y así saltarse las protección de un firewall. La definición de un túnel en informática es:

Se conoce como túnel o tunneling a la técnica que consiste en encapsular un protocolo de red sobre otro (protocolo de red encapsulador) creando un túnel de información dentro de una red de computadoras.

Para poder llevar a cabo este escenario, necesitaremos:

  • Servidor: VPS o un equipo linux con una IP de internet estática.
  • Cliente: Sistema operativo linux o una máquina virtual con linux en su defecto.
  • Tener control sobre un dominio y sus entradas de DNS.
  • Tener chrome con la extensión SwitchyOmega.

La idea principal se basa en crear un subdominio al que se le harán las peticiones de DNS y un NS (Name Server o Servidor de nombres) al que enviar las peticiones malformadas. Necesitaremos añadir la siguiente configuración en nuestro DNS público:

  • tunel.bitsdelocos.es (NS apuntando a ns.bitsdelocos.es)
  • ns.bitsdelocos.es (A apuntando a la IP del VPS)

De este modo se conseguirá que todas las peticiones DNS del tipo xxxx.tunel.bitsdelocos.es se envíen a ns.bitsdelocos.es. Lo siguiente que necesitamos es montar un servidor de nombres que haga la función de resolver de paquetes generados maliciosamente que le lleguen. En este caso usaremos iodine (https://github.com/yarrick/iodine) . He usado debian 9 base como servidor de DNS. Para hacer el build de iodine necesitaremos ejecutar como super usuario:

apt-get install gcc make autoconf libz-dev git
git clone https://github.com/yarrick/iodine.git
cd iodine
make && make install

Si todo ha ido bien iodine estará instalado en nuestro sistema:

root@Debi:~# iodine -v
iodine IP over DNS tunneling client
Git version: 27e5d6f

Para hacer funcionar este servidor de DNS bastará con ejecutar:

iodined -c -P <PASSWORD> -n <IP ESTATICA> 172.16.0.1 tunel.bitsdelocos.es -F /var/run/iodine.pid

En el caso de que estemos usando la red local 172.16.0.0/24 podremos cambiar este rango por uno que no estemos usando.

Para comprobar que todo salió bien, se puede ejecutar el comando ip addr show para ver si se asignó una ip a la interfaz virtual dnsX:

root@Debi:~# ip addr show dev dns0
11: dns0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1130 qdisc pfifo_fast state UNKNOWN group default qlen 500
    link/none 
    inet 172.16.0.1/27 scope global dns0
       valid_lft forever preferred_lft forever

En nuestro PC debemos ejecutar el cliente que nos levantará el túnel contra el NS ns.bitsdelocos.es haciendo uso de resoluciones DNS al subdominio tunel.bitsdelocos.es. Para ello lanzaremos iodine en el cliente del siguiente modo:

iodine  -P <PASSWORD> <IP DNS FORWARDER> tunel.bitsdelocos.es -F /var/run/iodine.pid

Donde es la ip del forwarder que use la red a la que estamos conectados o bien un servidor externo como el NS de google (8.8.8.8). Si no ha habido errores se podrá levantar un proxy SOCKS5 con el comando SSH:

ssh -fN -D *:8080 root@172.16.0.1

La IP 172.168.0.1 es la ip que se le habrá asignado a la interfaz dnsX en el servidor.

Para comprobar que todo ha ido bien se debe instalar el plugin switchy omega en el navegador chrome y configurarlo:

La IP que aparece en la captura es la ip de la máquina virtual donde se está ejecutando el cliente de iodine.

Para comprobar si ha ido bien la configruación del proxy, debemos abrir una web y con F12 inspeccionar la ip remota de la página abierta, si corresponde con la ip de nuestro proxy significa que habrá funcionado.

Se ha configurado Switchy omega con Chrome.

Otro modo de comprobar si funciona es usando CURL en un terminal linux

[root@localhost ~]# curl --socks5-hostname  127.0.0.1:8080 www.bitsdelocos.es -v
* About to connect() to proxy 127.0.0.1 port 8080 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.bitsdelocos.es
> Accept: */*
> 
< HTTP/1.1 302 Found
< Server: openresty
< Date: Sun, 21 Oct 2018 15:52:40 GMT
< Content-Type: text/html; charset=iso-8859-1
< Content-Length: 211
< Connection: keep-alive
< Location: https://www.bitsdelocos.es/

Este método de túneling es mucho menos efectivo que el túnneling por ssh ya que el overhead introducido es mucho mayor.

Shaping con Iptables: Limitando CPS

Buenas noches, después de mucho tiempo sin pasarme por aquí, esta noche os traigo una pequeña entrada para ver como se puede configurar un rate limiting (shaping) en función de las conexiones por segundo en lugar del por ancho de banda (bandwidth).

Durante el transcurso de esta semana, me han consultado si se podría limitar el consumo de una API REST de un proveedor externo a priori no debería ser mucho problema, cuando te piden esto lo primero que piensas es en limitar el ancho de banda consumido en un packetshaper/firewall aplicando políticas de QoS. Pero esta vez, se solicitó que se limitara por transacciones por segundo permitidas. Tras revisarlo con los compañeros nunca habíamos montado nada así por lo que me he dispuesto a investigar un poco más y he llegado la solución que os contaré en este post.

En la siguiente imagen se describe la arquitectura inicial, en el recuadro rojo se muestra que existen N instancias de una aplicación que competirán por 10 conexiones por segundo contra la API externa (verde).


Sigue leyendo

Integración OSSIM – Elasticsearch

Qué es ossim?

El software de seguridad OSSIM, del inglés Open Source Security Information Management, es un conjunto de herramientas de seguridad (recogida de logs, monitorización, escaneo de vulnerabilidades,…) orquestadas para conseguir una solución de seguridad capaz de correlacionar y detectar eventos de seguridad y vulnerabilidades en una infraestructura determinada.

Tras haber gestionado ossim, me he dado cuenta que la integración de OSSIM con el mundo exterior es algo complicada.. expresiones regulares, creación de nuevos plugins, tener que pasar siempre por syslog,… Para evitar estos problemas se ha desarrollado un nuevo datasource de ossim para permitir la integración de OSSIM con elasticsearch.

El código se encuentra en mi repositorio público:

https://github.com/berni69/ossim-agent-elasticsearch

El código que se debe añadir a ossim es:

ParserElastic.py
ElasticDetector.py

Además se debe modificar el componente Agent.py (línea 559 aprox) para añadir un nuevo tipo de datasource.

                elif plugin.get("config", "source") == "elasticsearch":
                    parser = ParserElastic(self.conf, plugin, None)
                    parser.start()
                    self.detector_objs.append(parser)

Para que esto funcione se debe añadir la librería de elasticsearch para python:

pip install elasticsearch

Ejemplo de configuración:

https://raw.githubusercontent.com/berni69/ossim-plugins-elasticsearch/master/elasticsearch-example.cfg

Mantén tus dispositivos actualizados con Ansible

Si te gusta cacharrear como a mi, al final terminas teniendo varios dispositivos conectados a la red de tu casa y otros tantos distribuidos en el cloud, una de las tareas más tediosas a las que te puedes enfrentar es irlos actualizado a medida que pasa el tiempo. No a todos estos dispositivos me conecto habitualmente por lo que no siempre recuerdo actualizarlos, para solucionar esto he decidido que voy a usar Ansible. Esta pieza de software se define como:

Ansible es categorizado como una herramienta de orquestación. Maneja nodos a través de SSH y no requiere ningún software remoto adicional (excepto Python 2.4 o posterior para instalarlo). Wikipedia

Para poder instalar Ansible es necesario disponer de Pip y Python en nuestro sistema. Yo lo decidí instalar en mi Raspberry Pi por lo que además tuve que instalar software adicional:

apt-get update
apt-get upgrade python
apt-get install libssl-dev libffi5-dev python-dev build-essential
cd /tmp/
wget wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
pip install ansible

Dependiendo de la velocidad de la tarjeta SD de tu Raspberry Pi y la versión de ésta, puede tardar casi una hora en instalar todo el software necesario.

Una vez instalado el software, debemos crear el inventario de máquinas en /etc/ansible/hosts

mkdir /etc/ansible/
touch /etc/ansible/hosts

En mi caso voy a crear un grupo de servidores llamado servers que contiene un servidor vps y 2 raspberrys:

[servers]
mivps.example.com   ansible_connection=ssh  ansible_user=root
rpi1                ansible_connection=local #Host donde ejecuto ansible
rpi2                ansible_connection=ssh  ansible_user=pi    ansible_host=192.168.1.13

Donde la primera columna es el nombre del dispositivo al que nos vamos a conectar, ansible_host es la ip en el caso de que el nombre no se pueda resolver por dns y ansible_user es el usuario que usará ansible para conectarse al dispositivo.

Habitualmente, si no se especifica lo contrario, ansible intentará usar la clave ssh del usuario local para conectarse a los servidores remotos, si el usuario no tiene ninguna clave ssh generada, la crearemos.

mkdir $HOME/.ssh
chmod 600 $HOME/.ssh
ssh-keygen -t ecdsa -C "miusuario@miequipo"

Este proceso debe generar 2 claves (pública y privada) llamadas ~/.ssh/id_ecdsa.pub y ~/.ssh/id_ecdsa. Debemos copiar la clave pública (.pub) en el archivo authorized_keys del servidor remoto, para ello ejecutaremos el comando:

ssh-copy-id -i ~/.ssh/id_ecdsa root@mivps.example.com

Si queremos probar que se han copiado las claves ssh correctamente y tenemos acceso podemos ejecutar el comando

root@rpi1:~# ansible servers -m ping
mivps.example.com | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
rpi1 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
rpi2 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

Si todos los hosts aparecen como success, es que la instalación de claves ha ido correctamente.

Una vez copiadas todas las claves en los servidores, debemos crear el archivo /etc/ansible/update.yml:

---

- hosts: servers
  become: true
  become_user: root
  become_method: sudo
  tasks:
    - name: Update packages list [APT]
      apt: update_cache=yes
      when: ansible_os_family == 'Debian'
    - name: Upgrade packages [APT]
      apt: upgrade=safe
      when: ansible_os_family == 'Debian'
    - name: Upgrade packages [YUM]
      yum:
        name: '*'
        state: latest
        update_cache: yes
      when: ansible_os_family == 'RedHat'

Para finalizar, debemos lanzar el comando

root@rpi1:~# ansible-playbook /etc/ansible/update.yml

PLAY [servers] *********************************************************************************************************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************************************************************************************************
ok: [mivps.example.com]
ok: [rpi2]
ok: [rpi1]

TASK [Update packages list] ********************************************************************************************************************************************************************************
changed: [mivps.example.com]
changed: [rpi2]
changed: [rpi1]

TASK [Upgrade packages] ************************************************************************************************************************************************************************************
changed: [mivps.example.com]
changed: [rpi1]
changed: [rpi2]

PLAY RECAP *************************************************************************************************************************************************************************************************
mivps.example.com          : ok=3    changed=2    unreachable=0    failed=0   
rpi1                       : ok=3    changed=2    unreachable=0    failed=0   
rpi2                       : ok=3    changed=2    unreachable=0    failed=0   

Si todos los hosts aparecen como 0 failed y 0 unreachable es que la ejecución del script ha ido correctamente.

Actualizar DNS con DHCP

En la entrada anterior vimos como montar un servidor bind y un server dhcp en linux para bloquear la resolución de algunas webs en nuestra red de área local. (Suplantando nuestros dns en la red local). Ya que tenemos el laboratorio montado en casa, podemos mejorar sus funcionalidades haciendo que todos los dispositivos que reciban una dirección DHCP de nuestro servidor queden registrados en el DNS con una entrada dinámica. Hacerlo a mano sería bastante laborioso y en breves tendríamos la zona dns desactualizada.

Para ello me he creado una zona a la que llamaré “canostra.local”, esta zona engloba mi red local. Siguiendo con el ejemplo anterior, tendremos 3 dispositivos en la red:

	192.168.22.1  --> Gateway
	192.168.22.2  --> Equipo Windows con reserva de DHCP
	192.168.22.11 --> DNS + DHCP.

Para poder crear el dynamic dns, el primer paso es editar el archivo para crear las nuevas zonas:

sudo vi /etc/bind/named.conf.local

Sigue leyendo

Let’s Encrypt la CA Open Source

Para todos aquellos que no conozcáis Let’s Encrypt os invito a que visitéis su Web . Esta entidad certificadora es Open Source y expide certificados gratuitamente siempre que podamos verificar la propiedad del sitio web mediante el protocolo ACME (automatic certificate management environment). Este protocolo nos permite administrar y expedir certificados de manera automática.

La única pega de esta entidad es que la validez de los certificados es de 90 días. Por lo que cada 3 meses hay que renovarlos en el servidor. Existen varios mecanismos de autenticación de un dominio, el más sencillo es la comprobación web donde la entidad certificadora nos solicita que creemos un .html con un contenido específico en nuestro dominio. Para automatizar el uso de ACME se creó un proyecto que se llama dehydrated en el que se gestionan en bash las llamadas a letsencrypt. Este proyecto es modular y permite parametrizar fácilmente las opciones de despliege de los certificados:

https://github.com/lukas2511/dehydrated

Este tipo de autenticación vía http presenta un problema, no puedes autenticar subdominios no publicados en Internet ya que la CA no podría conectarse a comprobar el challenge. Para este tipo de escenarios podemos utilizar la autenticación DNS01, donde se publica la información en un registro TXT del DNS que nos gestiona el dominio. Para usar este tipo de challenge, hay que especificar un “hook” a dehydrated para indicarle como tiene que interactuar con nuestro DNS.

En mi caso dispongo de una solución DNS de EfficientIP solid server, he creado un hook para usar dehydrated con SolidServer. Se puede encontrar en github:

https://github.com/berni69/solidserver-challenge

Para usarlo bastaría con descargarlo junto con dehydrated:

$ cd ~
$ git clone https://github.com/lukas2511/dehydrated
$ cd dehydrated
$ mkdir hooks
$ git clone https://github.com/berni69/solidserver-challenge.git hooks
$ chmod +x dehydrated
$ ./dehydrated --challenge dns-01  --cron --domain "test.example.com" --hook "hooks/solid-hook.py"

Saludos!