Baptiste Fontaine’s Blog  (back to the website)

Preventing Bash Pranks

The easiest and most popular Bash pranks involve someone messing up with your ~/.bashrc. For example, here is a real-life example:

#! /bin/bash
b=~/.bashrc
echo >>$b
echo "echo sleep 1 >>$b" >>$b

If you execute this script, it’ll add a newline in your ~/.bashrc just in case it doesn’t end with a newline, then add this line:

echo sleep 1 >>~/.bashrc

The effect of this isn’t immediately visible to the pranked user. When they’ll start a new Bash session, e.g. by opening a new terminal window, the code in ~/.bashrc will be executed, and the previous line will add sleep 1 at the end of it, which means it’ll be executed and the user will have to wait one more second before having their prompt. The next time they’ll open a session, it’ll add one more line and thus will wait 2 seconds, and so forth.

In this post, I’ll give you an overview of the existing solutions to prevent these pranks.

Note that I’m referring to ~/.bashrc as your startup Bash file because it’s commonly used, but some people directly use ~/.bash_profile instead, or another one. When you start a session, Bash reads /etc/profile, then tries ~/.bash_profile, ~/.bash_login, and ~/.profile, (in that order). In most environments the default ~/.bash_profile file sources ~/.bashrc.

User Rights

The first solution is to protect your ~/.bashrc by restraining the access. Nobody should be able to edit your file except you (and root). It should be the default, but if you messed up with user rights, here is how to reset the file to a safe state (read and write for you, and that’s all):

$ chmod 600 ~/.bashrc

Most attacks thus involve you executing a script, which allows them to bypass the rights because the script is executed by you with your editing rights.

One solution would be to remove your own writing right and adding it only when you need it:

# add this in your ~/.bashrc
secure-edit() { chmod u+w $*; ${EDITOR:-vi} $*; chmod u-w $*; }

Then remove your writing right:

$ chmod 400 ~/.bashrc

You can’t edit your file anymore, but you can use your new secure-edit command:

$ secure-edit ~/.bashrc

It temporarily allows you to modify the file, open your editor, then put the restricted rights back.

The “last line protection”

This one is easy to use but easy to circumvent. The goal is to prevent one-line insertions, such as:

echo "alias ls=cd" >> ~/.bashrc

and the solution is as simple as:

#

Yes, that’s just an hash symbol. If you ends your ~/.bashrc with it, the first inserted line will be commented out:

#alias ls=cd

It doesn’t work if the prankster adds multiple lines, or adds a newline before the prank.

return

You can exit from a Bash script with exit. Your ~/.bashrc is not executed like a script, it’s sourced. This means Bash doesn’t start a subshell for it and execute all its content in the current shell. This also means if you write exit it’ll exit your current shell.

The solution here is to use return at the end of your file:

return

Any line added after this one won’t be executed because Bash will stop the evaluation. Note that while it’s better than the previous solution, it can be nullified by a sed call (e.g. sed 's/return//').

The disguised return

This one is the same as the previous one, but prevents pranksters from removing it with calls to sed or similar search & replace techniques. It uses the fact than in Bash you can execute a command contained in a variable by using it at the proper place:

print_something=echo
$print_something hello

These lines are equivalent to echo hello. We use the same thing here with return. The idea is to execute an obfuscated version of return, e.g.:

b=tu
a=re
c=rn

$a$b$c

And voilà! It’s now nearly impossible to detect the return execution without manually editing the ~/.bashrc file.

This is still vulnerable to file replacement, e.g.:

rm ~/.bashrc
echo 'echo "sorry, no."' > ~/.bashrc

This wipes the existing ~/.bashrc file and replace it with another one.