Security Risks of vsftpd’s chroot_local_user: Vulnerabilities and Secure Alternatives


1 views

While chroot_local_user=YES in vsftpd appears to restrict users to their home directories, it creates a fundamental security vulnerability due to Linux's filesystem permissions model. When chroot is applied, the user still retains ownership of their files, which can lead to privilege escalation paths.

# Example of dangerous permission structure:
drwxr-xr-x 3 ftpuser ftpgroup 4096 Jan 1 10:00 /home/ftpuser
-rw-r--r-- 1 ftpuser ftpgroup    0 Jan 1 10:00 /home/ftpuser/.bashrc

Your intuition about SSH is correct - disabling shell access via /etc/passwd helps but doesn't fully solve the issue:

# In /etc/passwd:
ftpuser:x:1001:1001::/home/ftpuser:/usr/sbin/nologin

However, the chroot vulnerability still exists because:

  • FTP users could potentially upload malicious scripts
  • World-readable system files might be accessible through symlink attacks
  • Configuration errors in vsftpd could lead to escapes

For production systems, consider these robust alternatives:

1. Using Virtual Users with Proper Jail

Create virtual users with PAM and enforce proper chroot through vsftpd's jail mechanism:

# /etc/vsftpd.conf
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES
allow_writeable_chroot=YES
user_sub_token=$USER
local_root=/var/ftp/$USER

2. Implementing Filesystem Namespaces

For modern Linux systems, using mount namespaces provides better isolation:

# Create dedicated mount namespace
unshare --mount --user --map-root-user --fork --pid
mount --bind /home/ftpuser /home/ftpuser
mount -o remount,rw,nosuid,nodev,bind /home/ftpuser

3. Container-based Solution

For maximum security, run vsftpd in a container with properly configured volumes:

# Docker example
docker run -d \
  --name secured-ftp \
  -p 21:21 \
  -v /path/to/ftp_data:/home/ftpuser \
  -e FTP_USER=ftpuser \
  -e FTP_PASS=password \
  --cap-drop=ALL \
  fauria/vsftpd

Even with chroot, implement these permission controls:

# Secure directory structure:
chown root:root /home/ftpuser
chmod 755 /home/ftpuser
mkdir /home/ftpuser/files
chown ftpuser:ftpgroup /home/ftpuser/files
chmod 750 /home/ftpuser/files

This creates a root-owned parent directory with restricted access to the actual user content area.


While chroot_local_user=YES seems like a straightforward solution for restricting FTP users to their home directories, it introduces several security vulnerabilities:

# Example vulnerable vsftpd.conf configuration
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES

The primary security issues stem from:

  • Write permission requirements: vsftpd requires the chroot directory to be writable when using chroot_local_user
  • Potential privilege escalation: Users can create hard links to system files before chroot is applied
  • Incomplete isolation: The chroot jail can be broken through various techniques

Even if you disable SSH access for these users, the FTP-specific vulnerabilities remain:

# Disabling SSH in /etc/ssh/sshd_config
DenyUsers ftpuser1 ftpuser2
Match User ftpuser*
    ChrootDirectory %h
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

Consider these more robust approaches:

Option 1: Using chroot_list

# Secure vsftpd.conf configuration
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES

Option 2: Combined with SFTP

# /etc/ssh/sshd_config configuration
Subsystem sftp internal-sftp
Match Group sftpusers
    ChrootDirectory /home/%u
    ForceCommand internal-sftp
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no

Option 3: Proper Directory Structure

Create a secure directory hierarchy:

sudo mkdir -p /var/ftp/users/user1/{uploads,downloads}
sudo chown -R root:root /var/ftp/users/user1
sudo chmod -R 755 /var/ftp/users/user1
sudo mkdir /var/ftp/users/user1/uploads
sudo chown user1:user1 /var/ftp/users/user1/uploads

Here's a complete secure setup:

# vsftpd.conf
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list
allow_writeable_chroot=YES
user_sub_token=$USER
local_root=/var/ftp/users/$USER
pasv_min_port=40000
pasv_max_port=50000

Create the chroot list:

sudo touch /etc/vsftpd.chroot_list
sudo chmod 600 /etc/vsftpd.chroot_list

For production environments, consider:

  • Implementing TLS encryption
  • Setting up rate limiting
  • Using fail2ban for brute force protection
  • Regularly auditing file permissions

Remember that security is an ongoing process, not a one-time configuration. Always test your setup thoroughly before deploying to production.