Rants of a madman » Users can delete,move and rename files owned by root eg. via an FTP Server. Read why and how to fix. (unlink_override v.1.0)
May
12

The Problem

When i first discovered this, my world shattered for a couple of hours. Ive been working with Unix & Linux for more than 15 years and my brain was firmly wired with the notion that “A file owned by root, cannot be touched by any other user” (unless, of course, the user is giving explicit permissions to do so via chmod 777 or the likes).

So when i discovered that a file, owned by root, with nothing but read permissions, had been deleted by an FTP user, i started hunting for exploits in the FTP daemon. In this case it was vsftpd.

I quickly saw in the source code of vsftpd, that all it did was leave the permission decision up to the filesystem/linux kernel. So i started googling. Apparently i wasn’t the only one with this issue and i found posts relating to ProFTPD as well. And the answer was almost always “thats just the way it is, get used to it” without the actual explanation.

So is this an FTP server issue? A lot of answers i found on the net would suggest yes. But actually this is not true. And actually its not even a bug.

Heres a test that may surprise a lot of people (it sure surprised me):

As root:

$ touch /home/user/testfile
$ chmod 000 /home/user/testfile
$ exit

(back as normal user)

$ rm /home/user/testfile
rm: remove write-protected regular empty file `testfile'? y
$ ls /home/user/testfile
ls: /home/user/testfile : No such file or directory

The file is successfully deleted. Whoa.. Brainfreeze!.

Let me explain in detail and then give you a “fix”.

It turns out that “write” permission on a file has nothing to do with deleting the file. If you have write permissions to the directory that contains the file, you can “unlink” it. You should think of directories as a “catalogue of references to files”. If i have write permissions to directory (ie. /home/user) then i get to decide what this catalogue “links” to. Hence what files are in the directory.

This is normal and default. So is it Linux specific? Nope. We tested this on Solaris and Windows as well. Same deal. It blows my mind, that something so basic in any O/S, has escaped me for so many years.

In my case, i sometimes drop .htaccess files in a users webroot if the site has security problems that are being misused. Ie. insecure PHP include misused for Remote File Inclusion. Instead of downing the users site entirely, i can disable the “URL include” option in an .htaccess file for the user, temporarily mitigating the problem, while the user gets time to fix his code without downtime on his site. The problem is, that the user will sometimes just overwrite the .htaccess file with his own via FTP, so i chown it to root to prevent him from doing so by accident.

This worked great so far, until a user showed up using an FTP-client that issued a DELE command before UPLOAD. And presto, the site got re-hacked and started sending out spam.

The Fix

I know talking about a “fix” for something thats not a bug, may seem wrong, but its nevertheless a problem in some cases, including my FTP example. My first thought was to patch the FTP server to not allow deletion of files not writable by the user. I quickly realized that this wasn’t very elegant and that the vsftpd developers probably never would include such a patch.

Then i remembered an old “friend”. LD_PRELOAD. The LD_PRELOAD function allows you to override any system-call from any process you like, unintrusive and uncomplicated.
What ive done is really simple, effective and a little cool :). Ive made a LD_PRELOAD that overrides the “unlink” and “unlinkat” system-calls that makes write access to the file as equally important as write access to the folder. This module is then “preloaded” in front of where ever you wish to “fix” this. In my case vsftpd.

Edit /etc/init.d/vsftpd and add, somewhere after the “set -e” line in the beginning of the file:

export LD_PRELOAD=/path/to/unlink_override.so

Issue /etc/init.d/vsftpd restart

Its that simple!. If it was proftpd (or anything else) you just do the same- export LD_PRELOAD before the daemon is started.

With my library, upon “unlink file” the following happens:

  • unlink OK if: “uid of current user == owner of the file”.
  • unlink OK if: current user has write access to the file.
  • else FAIL

And it works perfectly.

There are other paths to fixing this, such as Extended Filesystem Attributes or filesystem ACL’s, but they aren’t very elegant in this case and i simply want it to “just work as one expects”. And “one” being me, this is how i expected it to work ;).

Download

Download source from here:
unlink_override_1.0.tgz

And for convenience, heres a binary:
unlink_override.so

Id appreciate a comment if you use it.



  - Dan

Comments

  1. Neil Said,

    I’ve noticed this before and always assumed it was to do with the folder permissions vs the file permissions, I never just saw the potential for a web site or ftp exploit . Thanks for the heads up.

  2. Tony Said,

    Why not set the sticky bit on the dir?

  3. Dan Said,

    AFAIK, the sticky bit enforces that only the owner of a file may delete the file.
    Under a default apache setup, any file created via the website, (like uploads, installation of wordpress extensions, ect.) would be owned by the apache user, not the ftp user.
    With the sticky-bit set on directory, the ftp-user woud be unable to delete the files owned by the webserver, like a malicious uploaded file.

  4. Sheldon Said,

    I agree. It is VERY counter-intuitive and i think your preload hack is awesome. Ive been running it for a week now on ProFTPD and i works like a dream :D.

  5. Peter Said,

    Thank you.. That explains quite a lot :)

Add A Comment

REFRESH THIS PAGE TO POST COMMENTS!