chester's blog

technology, travel, comics, books, math, web, software and random thoughts

Building bash from source (Shellshock mitigation for Ubuntu 13.04 and other unsupported distros)

25 Sep 2014

Shellshock is a serious server security issue that was made public yesterday. The best fix is to apply security updates from your Linux distribution, as they become available.

If that is not possible for any reason (e.g., unsupported distros, like the Ubuntu 13.04 boxes we have not killed yet), you will need to compile bash from the source (including all the patches) - which may be confusing if you are not used to build C/C++ software “by hand”.

There are some scripts that compile and install a new bash (like’s curl | sh), but they assume you are ok with the latest bash version (4.3), and I needed to stay with 4.2. Here is how I did it:


  • You can copy and paste, but I recommend reading and applying commands one by one.
  • You need a user with sudo powers.
  • Replace “4.2” with the actual “major.minor” version of bash you are running (the steps will guide you into finding that).
  • In the end, this will not install the new bash, just build it. Read below for your installation options.
# Find which is your current bash version
bash --version

# Software versions are usulally named in "max.min.patch" format, and we just
# want to advance to the latest patch.
# Mine was "GNU bash, version 4.2.45(1)-release (x86_64-pc-linux-gnu)", so I
# want to get the latest patch for 4.2. Let’s first get the 4.2 source:
cd ~
mkdir bash
cd bash
tar -xvzf bash-4.2.tar.gz
cd bash-4.2

# You can see we have no patches applied, because the file below contains
# "#define PATCHLEVEL 0" (i.e., this is 4.2.0)
cat patchlevel.h

# Now let’s grab all the patches released for it:
cd ..
wget -r -l 1

# Ideally we’d check the signatures, but for now it’s good enough to just
# get rid of them and other non-patch files:

# Apply the patches onto the source code...
cd bash-4.2
for i in ~/bash/*; do patch -p0 < $i; done

# ...and now we should be on the latest PATCHLEVEL:
cat patchlevel.h

# Great, our code is ready to build. Go for it:
# (if it fails, the messages will help you. Most common issue is lack of yacc,
#  which you solve in Ubuntu/Debian with "sudo apt-get install bison")

# By this point, you have a bash file inside the bash-4.2 directory. Check
# if it is the version you expected (the "./" is important)...
./bash --version

# ...and that it is not vulnerable, i.e., does not print HTML when running
# this command (again, notice the "./"; you can remove it to compare the
# existing bash with the new one):
env -i  X='() { (a)=>\' ./bash -c 'echo curl -s'; head echo; rm -f echo

Now you need to replace your vulnerable bash with the new one. There are two ways of doing it:

  • Installing the new bash with sudo make install. If you only have a couple servers, I recommend that.
  • Manually replacing /bin/bash in affected servers with the new one. Only do it if the other servers use the same architecture/Linux version.

sudo cp /wherever/my/new/bash/is/bash /bin/bash should work, unless the server complains the file is already in use. In that case, try this:

  • Move the old bash somewhere else (sudo mv /bin/bash ~/old_bash).
  • Copy the new bash where the old one was (sudo cp /wherever/my/new/bash/is/bash /bin/bash).
  • Re-run bash --version (and the vulnerability test, if you want) to check the new bash is in place. You can also log in again and echo $BASH_VERSION.

You may have to chmod +x /bin/bash and/or chown root:root /bin/bash if your copy didn’t preserve permissions/ownership.



Thank you for this guide. I have one problem after exchanging the old bash with the new bash: whenever I open a screen session the /etc/profile won´t be parsed anymore. I can load it with source /etc/profile but it would be great if there is a way to make it work again. It´s an older Suse Linux, so I cannot use a rpm. I was looking at the configure options and couldn´t find any option that is controlling the behaviour where to look for the profile. Any help would be great. Thank you.



bash's behaviour regarding configuration files (/etc/profile, ~/.bash_profile ~/.bashrc) is sometimes hard to figure out - in no small part because it changes according to several things (whether it is a "login" shell, whether it's "interactive", the relationship between effective/acutal GID/UID, and even whether it was called as "bash" or "sh"!). If you get curious, you can check all those quirks here:

In your specific case, a likely explanation is that screen is calling it as a non-login shell (and hence, /etc/profile is not ran). It may have worked before either because of the permissions of the old bash, or something else that older versions didn't do and the latest does).

This page describes what seems to be an easy way to solve it: (in short: add "shell -$SHELL" to /etc/screenrc or ~/.screenrc). If that fails, you can try changing that line to include parameters mentioned in the first link to get bash to read /etc/profile.

As a last resource: assuming your /etc/profile is idempotent (i.e., it doesn't matter if you run it one or ten times), you could source from some of the files that get actually run. But I don't really recommend that (you may have overrides executed in the wrong order, for example).

Please let us know here if some of this solutions (and which one, if any) worked, so other people can benefit. Thanks!

Gaetano Sancilio

Gaetano Sancilio

Thanks a lot. It works great on a openSuse 11.3 distribution. I had to use "sudo make install" to mantain the shell local preferences. Thank you.