How does CVE-2014-7169 work? Breakdown of the test code
Asked Answered
E

2

11

With a bash release which has been patched for shellshock

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

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

another similar exploit still works and has been assigned CVE-2014-7169

$ env X='() { (a)=>\' bash -c "echo date"; cat echo
bash: X: line 1: syntax error near unexpected token `='
bash: X: line 1: `'
bash: error importing function definition for `X'
Thu Sep 25 12:47:22 EDT 2014

$ ls echo
echo

Looking for a breakdown of this as well.

Egg answered 25/9, 2014 at 15:6 Comment(4)
unix.stackexchange.com/questions/157329/…Semicircle
Already asked and answered here on SO, too.Assure
@CharlesDuffy Thanks for the question you linked, that was really helpful; too bad I didn't find that from searching shellshock. I just found another snippet that is not explained by that question though and seems hard to find since it is eclipsed by the simpler test code. Do you know of another question which answers this?Egg
The part added by the edit is indeed not duplicative [with #26022748, as previously given in close reason].Assure
S
16

The bug

CVE-2014-7169 is a bug in bash's parser. Bash's parser uses a variable eol_ungetc_lookahead to ungetc characters across lines. That variable wasn't being properly reset from the reset_parser function, which is called e.g. on some syntax errors. Using that bug, it's possible to inject a character into the start of the next bash input line.

So the test code forces a syntax error, using either (a)= or function a a, adds the redirection character to prepend to the next line >, and adds a line continuation \, which leads to either version of the test code:

() { (a)=>\
() { function a a>\

When bash is executed, it processes variables from the environment, finds that variable X is a exported function, and evaluates it to import the function. But the evaluation fails with a parse error, leaving the > character in the eol_ungetc_lookahead variable. Then, when parsing the command argument echo date, it prepends the > character, leading to >echo date, which runs date redirected to a file named echo.

Its relation to the previous bug

The above bug is obviously very different to the original shellshock bug. There are actually several problems:

  • Bash evaluates completely a variable that looks like an exported function (starts with the four characters () {). CVE-2014-6271.
  • Under some conditions, it is possible to inject a character into an ungetc variable, that will be prepended to the next input line. CVE-2014-7169.
  • Bash allows every environment variable to be treated like an exported function, so long as it starts with the four characters () {. CVE-2014-6271, CVE-2014-7169, all the other CVEs where a bug is triggered in bash's parser.
  • There is a limited stack for here-doc redirection, and there is no check for overflow. CVE-2014-7186, which leads to memory corruption, and can probably be leveraged for arbitrary code execution.
  • There is a limited stack for nested control structures (select/for/while), with checks for overflow. That stack is still corrupted. CVE-2014-7187.

The fixes

  • The first patch restricts bash to evaluating a single function definition in each variable that looks like a exported function.
  • The second patch properly resets eol_ungetc_lookahead on reset_parser.
  • The third patch changes how functions are exported: now they are exported in variables named BASH_FUNC_functionname%%.

Attack surface

The big problem here has been that every environment variable could be used as a vector for attack. Typically, attackers cannot control arbitrary environment variables, otherwise there are already other known attacks (think of LD_PRELOAD, PATH, IFS, ...).

sudo is not affected because it strips exported bash functions from the environment, as mentioned by Gilles on security.SE.

ssh is affected. Typical sshd installations only allow a limited set of environment variables to be exported as configured in AcceptEnv in sshd_config, e.g: LANG and LC_*. Even with this aggressive whitelisting approach, in shellshock any variable could be an attack vector.

Not only was every environment variable a potential attack vector, they exposed a >6000 lines parser.

Lessons relearned

system, popen, and others are potentially dangerous. Not only should you take care with their arguments: even when the arguments are fixed at compile-time, the environment is a potential attack vector. Use fork()/execve(), preferably with a clean environment (but at least restrict the environment to white-listed variables, preferably with their values sanity-checked). Remember that a good quality system does what it is supposed to do, while a secure system does what it is supposed to do and nothing more. Invoking a full-blown shell makes doing nothing more a little bit harder.

Complexity is the enemy of security. These days you can easily find people recommending simpler shells. Most shells are free from shellshock by not supporting exported functions at all. Conversely, bash has received lots of security features over the years (you need to invoke it with -p to avoid it dropping privileges on startup, it sanitizes IFS, ...), so don't assume I'm advocating switching shells, this is more of a general advice.

Some excerpts from David Wheeler's ancient "Secure Programming for Linux and UNIX HOWTO" chapter on environment variables are still worth rereading.

§5.2.3 ¶1:

For secure setuid/setgid programs, the short list of environment variables needed as input (if any) should be carefully extracted. Then the entire environment should be erased, followed by resetting a small set of necessary environment variables to safe values. There really isn't a better way if you make any calls to subordinate programs; there's no practical method of listing ``all the dangerous values''.

§5.2.3 ¶6:

If you really need user-supplied values, check the values first (to ensure that the values match a pattern for legal values and that they are within some reasonable maximum length).

Semicircle answered 30/9, 2014 at 0:47 Comment(1)
Wow, awesome answer, learned a lot! Didn't know that >echo date is actually legal syntax; I've always used the date > echo style.Egg
C
1

Waving my hands a lot, I suspect the new exploit does the following:

  1. The backslash helps bypass the original patch, so that the string is still evaluated.
  2. The > combines with echo as an output redirection for the bash shell
  3. With echo being consumed by the evaluation to define the function, the only part of the -c argument left to execute is date, whose output goes to a file name echo instead of standard output.

That's the best I can come up with short of reading the bash source, but I suspect the backslash facilitates some sort of buffer overflow that allows the environment string and the argument to -c to be merged.

Chymotrypsin answered 25/9, 2014 at 18:48 Comment(3)
The backslash is probably used to escape a newline.Semicircle
Ok, I think I know what is happening here. Bash's yacc parser uses a variable to ungetc characters across lines. That variable wasn't being properly reset on parse error. The new exploit forces a syntax error, leaving > on the ungetc variable. Eventually, > is ungetc'ed as the first character in the next line.Semicircle
Ah, that makes sense, and I know the patches for this seem to be doing something about lookahead. Still not sure about the role the backslash plays, but the newline does make some sense.Chymotrypsin

© 2022 - 2024 — McMap. All rights reserved.