Bash – How does `env X='() { (a)=>\’ sh -c “echo date”` work

bashshellshock

After reading about the latest bash vulnerability, I was wondering how Tavis Ormandy's exploit works. How does (a)=>\ work?

He posted:

The bash patch seems incomplete to me, function parsing is still brittle. e.g.

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

Best Answer

GNU Bash exports shell functions in environment variables which include the function definitions:

$ function foo { echo bar; }
$ export -f foo
$ env | grep -A1 foo
foo=() { echo bar
}

When a new Bash instance is spawned, it looks for environment variables matching a certain pattern. The contents of those variables are automatically imported as shell functions. As Stéphane Chazelas explains, since this feature was introduced in Bash 1.03, importing of functions was done simply by replacing the = in the corresponding entry in the environment variable array, and interpreting the result as a function definition. Prior to the patch that fixed CVE-2014-6271, the environment variable was interpreted in its entirety, including any commands that follow the actual function body. The patch introduces two special modes to the parse_and_execute() function, SEVAL_FUNCDEF and SEVAL_ONECMD. When the function is called with SEVAL_FUNCDEF, it is supposed to prevent the interpretation of commands other than function definitions. The SEVAL_ONECMD flag is supposed to prevent the function from evaluation more than a single command.

Tavis Ormandy's specially crafted environment variable does something subtly different. It is designed to confuse the parser and corrupt the buffer used to the store the commands to be evaluated. Remnants of the environment variable in the buffer change the interpretation of the subsequent command. This related issue has received the CVE identifier CVE-2014-7169.

The constituents of environment variable definition X='() { (a)=>\' are:

  • () { which is interpreted by the parser as the beginning of a function definition

  • (a)= is intended to confuse the parser and cause it to leave remnants of the environment variable in the buffer

  • >\ is the actual payload that is left in the buffer

The purpose of the payload is to change the interpretation of the command executed in the subshell invoked by sh -c "echo date";. This of course assumes that /bin/sh is a symbolic link to bash. When the command string specified as an operand to -c is placed in the buffer, the contents of the buffer are:

>\[0xA]echo date

The [0xA] is an ASCII newline character, which would normally act as a command separator, but is now escaped by the \ from the payload. As a result, the contents of the buffer are interpreted as

>echo date

Because Bash allows redirection operators to precede commands, this is equivalent to

date > echo 

This simply causes the date command to be executed with its standard output redirected to a file called echo. The remaining cat echo is not part of the exploit, it only demonstrates that now a file called echo containing the output of date exists.

As to why the string (a)= confuses the parser in this case, it would seem to that the it is related to it appearing as a (malformed) nested function definition. The simplified variant of the exploit demonstrates this more clearly:

$ X='() { function a a>\' bash -c echo
$ ls echo
echo