How do I recompile Bash to avoid Shellshock (the remote exploit CVE-2014-6271 and CVE-2014-7169)?

Solution 1:

Status

Apple has released Bash security fixes for Shellshock and related vulnerabilities as "OS X bash Update 1.0". They can be installed through normal system update for people using OS X Mountain Lion v10.8.5 or OS X Mavericks v10.9.5 (they are included in Security Update 2014-005) and can also be installed manually. Official Apple fixes are also available for OS X Lion v10.7.5 and OS X Lion Server v10.7.5 but those are only available via manual download. The security fixes are available via different URLs based on the operating system version:

  • http://support.apple.com/kb/DL1769 - Mavericks (10.9.5 and above)
  • http://support.apple.com/kb/DL1768 - Mountain Lion (10.8.5)
  • http://support.apple.com/kb/DL1767 - Lion & Lion Server (10.7.5)

(If new patches are released, put them here but please keep these existing ones as well for reference.)

The Apple patch takes care of Shellshock and several other vulnerabilities and is fine for most people. tl;dr people can stop reading here.

HOWEVER, the attention drawn to bash by the Shellshock bug has caused many researchers to take a hard look at bash and more and more (hard to exploit) vulnerabilities keep being found. If you are highly concerned about security (because maybe you are running OS X Server to host a publicly available web site) then you may want to (try to) keep up with the vulnerabilities and patches as they keep rolling in by compiling bash yourself. Otherwise, don't worry about it.

Look for Apple to release another update to bash some time in the future when the dust settles on finding further vulnerabilities.


An official set of patches of bash itself for bash 3.2, patches 52, 53, and 54 (which correspond to Bash 4.3 patches 25, 26, and 27) are available which fix both CVE-2014-6271 and CVE-2014-7169, as well as the 'Game over' displayed below. This has been tested by me (@alblue) and the post has been updated accordingly (and then additional updates were made: see revision 41 for the post that stops at patch 54).

Many additional vulnerabilities have been reported against bash. According to Michal Zalewski's post if you have patch 54 (and presumably Apple's official patch) "there's no point in obsessing about the status of these individual bugs, because they should no longer pose a security risk:"

  • CVE-2014-6271 - original RCE found by Stephane. Fixed by bash43-025 and corresponding Sep 24 entries for other versions.

  • CVE-2014-7169 - file creation / token consumption bug found by Tavis. Fixed by bash43-026 & co (Sep 26)

  • CVE-2014-7186 - a probably no-sec-risk 10+ here-doc crash found by Florian and Todd. Fixed by bash43-028 & co (Oct 1).

  • CVE-2014-7187 - a non-crashing, probably no-sec-risk off-by-one found by Florian. Fixed by bash43-028 & co (Oct 1).

  • CVE-2014-6277 - uninitialized memory issue, almost certainly RCE found by Michal Zalewski. No specific patch yet.

  • CVE-2014-6278 - command injection RCE found by Michal Zalewski. No specific patch yet.

It gets pretty confusing. Fortunately Chet Ramey, the official bash maintainer, posted a CVE to patch mapping. His post refers to patches for bash 4.3, I (@OldPro) have translated them to patches for bash 3.2, which is what is applicable to OS X. Also, since this post he has released patch 57, so I added that below:

 bash32-052      CVE-2014-6271                           2014-09-24
 bash32-053      CVE-2014-7169                           2014-09-26
 bash32-054      exported function namespace change      2014-09-27 ("Game Over")
 bash32-055      CVE-2014-7186/CVE-2014-7187             2014-10-01
 bash32-056      CVE-2014-6277                           2014-10-02
 bash32-057      CVE-2014-6278                           2014-10-05

See David A. Wheeler's post for a timeline and greater detail.

@alblue posted build instructions through patch 55. I (@OldPro) added patch 56 and 57 to the instructions but have not tested it.

Testing for the original Vulnerability

You can determine if you are vulnerable to the original problem in CVE-2014-6271 by executing this test:

$ env x='() { :;}; echo vulnerable' bash -c 'echo hello'
bash: warning: x: ignoring function definition attempt
bash: error importing function definition for `x'
hello

The above output is an example of a non-vulnerable bash version. If you see the word vulnerable in the output of that command your bash is vulnerable and you should update. Below is a vulnerable version from OS X 10.8.5:

Screenshot of bash terminal showing vulnerability in 10.8.5

Testing for the new Vulnerability

There has been an update to the original post and Bash 3.2.52(1) is still vulnerable to a variation of the vulnerability, defined in CVE-2014-7169

$ rm -f echo
$ env X='() { (a)=>\' sh -c "echo date"; cat echo
sh: X: line 1: syntax error near unexpected token `='
sh: X: line 1: `'
sh: error importing function definition for `X'
Thu 25 Sep 2014 08:50:18 BST

The above output is an example of a vulnerable bash version. If you see a date in the output of that command your bash is vulnerable.

Disabling auto-imported functions to prevent "Game Over"

Researchers noted, without classifying it as a vulnerability, that a script could hijack a function in a subshell using auto-imported functions:

$ env ls="() { echo 'Game Over'; }" bash -c ls
Game over

The above code on an affected system would display Game Over instead of the directory listing you would expect from ls. Obviously, echo 'Game Over' could be replaced by any nefarious code you want. This became know as the "Game Over" bug.

Prior to the availability of patch 54, both NetBSD and FreeBSD disabled auto-importing bash functions by default, partly to prevent "Game Over" but mainly to contain any further errors in the parser (such as CVE-2014-7169) as they were continuing to be discovered, and added a new command line flag --import-functions to re-enable the old default behavior. I (@alblue) have prepared a patch (against 3.2.53) for others to use if they want to adopt this behaviour as well and have included it below. By default this patch is not enabled in the build script below. I (@OldPro) believe this patch is no longer necessary or a good idea, because it breaks backwards compatibility and the vulnerabilities it protects against are very well addressed by patch 54 and earlier patches, and enabling this unofficial patch prevents future patches from being applied.

(Note to question editors; please do not enable this by default, as it is an unofficial patch.)

a0c5c4d66742fddd0a35001cb91798a5fbf8a2f5 import_functions.patch

The patch can be enabled by running export ADD_IMPORT_FUNCTIONS_PATCH=YES before running the build. Note that enabling this patch will disable patch 54 and any future patches because future patches cannot be guaranteed to be compatible with the unofficial patch.

Apple Patch has Game Over vulnerability, sort of

As pointed out by @ake_____ on twitter the official Apple patch is still vulnerable to environment clobbering of executables:

$ env '__BASH_FUNC<ls>()'="() { echo Game Over; }" bash -c ls
Game Over

Users should decide for themselves how important this is. I (@OldPro) think it is nothing to worry about because there is no known exploit for this behavior (it was not even given a CVE identifier) because in general unprivileged remote attackers cannot set the name of an environment variable and attackers with privileges cannot use this to gain privileges they do not already have (at least not without exploiting an additional vulnerabiltiy).

To provide a little background, bash allows you to define functions, and furthermore allows you to export those functions to subshells via the export -f command. This used to be implemented by creating an environment variable with the same name as the function with its value set to the function definition. So

$ ls () { echo 'Game Over'; }
$ export -f ls
$ echo $ls
Game Over

This happened because export -f ls created an environment variable named ls. The "Game Over" vulnerability was that you could directly create this environment variable without having to first define the function, which meant if you could inject the right variable name you could hijack a command. Apple tried to fix this by making it hard to create a variable with the right name. The official bash patch 54 actually makes it impossible to create a variable with the right name by using variable names that include % which is a character not allowed in a variable name, effectively putting exported function definitions in a different, reserved namespace.

If none of the above makes sense to you, don't worry about it. You are fine with the Apple patch for now.

System Binaries

OS X 10.9.5 (the latest stable release at the moment) ships with Bash v3.2.51:

$ bash --version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.

You can obtain and recompile Bash as follows, providing that you have Xcode installed (and have run xcodebuild at least once before to accept the license):

$ # If you want to disable auto-imported functions, uncomment the following
$ # export ADD_IMPORT_FUNCTIONS_PATCH=YES
$ mkdir bash-fix
$ cd bash-fix
$ curl https://opensource.apple.com/tarballs/bash/bash-92.tar.gz | tar zxf -
$ cd bash-92/bash-3.2
$ curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-052 | patch -p0    
$ curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-053 | patch -p0  
$ # See note above about ADD_IMPORT_FUNCTIONS_PATCH
$ [ "$ADD_IMPORT_FUNCTIONS_PATCH" == "YES" ] && curl http://alblue.bandlem.com/import_functions.patch | patch -p0
$ [ "$ADD_IMPORT_FUNCTIONS_PATCH" == "YES" ] || curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-054 | patch -p0
$ [ "$ADD_IMPORT_FUNCTIONS_PATCH" == "YES" ] || curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-055 | patch -p0
$ [ "$ADD_IMPORT_FUNCTIONS_PATCH" == "YES" ] || curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-056 | patch -p0
$ [ "$ADD_IMPORT_FUNCTIONS_PATCH" == "YES" ] || curl https://ftp.gnu.org/pub/gnu/bash/bash-3.2-patches/bash32-057 | patch -p0
$ cd ..
$ # Note: DO NOT ADD SUDO TO XCODEBUILD HERE
$ xcodebuild
$ build/Release/bash --version # GNU bash, version 3.2.57-release
$ build/Release/sh --version   # GNU bash, version 3.2.57-release
$ sudo cp /bin/bash /bin/bash.old
$ sudo cp /bin/sh /bin/sh.old
$ sudo cp build/Release/bash /bin
$ sudo cp build/Release/sh /bin

(Note: you can run this by copy-and-pasting the above code block, going into Terminal and then running pbpaste | cut -c 2- | sh. Always take care when running random scripts from the internet though ...)

After this, the Bash version should be v3.2.57:

$ bash --version
GNU bash, version 3.2.57-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.

For security, and after testing, I recommend that you chmod -x the old versions to ensure they aren't re-used, or move them to a backup site.

$ sudo chmod a-x /bin/bash.old /bin/sh.old

Other answers have solutions for those using MacPorts or Homebrew; these don't fix the problem, they just install additional versions of Bash. Please see those answers if you want to upgrade those specifically.

Thanks

Thanks to Chet, who looks after bash, and has been making these patches available. Thanks to everyone else who has commented on this and improved it over time.

Now Apple has released the real fix, though this might still be useful. Because they only released a fix for Lion and up, and the official patch provides GNU bash, version 3.2.53(1)-release (x86_64-apple-darwin13), however, the Game over bug is still somewhat vulnerable. At this point, rebuilding your own version of Bash against 3.2.57 is probably more secure than relying on Apple's patch, unless you do it wrong.

Solution 2:

Macports

This gets you a bash version 4.3.28(1) which patched both vulnerabilities (CVE-2014-6271 and CVE-2014-7169) as well as some subsequently discovered ones. This is useful if you have changed shells to use Macports bash to get the version 4 features.

It will not solve the issue of standard OS scripts as the have #!/bin/sh or #!/bin/bash as the first line. This sort of issue is why Macports tries not to use Apple's supplied versions of programs as Macports tends to be updated quicker e.g. it has a newer version of bash)

You can make terminal use this as in the Homebrew answer

To install macports follow these instructions which are
1. Install Xcode and the Xcode Command Line Tools
2. Agree to Xcode license in Terminal: sudo xcodebuild -license
3. Download MacPorts pkg for your version of OS X: links are on the page
4. Run the pkg

When you have macports installed you need to latest versions, this is done by running

sudo port selfupdate

and recompile or get the latest binaries by

sudo port upgrade outdated

Solution 3:

NOTE regarding the official Apple OS X bash Update 1.0: This software update only brings the official Apple bash version to 3.2.53. The 3.2.54 patch revision offers the following change:

This patch changes the encoding bash uses for exported functions to avoid clashes with shell variables and to avoid depending only on an environment variable's contents to determine whether or not to interpret it as a shell function.

For users who have already patched the system with 3.2.54 binaries, you may either replace your compiled binaries with the Apple patch or you can leave things as they are but it is ill-advised. Although Apple left their binary versioning at 3.2.53, the Apple patch DOES contain the fix for the below exploit test:

env X='() { (a)=>\' sh -c "echo date"; cat echo

This means that the Apple official 3.2.53 binary contains equivalent security to the vanilla GNU 3.2.54 binary. An unfortunate point of confusion, but it is what it is. Apple's fix is not half-baked. It appears to be a complete fix for the problem. As such, the below roadmap to compiling vanilla bash and sh from GNU source should be considered a historic artifact and possibly consulted as a template for how to do patches in the future should they be necessary.

NOTE: With the vanilla GNU source, sh has privilege elevation problems that cause failures in various installers, e.g., Adobe Flash. I strongly recommend sticking with the Apple-patched binaries. Consider this patch scheme to be deprecated and ill-advised.

There is a new GNU bash 3.2.55 patch that describes the following fix:

Bug-Description:

There are two local buffer overflows in parse.y that can cause the shell to dump core when given many here-documents attached to a single command or many nested loops.

We leave it up to the gentle reader to determine whether to sit with the official Apple-patched binaries or roll your own to deal with the new possible exploits. Personally, I will be sticking with the Apple binaries.


This post details how to compile and install a vanilla bash and sh on OS X. I chose this route as following examples detailing using Apple-specific source did not leave me with the correct patch revision. YMMV. This vanilla installation is, however, targeted at replacing the OS X binaries such that when Apple does finally release a security update, these vanilla replacements will be usurped by by their proper Apple counterparts.

My base configuration is:

OS X Lion 10.7.5 and Xcode 4.6.3 with all command-line utilities installed.

My steps to fix this were:

Download the base bash source code for 3.2.48 from:

https://ftp.gnu.org/gnu/bash/bash-3.2.48.tar.gz

Download the bash3.2.49, .50, .51, .52, .53, .54 and .55 patches from:

https://ftp.gnu.org/gnu/bash/bash-3.2-patches/

I saved them as $filename.patch, e.g., bash3.2.50.patch.

CD into your download directory and …

Unpack the main source branch:

tar xzvf bash-3.2.48.tar.gz

cd bash-3.2.48

Assuming that you've renamed your downloaded patch files as described earlier,

cp ../*.patch .

Then …

for file in *.patch ; do
  patch -p0 < $file
done

This should show successful patches of various files. If not, be prepared to do some exploration and investigation.

Next:

sudo cp /bin/bash /bin/bash_old
sudo cp /bin/sh /bin/sh_old
sudo chmod -x /bin/bash_old
sudo chmod -x /bin/sh_old

That basically backed up your old, vulnerable bash and sh shells and removed their executable privilege. That gives you the capacity to restore the commands as necessary, but removes their ability to do damage in the meantime.

Next:

./configure --prefix=/ ; make ; sudo make install

This should correctly configure, compile and install the new bash binary into /bin. After it's done, exit Terminal and reopen.

You should, all things happy and smiling, be able to bash --version and now see 3.2.55, e.g.:

Gaia:Downloads trane$ bash --version
GNU bash, version 3.2.55(1)-release (i386-apple-darwin11.4.2)
Copyright (C) 2007 Free Software Foundation, Inc.

The exact output in the command above will differ depending on your version of OS X.

You should also be able to test your vulnerability against bash and find that it is fine.

NOTE: We've only fixed bash so far, but the /bin/sh executable is still in its vulnerable state. Merely copying bash atop sh is a Linux style of doing things. OS X's sh implementation has some differences from bash, however, so you'll want to drag out the compiler again. Further information on how bash and sh differ in OS X can be found here:

https://apple.stackexchange.com/a/89327/91441

In your download directory do:

make clean

In your favourite editor, open the file Makefile.in and scroll to line 99. We're going to change the Program line so that the binary we output is sh instead of bash like so:

Program = sh$(EXEEXT)

Save it and then

./configure --prefix=/ --enable-xpg-echo-default --enable-strict-posix-default
make ; sudo make install

Now you'll have built sh almost exactly as Apple would.

One final note: On some (all?) systems, Apple generally seems to place the bashbug executable in /usr/bin. Our compile will have put it into /bin. So, the final steps here:

sudo mv /usr/bin/bashbug /usr/bin/bashbug_old
sudo chmod -x /usr/bin/bashbug_old
sudo mv /bin/bashbug /usr/bin/bashbug

Solution 4:

For anyone struggling with compiling from source, as of September 29th, Apple has officially released patches for Mac OS X 10.9.5, 10.8.5 as well as 10.7.5:

  • OS X bash Update 1.0 – OS X Mavericks
  • OS X bash Update 1.0 – OS X Mountain Lion
  • OS X bash Update 1.0 - OS X Lion

Solution 5:

First, patching bash and sh for this vulnerability is likely to break some scripts on your Mac. You really don't need to do this unless you are are offering web services to the public internet directly from your Mac. So if it is really not necessary, wait until there is an official security update from Apple.

Being warned, here are some instructions on how to do this update using Brew on Mavericks 10.9.

First confirm that you are using an outdated bash:

$ which bash
/bin/bash
$ /bin/bash --version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.

The most current bash is 4.3.25

If you don't have Xcode installed, you'll need the Xcode command line tools, which can be installed by

$ xcode-select --install

Or from the developer portal.

To install Brew (http://brew.sh):

$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Then do:

$ brew doctor

Follow any instructions if there are problems. Many common problems are addressed here.

Then update brew to the latest list of packages:

$ brew update

To get the latest bash 4.3.25:

$ brew install bash

This installs bash into /usr/local/Cellar/bash/4.3.25/bin/bash

The old bash and sh still exists at /bin, so after installing you'll rename the old executables to a new file.

$ sudo mv /bin/bash /bin/bash_old
$ sudo mv /bin/sh /bin/sh_old

If you are very paranoid, you can remove execute permissions on the bash_old

$ sudo chmod a-x /bin/bash_old /bin/sh_old

Then create a symbolic link to the new bash 4.3.25 that brew installed.

$ sudo ln -s /usr/local/Cellar/bash/4.3.25/bin/bash /bin/bash
$ sudo ln -s /usr/local/Cellar/bash/4.3.25/bin/bash /bin/sh

Reboot and it is complete.

A warning — this may break some existing shell scripts that might rely on bash 3.2 or the differences that the Mac sh has over the linux sh. There is a much more sophisticated answer to replacing bash and sh from sources, from an answer by @TraneFranks in this same thread.