So yesterday a 20-odd year old bug in the popular bash shell was announced as CVE-2014-6271. In essence the bug allows a user to set a environmental variable that includes additional executable code. Later when that environmental variable is read as part of a Bash sub process the code will be executed. The biggest impact will be exploits via CGI, but anything that makes use of Bash will execute any ‘compromised’ environmental variables.

CGI converts HTTP headers into environmental variables, which in itself isn’t too scary, it’s what it’s supposed to do. We’d expect anything that then used these variables to sanitise them and that’s where the problem lies. If it’s Bash reading this environment and one of those variables is suitably crafted Bash will kindly execute that code. Now not many people are going to write CGI scripts in Bash, but potentially on some systems other code might start a shell to perform some task and if this shell is Bash (perhaps because /bin/sh is a link to Bash) then it’ll be executing the payload contained in the environmental variable(s).

Now firstly we can be a little smug because FreeBSD doesn’t ship with Bash installed. Nope no Bash here please. However Bash is such a common shell all our users expect it and it’s often part of the standard set of packages we deploy on new servers - so time to lose the smug face and get it updated!

Testing versions of Bash for the vulnerability is easy and there are lots of “one liners” floating around, however in good *NIX tradition it’s not very clear what is happening. If you break the test down into setting the environmental variable and then starting a bash sub process you can see it more clearly.

So for example on a vulnerable copy of bash

export somevariablename='() { :;}; echo Vulnerable'

Will set the environmental variable somevariablename to the value () { :;}; echo vulnerable. Now if we use bash to echo some content to the console

bash -c "echo Some interesting comment on security"      

Bash will load it’s environment including our odd somevariablename variable. Now we’d expect to see an output like:

Some interesting comment on security

From this script, what we see on a vulnerable machine however is output like this

Vulnerable
Some interesting comment on security

So our odd environmental variable has actually been executed and echoed the word ‘Vulnerable’ to the console. As you can imagine it’s possible to do a lot more than just echo some additional text in the Bash sub process.

On a version of Bash that isn’t vulnerable you see a warning message like this

bash: warning: somevariablename: ignoring function definition attempt
bash: error importing function definition for `somevariablename'

As far as I understand you would normally use this for exporting functions to use in your code, so for example you might do

$ export sayhello='() { echo "Hello world" ; }'
$ bash -c 'sayhello'
Hello world 

However as we saw with our test above code beyond the end of the function is also executed (the echo Vulnerable bit), this is simply due to limitations in the code that determines what is an acceptable function-like string to store.

Sundive Networks primarily operate FreeBSD based servers that by default don’t use the Bash shell, but instead use versions of the C shell and Bourne shell. However the Bash shell is widely used by many third party tools that many FreeBSD machines will have copies installed.

FreshPorts is reporting that the ports tree currently has Bash version 4.3.25 [EDIT - a 4.3.25_1 is now present to fix CVE-2014-3659]. There is also a statically complied version of Bash in the ports tree which is a slave port to the main Bash port. We’ll have to wait for a package to become available on the package servers, but until then it’s trivial to compile the port to replace a currently installed package (if that’s how you manage your software). So on our FreeBSD 10 servers with Bash we should be able to simply run:

$ cd /usr/ports/shells/bash-static
$ make reinstall clean BATCH=yes 

However life is never that easy and we get an error

pkg(8) must be version 1.3.8 or greater, but you have 1.3.7. You must upgrade pkg(8) first

Alas as of writing this pkg version 1.3.8 is not available on the package repository - so we need to build that from ports! Why does the Bash port need pkg version 1.3.8 or above? Well in /usr/ports/Mk/bsd.port.mk you’ll find a variable MINIMAL_PKG_VERSION which sets the the minimum version needed. That’s currently set to 1.3.8. Little bit of a shame the MINIMAL_PKG_VERSION was bumped before 1.3.8 was actually in the package repository, but ho hum.

$ cd /usr/ports/ports-mgmt/pkg
$ make reinstall clean BATCH=yes 

An alternative is to remove pkg and bootstrap it again, then you’d get version 1.3.8. Anyhow now we can go back and do the build of Bash (bash-static in our case)

Then when we re-test the exploit we instead see (firstly switching to a Bash shell if we’re not already using it!)

$ export somevariablename='() { :;}; echo Vulnerable' 
$ bash -c "echo Some interesting comment on security" 
bash: warning: somevariablename: ignoring function definition attempt
bash: error importing function definition for `somevariablename' 
Some interesting comment on security

Hooray! A version of the Bash shell that is not vulnerable. Of course once 3.2.25 makes it onto the package servers for those using packages it becomes trivial to just do a pkg upgrade. Until then if you’ve got lots of machines to patch then you might be better off building packages of pkg-1.3.8 and bash-4.3.5 putting them somewhere and using pkg add -f to install them.