SSH Chroot In FreeBSD?
In this hack, I'll show you how to limit access to a server through a SSH link. This is useful when we need to provide some users with FTP-like access to a server, just for upload or download files, but limiting their scope inside the server filesystem.
Everyone knows that FTP is an old and insecure protocol, but most lazy sysadmins out there just keep using it because a ftpd server is easy to set up and most users already know how to connect to that kind of server (using well-known FTP clients).
Here, we will use sftp instead of FTP to provide users with full access to our server. By default, a user accesing a server using sftp would have access to every part of the filesystem, with the only restriction the classic unix permissions provide. That is, users creating content somewhere in the filesystem are resposible for setting up the correct permissions, so no allowed users can get access to their files.
To minimize such problem, we will use individual chroots for users connecting to our server, and to set up those chroots, we will use rssh, a shell that will jail users connecting through sftp (or even using some commands over SSH) in a given directory.
In FreeBSD we can install rssh from the ports system:
[prunus] ~> cd /usr/ports/shells/rssh/ [prunus] /usr/ports/shells/rssh> sudo make install [ ... ] ===> Registering installation for rssh-2.3.2 ===> SECURITY REPORT: This port has installed the following binaries which execute with increased privileges. /usr/local/libexec/rssh_chroot_helper If there are vulnerabilities in these programs there may be a security risk to the system. FreeBSD makes no guarantee about the security of ports included in the Ports Collection. Please type 'make deinstall' to deinstall the port if this is a concern. For more information, and contact details about the security status of this software, see the following webpage: http://www.pizzashack.org/rssh/index.shtml [prunus] /usr/ports/shells/rssh>
The port itself already add /usr/local/bin/rssh to the /etc/shells file, so it became a valid shell. If we have installed from sources, we should add it manually by ourselves.
[prunus] /usr/ports/shells/rssh> cat /etc/shells | grep rssh /usr/local/bin/rssh [prunus] /usr/ports/shells/rssh>
Before getting into action, it is a good idea to take a look at rssh(1), the man page for rssh. There, we could read a little bit more about their funcionalities and how to use them.
So, following rssh(1), we have to replace the shell parameter for each user we want to chroot. So, we will have to open the passwd file using vipw, and then modify the required lines.
In this example we will change the shell for the user rsshexample from:
rsshexample:$1$wA8BSxd9$C.Vd0RE6YXSrAfJmN6bHH.:10005:10005::0:0:testing rssh in freebsd:/home/rsshexample:/bin/tcsh
rsshexample:$1$wA8BSxd9$C.Vd0RE6YXSrAfJmN6bHH.:10005:10005::0:0:testing rssh in freebsd:/home/rsshexample:/usr/local/bin/rssh
(we have change the user default shell from /bin/tcsh to /usr/local/bin/rssh).
Shell (sh csh tcsh rssh nologin) [sh]:
After setting up the correct shell for each user we want to chroot in its home directory, we would have to take a look over rssh.conf. In FreeBSD located under /usr/local/etc, in this file we can configure some aspects of rssh. As always, it is a good idea to take a look over rssh.conf(5) (the man page for the rssh config file).
Here, we will change some lines. first, we will uncomment those ones:
Just to allow users to use both scp and sftp. Then we will add a line like that to the bottom of the file:
Here we are telling rssh that each time the user rsshexample connects to our server, he will be able to use only the scp and sftp commands, and he will be chrooted inside /home/rsshexample. We also set the umask for the files and directories created by that user to 022, which results in files created with mode 744 and directories created with permissions 755.
We will have to add so many lines like that one as users we would like to chroot.
NOTE: Take care that we do not uncomment the chrootpath parameter. That parameter is used when all chroot users go inside the same chroot, which is not what we want in this case.
Now we have to create to chroot environment, where our users will be jailed as soon as they connect to the server. But before doing that, we should know that we have to posible setups there:
1- One single chroot_ for all users. In this case all users will be chrooted inside the same directory, and it is their task to manage permissions correctly, or other users could get access to their files. Using this setup, all users could move themselves around the chroot, having each one a home directory where they could save files, etc. With a single chroot, it is a good idea to set up a correct umask for users, so files created by them have correct permissions (like 750, for example).
2- One chroot per user. In this case each user has it's own private environment, where only such user will have access. This is a safer environment, but has the drawback of maintenance, because we will have to maintain so many chroot environments as chrooted users. That means that we will have to upgrade each chroot environment when upgrading the server userland.
For the purpose of this hack, we will set up one chroot per user. To create a valid chroot environment inside a user home directory, we will have to follow the following steps:
1- We have to create the needed directories inside the chroot, that is, directories where we will copy the needed binaries and libraries:[prunus] /home/rsshexample> sudo mkdir -p usr/bin usr/libexec usr/local/libexec usr/lib lib libexec bin dev etc [prunus] /home/rsshexample>
2- Then we have to copy over those directories the needed binaries:[prunus] /home/rsshexample> sudo cp /usr/bin/scp usr/bin/ [prunus] /home/rsshexample> sudo cp /usr/libexec/sftp-server usr/libexec/ [prunus] /home/rsshexample> sudo cp /usr/local/libexec/rssh_chroot_helper usr/local/libexec/ [prunus] /home/rsshexample>
3- Then we have to copy the libraries those binaries are linked against too:[prunus] /home/rsshexample> ldd /usr/bin/scp /usr/bin/scp: libssh.so.3 => /usr/lib/libssh.so.3 (0x2807e000) libcrypt.so.3 => /lib/libcrypt.so.3 (0x280b3000) libcrypto.so.4 => /lib/libcrypto.so.4 (0x280cb000) libz.so.3 => /lib/libz.so.3 (0x281be000) libc.so.6 => /lib/libc.so.6 (0x281cf000) libgssapi.so.8 => /usr/lib/libgssapi.so.8 (0x282b6000) libkrb5.so.8 => /usr/lib/libkrb5.so.8 (0x282c4000) libasn1.so.8 => /usr/lib/libasn1.so.8 (0x282f8000) libcom_err.so.3 => /usr/lib/libcom_err.so.3 (0x28319000) libroken.so.8 => /usr/lib/libroken.so.8 (0x2831b000) libmd.so.3 => /lib/libmd.so.3 (0x28327000) [prunus] /home/rsshexample> [prunus] /home/rsshexample> sudo cp /usr/lib/libssh.so.3 /usr/lib/libgssapi.so.8 /usr/lib/libkrb5.so.8 /usr/lib/libasn1.so.8 /usr/lib/libcom_err.so.3 /usr/lib/libroken.so.8 usr/lib/ [prunus] /home/rsshexample> sudo cp /lib/libcrypt.so.3 /lib/libcrypto.so.4 /lib/libz.so.3 /lib/libc.so.6 /lib/libmd.so.3 lib/ [prunus] /home/rsshexample>
We should check that sftp-server is linked against the same libraries as scp, if not, we will have to copy over the needed libraries from sftp-server too. rssh_chroot_helper should be statically linked, so no big deal, but you should take a look before proceeding.
4- Then we have to copy the ld loader:[prunus] /home/rsshexample> sudo cp /libexec/ld-elf.so.1 libexec/ [prunus] /home/rsshexample>
5- Now we have to copy over a default shell (sh) and the libs it is linked against:[prunus] /home/rsshexample> sudo cp /bin/sh bin/ [prunus] /home/rsshexample> ldd /bin/sh /bin/sh: libedit.so.5 => /lib/libedit.so.5 (0x28092000) libncurses.so.6 => /lib/libncurses.so.6 (0x280a6000) libc.so.6 => /lib/libc.so.6 (0x280e7000) [prunus] /home/rsshexample> sudo cp /lib/libncurses.so.6 /lib/libedit.so.5 lib/ [prunus] /home/rsshexample>
NOTE: if you experience problems when connecting to a chroot account, getting a message about something wrong with wordwrap(), try copying over the /bin/tcsh and /bin/csh shells too (and the libs their are linked against too, obviously)
6- Almost finished, we have now to create a devfs filesystem inside the /dev directory in the chroot environment. This is just a matter of adding a line to rc.conf, then set the mount point in /etc/fstab and finally mount the filesystem manually to check it is ok:[prunus] /home/rsshexample> cat /etc/rc.conf|grep dev devfs_set_rulesets="/mnt/data/pexego/ayselucus.es/ftp/dev=devfsrules_jail" [prunus] /home/rsshexample> cat /etc/fstab | grep devfs none /home/rsshexample/dev devfs rw 0 0 [prunus] /home/rsshexample> sudo mount_devfs devfs /home/rsshexample/dev [prunus] /home/rsshexample> mount |grep devfs devfs on /dev (devfs, local) devfs on /var/named/dev (devfs, local) devfs on /home/rsshexample/dev (devfs, local) [prunus] /home/rsshexample>
7- Finally, we have to copy both /etc/passwd and /etc/master.passwd to the chroot. It is a good idea to edit them and remove all existing accounts except the one(s) for the user(s) that will have access to the chroot. After edited the files, we have to use the pwd_mkdb tool to generate the password database inside the chroot:[prunus] /home/rsshexample> sudo cp /etc/passwd /etc/master.passwd etc/ [ ... ] [prunus] /home/rsshexample> pwd_mkdb -d /home/rsshexample/etc /home/rsshexample/etc/master.passwd [prunus] /home/rsshexample>
NOTE: If we do not use pwd_mkdb, we will get a Unknown user message when trying to log in as the chrooted user.
Finally, we could use any sftp client to connect to our server and check the chroot:
[Fenris] ~> sftp rsshexample@Prunus Connecting to Prunus... Password: sftp> pwd Remote working directory: / sftp> ls -l drwxr-xr-x 2 0 10006 512 Dec 11 10:01 bin dr-xr-xr-x 4 0 0 512 Dec 11 10:29 dev drwxr-xr-x 2 0 10006 512 Dec 11 10:35 etc drwxr-xr-x 2 0 10006 512 Dec 11 10:32 lib drwxr-xr-x 2 0 10006 512 Dec 11 09:24 libexec drwxr-xr-x 6 0 10006 512 Dec 11 09:22 usr sftp> cd .. sftp> pwd Remote working directory: / sftp> ls -l drwxr-xr-x 2 0 10006 512 Dec 11 10:01 bin dr-xr-xr-x 4 0 0 512 Dec 11 10:29 dev drwxr-xr-x 2 0 10006 512 Dec 11 10:35 etc drwxr-xr-x 2 0 10006 512 Dec 11 10:32 lib drwxr-xr-x 2 0 10006 512 Dec 11 09:24 libexec drwxr-xr-x 6 0 10006 512 Dec 11 09:22 usr sftp>
Nice!, our user will be jailed inside his chroot!