Wednesday, April 30, 2008

Restrict Users to SCP and SFTP and Block SSH Shell Access with rssh

FTP is insecure protocol but often needed. OpenSSH Server can transfer file using SCP and SFTP (secure ftp) but it also grants ssh shell access, which is not desirable. Here is how sftp works:
SCP/SFTP -> sshd -> Call sftpd subsystem -> Requires a shell -> User login

rssh is a restricted shell for providing limited access to a host via ssh, it allows following operations only:

  • scp - Secure file copy
  • sftp - Secure FTP
  • cvs - Easily retrieve old versions to see exactly which change caused the bug
  • rsync - Backup and sync file system
  • rdist - Backup / RDist program maintains identical copies of files on multiple hosts.
  • Default configuration file is located at /etc/rssh.conf (FreeBSD - /usr/local/etc/rssh.conf)
  • Default rssh binary location /usr/bin/rssh (FreeBSD - /usr/local/bin/rssh)
  • Default port none - ( openssh 22 port used - rssh is shell with security features)
All you have to do is to set a user's shell to /usr/bin/rssh. For example:

Login as the root user, create a new user
# useradd -m -d /home/didi -s /usr/bin/rssh didi

Change user's shell:
# usermod -s /usr/bin/rssh didi # or
# chsh -s /usr/bin/rssh didivivek

Now try login via ssh or sftp using username didi:
$ sftp # or
$ ssh

This account is restricted by rssh.
This user is locked out.
Connection to closed.

By default rssh locks down everything including any sort of access. Now grant access to sftp and scp for all users by appending:
# vi /etc/rssh.conf

rssh reads configuration on fly (there is no rssh daemon). Now user can run scp and sftp, without shell access:
$ scp /path/to/file # or
$ sftp

Connecting to's password:
sftp> pwd
Remote working directory: /home/didi

Understanding command configuration options

  • allowscp : Tells the shell that scp is allowed.
  • allowsftp : Tells the shell that sftp is allowed.
  • allowcvs : Tells the shell that cvs is allowed.
  • allowrdist : Tells the shell that rdist is allowed.
  • allowrsync : Tells the shell that rsync is allowed.

Tip: Create a group for rssh users, and limit executable access to the binaries to users in that group to improve security. Use standard file permissions carefully and appropriately.

Chroot jail to lock users to their home only

rssh's chrootpath option is used to set the root of the chroot jail. A chroot affects only the current process and its children. If the default home directory is /home/didi, normal user can access files in /etc, /sbin or /bin. This allows an attacker to install sneaky things via your web server in /tmp.

=> Chroot directory: /users.
Tip: If possible mount /users filesystem with the noexec/nosuid option to improve security.

=> Required directories in jail:

  • /users/dev - Device file
  • /users/etc - Configuration file such as passwd
  • /users/lib - Shared libs
  • /users/usr - rssh and other binaries
  • /users/bin - Copy default shell such as /bin/csh or /bin/bash

=> Required files in jail at /users (default for RHEL / CentOS / Debian Linux):

  • /etc/
  • /etc/*
  • /etc/
  • /etc/nsswitch.conf
  • /etc/passwd
  • /etc/group
  • /etc/hosts
  • /etc/resolv.conf
  • /usr/bin/scp
  • /usr/bin/rssh
  • /usr/bin/sftp
  • /usr/libexec/openssh/sftp-server OR /usr/lib/openssh/sftp-server
  • /usr/libexec/rssh_chroot_helper OR /usr/lib/rssh/rssh_chroot_helper (suid must be set on this binary)
  • /bin/sh or /bin/bash (default shell)

Tip: Limit the binaries which live in the jail to the absolute minimum required to improve security. Usually /bin/bash and /bin/sh is not required but some system may give out error.

The files need to be placed in the jail directory mimic their placement in the root file system. So you need to copy all required files. For example, copy /usr/bin/rssh to /users/usr/bin/rssh.

Building the Chrooted Jail

# mkdir -p /users/{dev,etc,lib,usr,bin}
# mkdir -p /users/usr/bin
# mkdir -p /users/libexec/openssh

# mknod -m 666 /users/dev/null c 1 3

# cd /users/etc
# cp /etc/ .
# cp -avr /etc/ .
# cp /etc/ .
# cp /etc/nsswitch.conf .
# cp /etc/passwd .
# cp /etc/group .
# cp /etc/hosts .
# cp /etc/resolv.conf .

Open /usres/group and /users/passwd file and remove root and all other accounts.

# cd /users/usr/bin
# cp /usr/bin/scp .
# cp /usr/bin/rssh .
# cp /usr/bin/sftp .
# cd /users/usr/libexec/openssh/
# cp /usr/libexec/openssh/sftp-server . # Or

# cp /usr/lib/openssh/sftp-server .
# cd /users/usr/libexec/
# cp /usr/libexec/rssh_chroot_helper # Or

# cp /usr/lib/rssh/rssh_chroot_helper
# cd /users/bin/
# cp /bin/sh . # Or

# cp /bin/bash .

The library files that these binaries need can be found by using ldd / strace. For example:
ldd /usr/bin/sftp

Copy all these libraries to /users/lib and other appropriate location. Or use l2chroot script:
# cd /sbin
# wget -O l2chroot
# chmod +x l2chroot

Open l2chroot and set BASE variable to point to chroot directory (jail) location:

# l2chroot /usr/bin/scp
# l2chroot /usr/bin/rssh
# l2chroot /usr/bin/sftp
# l2chroot /usr/libexec/openssh/sftp-server # or

# l2chroot /usr/lib/openssh/sftp-server
# l2chroot /usr/libexec/rssh_chroot_helper # or

# l2chroot /usr/lib/rssh/rssh_chroot_helper
# l2chroot /bin/sh # or

# l2chroot /bin/bash # or

The syslog library function works by writing messages into a FIFO file such as /dev/log. You need to pass -a /path/to/chroot/dev/log option. This argument specify additional sockets to which syslogd has to listen. This is needed if some daemons will be running within a chroot() environment. Up to 19 additional sockets can be used. To have more, increase the symbol MAXFUNIX within the syslogd.c source file, find:
# vi /etc/sysconfig/syslog
Append -a /users/dev/log
SYSLOGD_OPTIONS="-m 0 -a /users/dev/log"

# /etc/init.d/syslog restart
(For Debian/Ubuntu, apply changes to /etc/default/syslogd)

Set chrootpath to /users
# vi /etc/rssh.conf
# /etc/init.d/sshd start

Add user to the jail:
# useradd -m -d /users/did -s /usr/bin/rssh didi

sftp> pwd
Remote working directory: /vivek
sftp> cd /tmp
Couldn't canonicalise: No such file or directory
Per User Configuration Options for chroot Jail

From the man page: The user configuration directive allows for the configuration of options on a per-user basis. THIS KEYWORD OVERRIDES ALL OTHER KEYWORDS FOR THE SPECIFIED USER. That is, if you use a user keyword for user foo, then foo will use only the settings in that user line, and not any of the settings set with the keywords above. The user keyword’s argument consists of a group of fields separated by a colon (:), as shown below. The fields are, in order:

  • username : The username of the user for whom the entry provides options
  • umask : The umask for this user, in octal, just as it would be specified to the shell access bits. Five binary digits, which indicate whether the user is allowed to use rsync, rdist, cvs, sftp, and scp, in that order. One means the command is allowed, zero means it is not.
  • path : The directory to which this user should be chrooted (this is not a command, it is a directory name).

rssh examples of configuring per-user options:

# vi /etc/rssh.conf
user=tom:077:00010 #
All user tom to bypass our chroot jail
user=jerry:011:00100 #
Provide jerry cvs access with no chroot
user=spike:011:10000 #
Provide spike rsync access with no chroot
user="tyke:011:00001:/users" #
Provide tyke access with chroot jail located at /users
user=nibbles:011:00001:"/usr/local/tv/shows/tom and jerry" #
Provide nibbles scp access with chroot directory, space must be quoted.

No comments: