Esta pagina se ve mejor con JavaScript habilitado

Jails bajo FreeBSD

 ·  🎃 kr0m

Los sistemas tipo BSD disponen de chroot desde la época de 4.2BSD. chroot permite restringir el directorio raíz de un conjunto de procesos creando un entorno seguro y separado del resto del sistema, es una buena herramienta para tareas sencillas que no requieran mucha flexibilidad, características complejas o muy avanzadas. Por desgracia, desde su invención se han ido encontrando formas de saltarse las barreras que impone, es evidente que chroot no es la solución ideal para ejecutar servicios con seguridad. Este es uno de los principales motivos por los que se crearon las jaulas.

Jails es una herramienta muy potente pero no es la panacea en cuanto a seguridad, existen varias maneras de conseguir root en el jail si cooperan un usuario no privilegiado en el servidor de virtualización y un usuario root en el jail.  La mayoría de estos ataques pueden ser mitigados asegurándose de que el root filesystem del jail no sea accesible por usuarios no privilegiados dentro del servidor de virtualización.

Un jail se puede montar de dos modos distintos:

  • Virtual system: Sistema operativo completo.
  • Service: Se arranca un proceso dentro del chroot. Si el jail es un servicio el parámetro exec.start debe ser modificado.

El jail se puede montar tanto desde paquetes binarios como desde las fuentes, en este manual optaremos por los paquetes binarios en favor de una mayor celeridad.

Definimos donde vamos a montar nuestro jail:

mkdir -p /var/jail/www
export DESTDIR=/var/jail/www

Ahora tenemos dos posibilidades, extraer solo el sistema base:

O extraer el sistema completo, base y ports:

Indicamos que queremos arrancar las jails en el boot:

sysrc jail_enable="yes"

Permitimos los raw sockets en los jails para que el ping funcione, no es algo imprescindible pero al principio para debugear nos vendrá bien:

sysctl security.jail.allow_raw_sockets=1
echo ‘security.jail.allow_raw_sockets=1’ » /etc/sysctl.conf


La red puede funcionar de distintos modos:

  • Una única ip : Si solo tenemos una ip en el host podemos utilizarla tanto para el host como para el jail siempre y cuando los servicios entre los jails y el host no se solapen.
  • Varias ip con alias : Si tenemos varias ips podemos crear un alias en el host y asignar la ip secundaria al jail.
  • Utilizar una interfaz vnet : Otra opción es utilizar vnet, dotando al jail de su propia pila TCP/IP de este modo podemos natear o bridgear el jail. Además ya no tendremos que preocuparnos por los bindeos que haga el padre.

Una única ip

Configuramos el jail:

vi /etc/jail.conf

www {
    host.hostname = www.alfaexploit.com;           # Hostname
    ip4 = "inherit";                               # IP config
    allow.raw_sockets = 1;                           # Needed for ping
    path ="/var/jail/www";                         # Path to the jail
    mount.devfs;                                   # Mount devfs inside the jail
    exec.start = "/bin/sh /etc/rc";                # Start command
    exec.stop = "/bin/sh /etc/rc.shutdown";        # Stop command
}

Podemos arrancar nuestro jail con:

service jail start www

Listamos los jails:

jls

   JID  IP Address      Hostname                      Path
     1                  www.alfaexploit.com           /var/jail/www

Entramos en el jail:

jexec 1 tcsh

Habilitamos el servicio ssh en el arranque:

sysrc sshd_enable="yes"

Generamos las keys ssh:

ssh-keygen -A

Reconfiguramos el puerto ssh ya que en esta configuración de red no se pueden solapar servicios con el host padre:

vi /etc/ssh/sshd_config

port 23

Reiniciamos el servicio:

service sshd restart

Accedemos por ssh al jail:

kr0m@www:~ %

Varias ip con alias:

vi /etc/rc.conf
ifconfig_em0="inet 192.168.69.23 netmask 255.255.255.0"
defaultrouter="192.168.69.1"
ifconfig_em0_alias0="inet 192.168.69.24 netmask 255.255.255.0"

Reiniciamos los servicios netif y routing para aplicar los cambios:

service netif restart
service routing restart

Hay que tener en cuenta que si un servicio se bindea a 0.0.0.0 en el host padre tendrá preferencia sobre el jail, por este motivo bindeamos el ssh del host a la ip 192.168.69.23, así el jail podrá hacerlo en la ip 192.168.69.24:

vi /etc/ssh/sshd_config
ListenAddress 192.168.69.23

Reiniciamos el servicio:

service sshd restart

Configuramos el jail:

vi /etc/jail.conf

www {
    host.hostname = www.alfaexploit.com;           # Hostname
    ip4.addr = "192.168.69.24";                       # IP config
    allow.raw_sockets = 1;                           # Needed for ping
    path ="/var/jail/www";                         # Path to the jail
    mount.devfs;                                   # Mount devfs inside the jail
    exec.start = "/bin/sh /etc/rc";                # Start command
    exec.stop = "/bin/sh /etc/rc.shutdown";        # Stop command
}

Reiniciamos el jail para aplicar la configuración nueva:

service jail stop www
service jail start www

Accedemos al jail vía ssh:

kr0m@www:~ %

Utilizar una interfaz vnet:

NOTA: Hay que tener en cuenta que si se está configurando en una máquina virtual de VirtualBox habrá que configurar la VM con “Modo promiscuo: permitir todo” en caso contrario el tráfico será capaz de salir de la máquina virtual pero las respuestas de dicho tráfico serán bloqueadas porque la MAC del bridge no coincide con la MAC asignada a la tarjeta de red virtual de VirtualBox.

Creamos un bridge:

vi /etc/rc.conf

cloned_interfaces="bridge0"
ifconfig_em0="up"
ifconfig_bridge0="inet 192.168.69.23 netmask 255.255.255.0 addm em0 up"
defaultrouter="192.168.69.1"

Aplicamos la configuración:

service netif restart
service routing restart

Las interfaces vnet en jails funcionan a modo de túnel, es decir una interfaz epair0a equivale a epair0b en el otro extremo, así que cuando el jail arranque crearemos epair0a y la meteremos en el bridge por otro lado el jail utilizará epair0b como interfaz de red:

vi /etc/jail.conf

www {
    host.hostname = www.alfaexploit.com;           # Hostname
    vnet = "new";                                      # IP config
    vnet.interface = "epair0b";
    allow.raw_sockets = 1;                           # Needed for ping
    path ="/var/jail/www";                         # Path to the jail
    mount.devfs;                                   # Mount devfs inside the jail
    exec.prestart += "ifconfig epair0 create up";
    exec.prestart += "ifconfig bridge0 addm epair0a";
    exec.poststop  = "ifconfig bridge0 deletem epair0a";
    exec.poststop += "ifconfig epair0a destroy";
    exec.start = "/bin/sh /etc/rc";                # Start command
    exec.stop = "/bin/sh /etc/rc.shutdown";        # Stop command
}

Reiniciamos el jail:

service jail stop www
service jail start www

Entramos en el jail y configuramos la interfaz del extremo de la interfaz vnet:

jexec 1 tcsh
vi /etc/rc.conf

ifconfig_epair0b="inet 192.168.69.24 netmask 255.255.255.0"
defaultrouter="192.168.69.1"

Salimos y reiniciamos el jail de nuevo:

Ctrl+d
service jail stop www
service jail start www

Comprobamos que ya tiene red:

jexec 1 tcsh
root@www:/ # ping 8.8.8.8

PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: icmp_seq=0 ttl=118 time=12.068 ms
^C
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss

Accedemos vía ssh:

kr0m@www:~ %

Los jails nos permiten ejecutar comandos adhoc:

jexec JID COMANDO

Una buena referencia en cuanto a documentación es el man del fichero de configuración de los jails:

man jail.conf

NOTA: Puede que encontremos mucha documentación mencionando como configurar los jails editando el fichero /etc/rc.conf, se trata de documentación obsoleta. The jail.conf file was added in FreeBSD 9.1

Por último puntualizar ciertas restricciones presentes en los jails:

  • No se pueden montar o desmontar sistemas de ficheros.
  • No se pueden cargar/descargar reglas de devfs, reglas de firewall(excepto en modo bridge) o cualquier otra operación que modifique datos en espacio de kernel.
Si te ha gustado el artículo puedes invitarme a un RedBull aquí