-
-
Save mattwhite/86de50d30134129e44ef to your computer and use it in GitHub Desktop.
# inspired by http://askubuntu.com/a/528171 and the comments below | |
# build bash 3.2, though this should work for other versions as well | |
BASH_MAJOR=3 | |
BASH_MINOR=2 | |
# prerequisites | |
sudo apt-get install build-essential gettext bison | |
# get bash source | |
mkdir src && cd src | |
wget https://ftp.gnu.org/gnu/bash/bash-$BASH_MAJOR.$BASH_MINOR.tar.gz | |
tar zxvf bash-$BASH_MAJOR.$BASH_MINOR.tar.gz | |
cd bash-$BASH_MAJOR.$BASH_MINOR | |
# download, verify, and apply all available patches, which as of 2014-10-02 | |
# include patches for CVE-2014-6271, CVE-2014-7169, CVE-2014-6277, CVE-2014-6278 | |
# CVE-2014-7186, and CVE-2014-7187. | |
wget -nv -r 1 -nH -nd -np https://ftp.gnu.org/gnu/bash/bash-$BASH_MAJOR.$BASH_MINOR-patches/ | |
wget -nv https://ftp.gnu.org/gnu/gnu-keyring.gpg | |
for i in bash$BASH_MAJOR$BASH_MINOR-???; do | |
if gpg --verify --keyring ./gnu-keyring.gpg $i.sig; then | |
if ! patch -p0 < $i; then | |
echo "patch $i failed" | |
exit 1 | |
fi | |
else | |
echo "patch $i has a bad signature" | |
exit 2 | |
fi | |
done | |
# compile and install to /usr/local/bin/bash | |
./configure && make | |
sudo make install | |
# point /bin/bash to the new binary | |
if /usr/local/bin/bash -c 'true'; then | |
if [ ! -f /bin/bash.old ]; then | |
sudo mv /bin/bash /bin/bash.old | |
sudo ln -s /usr/local/bin/bash /bin/bash | |
fi | |
else | |
echo "bash not installed correctly!" | |
exit 3 | |
fi | |
# test each of the exploits on the old version of bash | |
echo "OLD BASH:" | |
env x='() { :;}; echo VULNERABLE to CVE-2014-6271' /bin/bash.old -c echo | |
env x='() { (a)=>\' /bin/bash.old -c "echo echo TEST" 2>/dev/null; cat echo 2>/dev/null; rm -f ./echo; echo "If you see 'echo TEST' above you are ok, if you just see 'TEST' you are VULNERABLE to CVE-2014-7169" | |
/bin/bash.old -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo "VULNERABLE to CVE-2014-7186" | |
(for x in {1..200} ; do echo "for x$x in ; do :"; done; for x in {1..200} ; do echo done ; done) | /bin/bash.old || echo "VULNERABLE to CVE-2014-7187" | |
# test each of the exploits on the new version of bash | |
echo "NEW BASH:" | |
env x='() { :;}; echo Vulnerable to CVE-2014-6271' bash -c echo | |
env x='() { (a)=>\' bash -c "echo echo TEST" 2>/dev/null; cat echo 2>/dev/null; rm -f ./echo; echo "If you see 'echo TEST' above you are ok, if you just see 'TEST' you are VULNERABLE to CVE-2014-7169" | |
bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo "VULNERABLE to CVE-2014-7186" | |
(for x in {1..200} ; do echo "for x$x in ; do :"; done; for x in {1..200} ; do echo done ; done) | bash || echo "VULNERABLE to CVE-2014-7187" | |
echo "NOTE: CVE-2014-6277 and CVE-2014-6278 should be mitigated by these patches as well, but there is not yet a test for them." |
Why not going for a full download of all patches? Current solution needs fixing for every new patch that appears. My idea is to download the full patches folder and someone at ycombinator (https://news.ycombinator.com/item?id=8374948) had the same idea:
wget -r -l1 -nH -nd -np http://ftp.gnu.org/gnu/bash/bash-4.3-patches/ && rm *.sig index.html
cd bash-4.3
for i in ../bash43-*; do patch -p0 < $i; done
Maybe get rid of the static bash-version, too so one can apply the same script to some newer (or older) bash later on.
Above code is just deleting the *.sig, but one can easily extend the for-loop like this (untested):
for i in ../bash43-???; do
if gpg --verify --keyring ./gnu-keyring.gpg $i.sig; then
if ! patch -p0 < $i; then
echo "patch $i failed"
exit 1
fi
else
echo "patch $i has a bad signature!"
exit 2
fi
done
This is awesome, thanks.
Added auto-finding of latest patch level: https://gist.github.com/tonyflint/fddb5a3c669b8ae7d897
Thanks for the suggestions @Archetrix amd @TonyFlint. I have added downloading all available patches and put the bash version into env variables. I have also added tests for some of the subsequent bash vulnerabilities.
I'm still full of ideas :)
Is it intentionally to compile with default settings?
./configure --prefix=/usr --bindir=/bin --sbindir=/sbin --sysconfdir=/etc && make
Oh i just saw your tests at the end. I've got a test for the latest patch:
env ls="() { echo 'Game over'; }" bash -c ls
Basically if you get "ls" of your current folder it's OK if you get "Game over" you're screwed 😉
Or do this:
env date="() { echo 'doomsday'; }" bash -c date
If it returns a date it's ok if not .... 😄
I fun-tested bash 2.05b (has recent patches)
There are really old patches which don't have a .sig file.
thanks to all who helped putting this together, saves a lot of time!
btw.: Consider removing/archiving bash.old
Hi thanks for the script but im having problem with the last two tests..
dtest:/bash# bash --version/bash# echo $BASH_VERSION
GNU bash, version 3.2.54(1)-release (i686-pc-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
dtest:
3.2.54(1)-release
dtest:/bash#/bash# bash -c 'true <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF <<EOF' || echo "VULNERABLE to CVE-2014-7186"
dtest:
Segmentation fault
VULNERABLE to CVE-2014-7186
dtest:/bash# (for x in {1..200} ; do echo "for x$x in ; do :"; done; for x in {1..200} ; do echo done ; done) | bash || echo "VULNERABLE to CVE-2014-7187"/bash#
bash: line 129: syntax error near x129' bash: line 129:
for x129 in ; do :'
VULNERABLE to CVE-2014-7187
dtest:
@Archetrix, yes, I wanted to build in /usr/local/bin since this was a locally-compiled version of bash and not the one from the package.
@piccaso, no problem. i like keeping bash.old around in order to compare results of any new exploits found between the original and patched version.
@section1, previously the last two tests failed because bash 3.2 was not yet patched against them. however, a new patch was released on Oct 1, so you'll need to recompile bash. I can verify that the latest patch fixes the last two vulnerabilities.
Another …. tweak:
build bash 3.2, though this should work for other versions as well
BASH_VER=bash --version | grep 'version' | awk '{print $4};'
BASH_MAJOR=$(echo $BASH_VER | cut -d '.' -f1)
BASH_MINOR=$(echo $BASH_VER | cut -d '.' -f2)
Hi
I signed in here to comment THIS IMPORTANT ISSUE in your script (and forks as TonyFlint's).
The problem is the method to replace the vulnerable bash: a symbolic link to the patched bash. In my Debian 5 Lenny nodes, the /usr/local resides on A SEPARATE file system from the ROOT FILE SYSTEM, therefore /bin and /usr/local/bin reside on differente devices.
This causes an unbootable system because, in that case, the /bin/bash is not available to execute the scripts /etc/init.d/rcS, /etc/init.d/rc.
Therefore, instead of create a symbolic link, copy the patched binary bash into /bin.
Best regards
Thanks @sodabrew, I updated it.