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:
export DESTDIR=/var/jail/www
Now we have two possibilities, extract only the base system:
tar -xf base.txz -C $DESTDIR
Or extract the complete system, base and ports:
tar -xf base.txz -C $DESTDIR
fetch http://ftp.freebsd.org/pub/FreeBSD/snapshots/amd64/12.0-STABLE/ports.txz
tar -xf ports.txz -C $DESTDIR
We indicate that we want to start the jails at boot:
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:
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:
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:
We list the jails:
JID IP Address Hostname Path
1 www.alfaexploit.com /var/jail/www
We enter the jail:
We enable the ssh service at startup:
We generate the ssh keys:
We reconfigure the ssh port since in this network configuration, services cannot overlap with the parent host:
port 23
We restart the service:
We access the jail via ssh:
kr0m@www:~ %
Multiple IPs with aliases:
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 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:
ListenAddress 192.168.69.23
We restart the service:
We configure the jail:
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 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:
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 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:
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 start www
We enter the jail and configure the interface at the end of the vnet interface:
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:
service jail stop www
service jail start www
We check that it already has a network:
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:
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.