This page looks best with JavaScript enabled

Jails under FreeBSD

 ·  🎃 kr0m

BSD-type systems have had chroot since the 4.2BSD era. chroot allows restricting the root directory of a set of processes by creating a secure and separate environment from the rest of the system. It is a good tool for simple tasks that do not require much flexibility, complex or advanced features. Unfortunately, since its invention, ways have been found to bypass the barriers it imposes. It is evident that chroot is not the ideal solution for running services securely. This is one of the main reasons why jails were created.

Jails are a very powerful tool but not a panacea in terms of security. There are several ways to get root in the jail if an unprivileged user on the virtualization server cooperates with a root user in the jail. Most of these attacks can be mitigated by ensuring that the jail’s root filesystem is not accessible by unprivileged users within the virtualization server.

A jail can be mounted in two different ways:

  • Virtual system: Complete operating system.
  • Service: A process is started within the chroot. If the jail is a service, the exec.start parameter must be modified.

The jail can be mounted from both binary packages and sources. In this manual, we will opt for binary packages for greater speed.

We define where we will mount our jail:

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

Now we have two possibilities, extract only the base system:

Or extract the complete system, base and ports:

We indicate that we want to start the jails at boot:

sysrc jail_enable="yes"

We allow raw sockets in the jails so that ping works, it is not essential but at the beginning it will be useful for debugging:

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


The network can work in different ways:

  • A single IP : If we only have one IP on the host we can use it for both the host and the jail as long as the services between the jails and the host do not overlap.
  • Multiple IPs with alias : If we have several IPs we can create an alias on the host and assign the secondary IP to the jail.
  • Use a vnet interface : Another option is to use vnet, giving the jail its own TCP/IP stack so we can NAT or bridge the jail. Also, we will no longer have to worry about the bindings made by the parent.

A single IP

We configure the 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
}

We can start our jail with:

service jail start www

We list the jails:

jls

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

We enter the jail:

jexec 1 tcsh

We enable the ssh service at startup:

sysrc sshd_enable="yes"

We generate the ssh keys:

ssh-keygen -A

We reconfigure the ssh port since in this network configuration, services cannot overlap with the parent host:

vi /etc/ssh/sshd_config

port 23

We restart the service:

service sshd restart

We access the jail via ssh:

kr0m@www:~ %

Multiple IPs with aliases:

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"

We restart the netif and routing services to apply the changes:

service netif restart
service routing restart

It should be noted that if a service is bound to 0.0.0.0 on the parent host, it will take precedence over the jail. For this reason, we bind the host’s ssh to the 192.168.69.23 IP, so the jail can bind to the 192.168.69.24 IP:

vi /etc/ssh/sshd_config
ListenAddress 192.168.69.23

We restart the service:

service sshd restart

We configure the 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
}

We restart the jail to apply the new configuration:

service jail stop www
service jail start www

We access the jail via ssh:

kr0m@www:~ %

Using a vnet interface:

NOTE: It should be noted that if it is being configured on a VirtualBox virtual machine, the VM must be configured with “Promiscuous mode: Allow All” otherwise the traffic will be able to leave the virtual machine but the responses to that traffic will be blocked because the MAC of the bridge does not match the MAC assigned to the VirtualBox virtual network card.

We create a 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"

We apply the configuration:

service netif restart
service routing restart

The vnet interfaces in jails work as a tunnel, that is, an epair0a interface is equivalent to epair0b on the other end, so when the jail starts, we will create epair0a and put it in the bridge. On the other hand, the jail will use epair0b as the network interface:

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
}

We restart the jail:

service jail stop www
service jail start www

We enter the jail and configure the interface at the end of the vnet interface:

jexec 1 tcsh
vi /etc/rc.conf

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

We exit and restart the jail again:

Ctrl+d
service jail stop www
service jail start www

We check that it already has a network:

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

We access via ssh:

kr0m@www:~ %

Jails allow us to run ad hoc commands:

jexec JID COMMAND

A good reference in terms of documentation is the man of the jail configuration file:

man jail.conf

NOTE: We may find a lot of documentation mentioning how to configure jails by editing the /etc/rc.conf file, but this is outdated documentation. The jail.conf file was added in FreeBSD 9.1

Finally, we specify certain restrictions present in jails:

  • File systems cannot be mounted or unmounted.
  • Devfs rules, firewall rules (except in bridge mode), or any other operation that modifies data in kernel space cannot be loaded/unloaded.
If you liked the article, you can treat me to a RedBull here