Bash bug: the other two RCEs, or how we chipped away at the original fix
lcamtuf.blogspot.com
lcamtuf.blogspot.com
I must say that this shellchock thing has shaken my belief in humanity somewhat... Why is it that these are not obvious principles that we all agree on? Am I just too "oldschool" or something? :)
SIP, for instance, has very complicated parsing rules (like HTTP) because the messages are designed to be written by hand. This introduces security holes as well as interop. But instead of recognizing this and trying to get programs to be strict, the IETF publishes a document where they gleefully list a bunch of crazy things possible in their spec, and encourage programs that guess at the intent of malformed messages.
- The original ShellShock: Reused the general parsing/execution function for the subset task of evaluating a function definition. A hand-written parser would likely have this isolated to its own function. With a Yacc parser, there is neither an obvious nor easy way to call directly into the parser to parse a "nonterminal".
- The ones in the article having to do with error handling: traditionally, error handing in autogenerated parsers has been more difficult and Yacc is no exception. This is related to the first point in that a function for only parsing the function definitions would never execute its input, even upon encountering an error; the usual abort behaviour means the parser stack unwinds until the original caller - in this case the code parsing environment variables for function definitions - recognises the error, outputs an error message, and in this case, ignores the definition.
- The operation of a recursive-descent parser is simpler to trace through manually since each piece of the grammar is logically broken into separate functions, making it easier to audit than the more opaque flow of a Yacc one.
I have a feeling we'll be seeing different variations of this type of attack for a long time now that people are thinking about this type of vulnerability. The ways that this type of thing can be combined with other exploits are both exciting and terrifying.
Really? Don't you think its easier to audit the system to ensure that nobody's parsing the entire environment as if it was shell script / function definitions, threatening to execute parts of it as shell commands?
Here we're talking about a system made up of several different Unix processes, passing data between them through environment variables, command line arguments, input and output. This seems to affect how people think about the problem in an unfortunate way... Pretend instead that all this happened within one process, e.g. a Ruby program - who would then be responsible for the vulnerability - person A who stored a HTTP request header in a variable or person B who decided to call eval() on that variable?
To me it's quite obvious that person B is at fault.
* CVE-2014-6271 (original shellshock)
* CVE-2014-7169 (taviso bug)
* CVE-2014-7186 (redir_stack bug)
* CVE-2014-7187 (address sanitizer)
* CVE-2014-6277 (lcamtuf bug #1) [no patch]
* CVE-2014-6278 (lcamtuf bug #2)
bash -c "f(){ x(){ _;};x(){ _;}<<a;}"
Segmentation fault (core dumped)(It wasn't necessarily a security issue, but I figured I'd go exploring to learn some bash internals.)
It was in no way clear that Red Hat's second release included Florian's fixes - I found out from Mark Cox's post on this Twitter thread - https://twitter.com/lcamtuf/status/516297412579581952