Bash Me Some More

Credit: vixie
Risk: High
Local: No
Remote: Yes

Good morning! This is kinda long. == Background == If you are not familiar with the original bash function export vulnerability (CVE-2014-6271), you may want to have a look at this article: Well, long story short: the initial maintainer-provided patch for this issue [1] (released on September 24) is *conclusively* broken. After nagging people to update for a while [5] [7], I wanted to share the technical details of two previously non-public issues which may be used to circumvent the original patch: CVE-2014-6277 and CVE-2014-6278. Note that the issues discussed here are separate from the three probably less severe problems publicly disclosed earlier on: Tavis' limited-exploitability EOL bug (CVE-2014-7169) and two likely non-exploitable one-off issues found by Florian Weimer and Todd Sabin (CVE-2014-7186 and CVE-2014-7187). == Required actions == If you have installed just the September 24 patch [1], or that and the follow-up September 26 patch for CVE-2014-7169 [2], you are likely still vulnerable to RCE and need to update ASAP, as discussed in [5]. You are safe if you have installed the unofficial function prefix patch from Florian Weimer [3], or its upstream variant released on September 28 [4]. The patch does not eliminate the problems, but shields the underlying parser from untrusted inputs under normal circumstances. Note: over the past few days, Florian's patch has been picked up by major Linux distros (Red Hat, Debian, SUSE, etc), so there is a reasonable probability that you are in good shape. To test, execute this command from within a bash shell: foo='() { echo not patched; }' bash -c foo If you see "not patched", you probably want upgrade immediately. If you see "bash: foo: command not found", you're OK. == Vulnerability details: CVE-2014-6277 (the more involved one) == The following function definition appearing in the value of any environmental variable passed to bash will lead to an attempt to dereference attacker-controlled pointers (provided that the targeted instance of bash is protected only with the original patches [1][2] and does not include Florian's fix): () { x() { _; }; x() { _; } <<a; } A more complete example leading to a deref of 0x41414141 would be: HTTP_COOKIE="() { x() { _; }; x() { _; } <<`perl -e '{print "A"x1000}'`; }" bash -c : bash[25662]: segfault at 41414141 ip 00190d96 sp bfbe6354 error 4 in[110000+191000] (If you are seeing 0xdfdfdfdf, see note later on). The issue is caused by an uninitialized here_doc_eof field in a REDIR struct originally created in make_redirection(). The initial segv will happen due to an attempt to read and then copy a string to a new buffer through a macro that expands to: strcpy (xmalloc (1 + strlen (redirect->here_doc_eof)), (redirect->here_doc_eof)) This appears to be exploitable in at least one way: if here_doc_eof is chosen by the attacker to point in the vicinity of the current stack pointer, the apparent contents of the string - and therefore its length - may change between stack-based calls to xmalloc() and strcpy() as a natural consequence of an attempt to pass parameters and create local variables. Such a mid-macro switch will result in an out-of-bounds write to the newly-allocated memory. A simple conceptual illustration of this attack vector would be: -- snip! -- char* result; int len_alloced; main(int argc, char** argv) { /* The offset will be system- and compiler-specific */; char* ptr = &ptr - 9; result = strcpy (malloc(100 + (len_alloced = strlen(ptr))), ptr); printf("requested memory = %d\n" "copied text = %d\n", len_alloced + 1, strlen(result) + 1); } -- snip! -- When compiled with the -O2 flag used for bash, on one test system, this produces: requested memory = 2 copied text = 28 This can lead to heap corruption, with multiple writes possible per payload by simply increasing the number of malformed here-docs. The consequences should be fairly clear. [ There is also a latter call to free() on here_doc_eof in dispose_cmd.c, but because of the simultaneous discovery of the much simpler bug '78 discussed in the next section, I have not spent a whole lot of time trying to figure out how to get to that path. ] Perhaps notably, the ability to specify attacker-controlled addresses hinges on the state of --enable-bash-malloc and --enable-mem-scramble compile-time flags; if both are enabled, the memory returned by xmalloc() will be initialized to 0xdf, making the prospect of exploitation more speculative (essentially depending on whether the stack or any other memory region can be grown to overlap with 0xdfdfdfdf). That said, many Linux distributions disable one or both flags and are vulnerable out-of-the-box. It is also of note that relatively few distributions compile bash as PIE, so there is little consolation to be found in ASLR. Similarly to the original vulnerability, this issue can be usually triggered remotely through web servers such as Apache (provided that they invoke CGI scripts or PHP / Python / Perl / C / Java servlets that rely on system() or popen()-type libcalls); through DHCP clients; and through some MUAs and MTAs. For a more detailed discussion of the exposed attack surface, refer to [6]. == Vulnerability details: CVE-2014-6278 (the "back to the '90s" one) == The following function definition appearing in the value of any environmental variable passed to bash 4.2 or 4.3 will lead to straightforward put-your-command-here RCE (again, provided that the targeted instance is not protected with Florian's patch): () { _; } >_[$($())] { echo hi mom; id; } A complete example looks like this: HTTP_COOKIE='() { _; } >_[$($())] { echo hi mom; id; }' bash -c : ...or: GET /some/script.cgi HTTP/1.0 User-Agent: () { _; } >_[$($())] { id >/tmp/hi_mom; } Note that the PoC does not work as-is in more ancient versions of bash, such as 2.x or 3.x; it might have been introduced with xparse_dolparen() starting with bash 4.2 patch level 12 few years back, but I have not investigated this in a lot of detail. Florian's patch is strongly recommended either way. The attack surface through which this flaw may be triggered is roughly similar to that for CVE-2014-6277 and the original bash bug [6]. == Additional info == Both of these issues were identified in an automated fashion with american fuzzy lop: The out-of-the-box fuzzer was seeded with a minimal valid function definition ("() { foo() { foo; }; >bar; }") and allowed to run for a couple of hours on a single core. In addition to the issues discussed above, the fuzzer also hit three of the four previously-reported CVEs. I initially shared the findings privately with vendors, but because of the intense scrutiny that this codebase is under, the ease of reproducing these results with an open-source fuzzer, and the now-broad availability of upstream mitigations, there seems to be relatively little value in continued secrecy. == References == [1] [2] [3] [4] [5] [6] [7] PS. There are no other bugs in bash. --------- FOLLOW UP ----------- Date: Wed, 01 Oct 2014 07:32:57 -0700 From Wed Oct 1 14:37:33 2014 From: Paul Vixie <> To: Michal Zalewski <> Cc: "" <> Subject: Re: [FD] the other bash RCEs (CVE-2014-6277 and CVE-2014-6278) michal, thank you for your incredibly informative report here. i have a minor correction. > Michal Zalewski <> > Wednesday, October 01, 2014 7:21 AM > ... > > Note: over the past few days, Florian's patch has been picked up by > major Linux distros (Red Hat, Debian, SUSE, etc), so there is a > reasonable probability that you are in good shape. To test, execute > this command from within a bash shell: > > foo='() { echo not patched; }' bash -c foo this command need not be executed from within bash. the problem occurs when bash is run by the command, and the shell that runs the command can be anything. for example, on a system where i have deliberately not patched bash, where sh is "ash" (almquist shell): > $ foo='() { echo not patched; }' bash -c foo > not patched here's me testing it from within tcsh: > % env foo='() { echo not patched; }' bash -c foo > not patched > % (setenv foo '() { echo not patched; }'; bash -c foo) > not patched this is a minor issue, but i've found in matters of security bug reports, tests, and discussions, that any minor matter can lead to deep misunderstanding. thanks again for your excellent report, and your continuing work on this issue. vixie

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2022,


Back to Top