Anonymous FTP server

Anonymous FTP server

This article was written by Kim Scarborough <somebody@unknown.nu>. Reviewers include Nik Clayton,
Crist J. Clark, and Yonatan Bokovza.

Although much of the purpose of anonymous FTP has been rendered obsolete by HTTP, it still has one advantage: allowing
anonymous uploads. [Ed. note: see also upload files via http.]

Often, people want to give me files too large to send through e-mail, so I’d like them to be able to upload
them to my FreeBSD box without having to give them accounts. Anonymous FTP is the natural solution, but setting
it up to allow uploads yet still be reasonably secure takes care.

Warning: the method outlined below requires the use of SUIDDIR. This can be a security risk if used carelessly.
I believe that the setup below takes sufficient precautions that it won’t be a problem. But do be aware.

NOTE: FreeBSD’s ftpd now supports the -o option to
create a write-only FTP site. This makes the FTP daemon deny all
downloads, irrespective of the file permissions. To check if your ftpd
includes this option, see man ftpd
and look for that option. If it does, then we recommend that you use it
as a second layer of defense.

Step 1: Set up a new partition

The first danger to be considered when setting up anonymous FTP uploads is the possibility of people filling up
your drive. CERT advises that the upload
directory be on a dedicated drive; I think a dedicated partition will suffice just as well.
Either way, this will ensure that the important system partitions will not be filled.

Carve out a separate partition that will just be for uploads. The size is up to you, but I would recommend 750MB,
which will leave enough room in case somebody wants to upload an ISO. Don’t worry about mounting it yet; we’ll
do that in a minute. Actually creating a partition is beyond the scope of this article. It is recommended that
you read Chapter 12 of
The FreeBSD Handbook
for more information. Either that or you can use quotas
to limit the space used by the ftp daemon.

Step 2: Add the FTP user

Your FreeBSD system may already contain an entry in the password file for the ftp daemon.
Recent versions of FreeBSD include such an entry. If so, you can skip this step.

You’ll need to create a user that anonymous FTP uploads and downloads will execute as. If you chose to allow anonymous
FTP when you first installed FreeBSD, you’ll already have it; otherwise, you’ll need to create it. In either case, run
vipw and make sure the entry looks like this:

ftp:*:14:14:ftp:0:0:Mr. Anonymous FTP:/home/ftp:/nonexistent

NOTE: man hier indicates that the ftp home directory should be
/var/spool/ftp. This location can be acheived via symlinks which
would allow the physical directory to exist elsewhere. For example, if you set the home
directory via vipw to be /var/spool/ftp, you could put
the actual files in /ftp/home (or whatever locationyou choose).
Then you would create a symbolic link with this sequence of commands:


cd /var/spool
ln -s /path/to/real/files ftp

Let’s go over that vipw entry (also see the man page for passwd(5)).
First is the user name; to allow anonymous ftp you have to create a user named ftp.
is customary but it can be whatever you want. Make sure the
password is set to “*”, which ensures no password will work; Setting “*” as the password is a good idea
for all accounts that don’t need passwords. You should create a new group called
ftp too, and choose a unique UID and GID.
The home directory should be set to wherever you’re going to set up the anonymous
FTP file hierarchy; /home/ftp is generally a good choice. Finally, make sure the shell is set
to /nonexistent.
Never give an account a shell unless it needs it.

Step 3: Set up the directory structure

Now we set up the directories people will see when FTP’ing in. Create the directory you set as ftp’s‘s home directory; here
we’re using /home/ftp. Inside that directory, create the following directories:

  • etc
  • pub
  • incoming

Here are the commands to set up those directories in the ftp user’s home directory.

# cd ~ftp
# mkdir pub
# mkdir incoming
# mkdir etc

We will deal with directory permissions in Step 5

Step 4: Set up /etc/fstab and recompile the kernel

To keep people from being able to delete other people’s uploaded files, we’ll need SUIDDIR (explained in more detail below).
We have to do two things to mount a file system SUIDDIR.

First, let’s edit /etc/fstab. Put in this line:

/dev/ad2s2f   /home/ftp/incoming ufs  rw,SUIDDIR    2       2

Substitute the device of the partition you created in step 1. The SUIDDIR option must be specified at mount time for it
to work. See the man pages fstab(5) and mount(8) for more information.

Next, we need to enable SUIDDIR in the kernel. Add this option to your kernel configuration file:

options         SUIDDIR

Then configure, compile, install, and reboot to a new kernel.

Step 5: Setting permissions

When your system comes back up, do this:

chown -R root:wheel /home/ftp
cd /home/ftp
chmod 755 etc pub
chown nobody incoming
chmod 5777 incoming

[Ed. note: It was recomended by one reviewer that we not use nobody as the owner. I
have yet to establish if using ftp as the owner would be secure.

The directories should now look like this:

drwxr-xr-x   4 root    wheel  512 Nov 10 00:42 .
drwxr-xr-x  14 root    wheel  512 Oct 20 14:58 ..
drwxr-xr-x   2 root    wheel  512 Nov 10 00:44 etc
drwsrwxrwt   2 nobody  wheel  512 Nov 10 00:45 incoming
drwxr-xr-x   2 root    wheel  512 Nov 25 00:44 pub

You may have noticed there’s no /bin. Pre-4.x versions of FreeBSD required a
/bin/ls in the anonymous
chroot for directory listings to work. This is no longer needed, so don’t worry about it if you’re running 4.x.

Here’s why we did it that way. First, it’s a bad idea to make anything owned by ftp; that would mean that the anonymous
user would essentially own all those files/directories and might possibly be able to change things around. The man page
for ftpd(8) says that /pub should be owned by ftp, but I disagree
(and so does CERT).

/etc and /pub need to be readable by everybody and
writable only by root, for obvious reasons. The interesting case is
/incoming. We want everyone to be able to write to it, and we also want them to be able to list
the contents of the
directory (so they can ensure that their files uploaded). We don’t want them to be able to delete files that other
people have uploaded in there, however. To prevent this, we’ve done two things:

  1. We’ve made the directory SUIDDIR and owned by nobody. Normally, files uploaded to the incoming
    directory will be owned by ftp, regardless of the ownership of the directory. This means that anybody who comes along
    later can delete the files, since they are also the user ftp. Making the directory SUIDDIR will ensure that the files
    are owned by the directory owner, in this case nobody.

  2. We’ve set the “sticky bit”, which prevents users from deleting
    other users’ files in a directory, even if everyone has write permission
    to the directory. In this case, the sticky bit prevents user ftp from
    deleting the files which are now owned by user nobody. See also sticky(8).

We set the above items using chmod. Here’s how we determined the mode:

  • 4000 for SUIDDIR
  • 1000 for sticky bit
  • 777 to set the directory +rwx for everyone

Add those values up and you get 5777.
Read the man page for chmod(1) for more information.

Note that /incoming is not owned by root.
You never want to make a SUIDDIR owned by root because then anyone
can create root-owned files, which is a Bad Thing (actually, FreeBSD won’t let you do this anyway, but it’s bad practice
to depend on the OS to protect you from poor decisions).

Optional extras

We might want to put a couple of files in /etc. These are not mandatory; in fact,
the /etc directory itself is not
required. But it will make things look a little nicer if you add them.

  • ftpmotd is a banner that will be displayed after login. I have some ASCII art in mine from
    Joan Stark’s site. It looks nice in a browser.

  • You also might want to generate a pwd.db
    file from a password file. The only purpose of this is to make directory listings show usernames rather than UIDs.
    Similarly, you may want to create a group file to substitute group names for GIDs.

    Do not use the system
    /etc/passwd or /etc/group.

    Here’s the password file I created:

    default:*:0:0::::::
    ftp:*:65534:0::::::
    

    As you can see, the user names in our little password file don’t have to have anything to do with what user names
    really correspond with those UIDs. In my case, I made it so root-owned files will appear as being owned
    by default and files owned by nobody will show up with an owner of ftp (just to keep it
    confusing). To convert this input file into a pwd.db file, run this command:

    pwd_mkdb -d /home/ftp/etc passwd
    

    This will delete passwd and create master.passwd,
    pwd.db, and spwd.db in /home/ftp/etc.
    You can delete everything except pwd.db. Now, just create a group file:

    default:*:0:
    

    Again, name the group whatever you like.

Step 6: Edit /etc/login.conf

One extremely crucial thing I haven’t discussed before about anonymous FTP uploads: it is imperative that the
anonymous user not be allowed to download files from /incoming.
Otherwise, your site will be used as a warez
drop. And it will be found. Warez kiddies have scripts scanning thousands of IPs looking for FTP sites, and then
checking if they can upload and download anonymously when they find one. If your site allows this, it will be announced
on IRC when it is discovered and your bandwidth will skyrocket until you figure out what’s going on and fix it.

The permissions of a newly-created file are set by the user’s umask. The default umask for users under
FreeBSD is 022, which means that files will be created 644 and directories 755. We want the files that the anonymous FTP
user creates to be 640, so that once they’re uploaded, they can’t be downloaded (since the SUIDDIR changes the ownership).
So the umask for ftp needs to be 027.

This is why we gave the ftp user its own login class in step 2. We can now change the umask for just that user.
Add this line to /etc/login.conf:

ftp::umask=027:

Run the command:

cap_mkdb /etc/login.conf

to rebuild it, and we’re set. Now the uploaded files will be mode 640
(directories will be created mode 750, which makes them rather useless, but that’s a small downside to this setup). Since
they won’t belong to ftp, they can’t be read, but they will show up in directory listings. This will stop the
warez kiddies from using your site as a dropbox, since there’s no point in uploading giant files if they can’t subsequently
be downloaded. You will still get occasional files that their scripts
upload for testing, but these will be fairly small. Just keep an eye on it so you can clear these out.

Step 7: Restart ftpd

Now all we have to do is restart ftpd with logging enabled. The line in
/etc/inetd.conf should look like this:

ftp    stream  tcp     nowait  root    /usr/libexec/ftpd       ftpd -lS

WARNING: If your ftpd includes the -o option,
you should include the -o option above.

That’s the same as the default except for the “S” at the end, which will log anonymous transfers to
/var/log/ftpd.
You may also wish to include the A option to restrict FTP to only anonymous users if you don’t want
regular users using ftp (I force mine to use sftp instead).

Now send a HUP single to (inetd by issuing the command
(killall -HUP inetd), and you should be done.

Step 8: Test it to make sure it’s right!

Be sure to test it out from a remote site; upload a file and make sure
you can’t download or delete it. If you don’t verify everything is correct,
your server will most likely become the target of warez kiddies.


12 thoughts on “Anonymous FTP server”

  1. Thank you for your article. I used it to successfully set up an anonymous ftp server with disk quotas to limit the size of the incoming directory instead of creating a separate partition for it. I was a little confused on how to do this but with some help from -questions, I realized that I needed to mount the filesystem SUIDDIR and set the suiddir bit on the incoming directory. In my case, I set nobody as the owner of incoming and set quotas on the filesystem for nobody. All files available for downloading will be owned by ftp. Now when the ftp user uploads to incoming, suiddir will change ownership from ftp to nobody, enforcing my quotas. I just have to be sure that nobody does not own files that are outside of incoming or else those files will be counted toward nobody’s quota.

    I had a 4GB drive to dedicate to ftp, so I mounted the drive at /ftp. As the article suggests, I created /ftp/etc, /ftp/pub, and /ftp/incoming. Because I am using disk quotas, there is a /ftp/quota.user file. I would like to know if there is a way to completely hide this file.

    Thanks,

    Drew

    1. Marcus Nedelman

      Hi Drew,

      I agree, the article was very helpful.
      One piece is not working for me, though. Permissions for incoming were set as specified in the article:
      5777 and owner nobody. I made the entry in login.conf for ftp and mounted incoming SUIDDIR. Files are uploaded but the permissions on the uploaded files are to ftp and not nobody. Consequently, any ftp user can download and delete the uploaded files.
      I wonder what I am doing wrong.

      marcus

  2. i have a ftp server running on BSD unix.I want to change the umask setting for a particular user so that whenever he uploads
    files using ftp all files are created using that user.
    How can i achieve this

      1. I find it ever helpfull to evoke ftpd with the verbose logging options. To do this, edit inetd to run ftpd with the "-ll" flags [1st ‘l’ for logging, 2nd ‘l’ for verbose logging]. This way, you can watch for anonymous user names, new uploads and current downloads by tailing your http://ftp.log file.

        man pages: ftpd, tail, inetd

    1. dear sir,
      sir i ahve to install the ftpserver .i am having sun solaris
      system.i want to make out the setting of the derver for the anonymous user

      waiting for ur reply

      girja nandan

  3. Hello!

    First, thanks for the article. It was indeed very helpful and I got my anonymous ftp server up without any problems.

    I made only one change to the settings suggested in the article. I want a few remote users to be able to download files from /incoming. Because of possible security problems I decided that I don’t want them to do it with ftp but use scp instead.

    So, instead of chowning /incoming to nobody.wheel I created a ‘ftpadm’ group and chowned /incoming to nobody.ftpadm. Then I just put the users that I want to let to download the files into ftpadm group.

    I’m running the server in ‘anonymous-only’ mode so these users cannot access the ftp server with their usernames/passwords but *must* use scp.

    I wonder if I have opened any security holes by deviating from the article in this way?

  4. I am tring to setup anon ftp on my bsd box and followed the directions
    layed out on this web page
    http://www.freebsddiary.org/ftp-anonymous.php but to no avial. The anon
    user should be able to browse the dirctories and upload files to
    incoming but not be able to downlaod or erase files from the incoming
    directory. My problem is that the anon user can download files from the
    incoming directory and i have already had script kiddies up and down
    loading files can someone please help.

    Everthing seems to be working right when look at perms i get this

    v22.computerking.ca > /var/spool/ftp #l
    total 6
    drwxr-xr-x 2 root wheel 512 Sep 9 02:58 etc
    drwsrwxrwt 2 nobody wheel 512 Sep 15 19:52 incoming
    drwxr-xr-x 4 root wheel 512 Sep 9 03:16 pub
    [Wed Sep 15] 07:56 PM [0]

    Inside the incoming dir when i upload a file using an ftp client i get this which should not allow me to upload files useing the same client right?? What is wrong??

    v22.computerking.ca > /var/spool/ftp/incoming #l
    total 38
    -rw-r–r– 1 nobody wheel 37849 Sep 15 19:52 uncle.zip
    [Wed Sep 15] 07:59 PM [0]

Leave a Comment

Scroll to Top