What you need to know about the Bash Bug aka Shellshocked

European security researcher Stéphane Chazelashas discovered a critical vulnerability in the command-line shell known as Bash, or GNU Bourne-again Shell, the most widely deployed shell for Unix-based systems. The bug allows arbitrary, injected code to be executed as part of the assignment of environment variables. While Bash is deployed in many systems, including Linux, Debian, Ubuntu, MAC OS X, Android, and has even been ported to Windows, not all Bash implementations are vulnerable/exposed.

There is already a lot of media attention on the size and scope of this threat. The distinction between vulnerable hosts and truly exposed hosts becomes critical in this scenario. There are numerous variables required for exploitation to be successful. Our research teams are diligently analyzing the finer points of this threat and as more detail becomes available (and confirmed), it will be communicated quickly and clearly.  At this time, we recommend following the guidance of affected vendors around the application of available patches and updates.

Critically exposed systems include, but are not limited to, those providing shells to remote users, parsing of CGI scripts, or executing remote commands.

How we’re addressing the problem

Several McAfee products/technologies have been updated to address or mitigate this issue.   Please continue to watch this location, as this list will be continually updated as our analysis progresses.

  • McAfee Network Security Platform –Coverage for Apache CGI and SSH is released.
  • McAfee Next Generation Firewall – Coverage Released Today
  • McAfee Vulnerability Manager – Coverage Released Today
  • McAfee Host Intrusion Prevention – Coverage exists on Linux and Solaris endpoints (Apache CGI).  Further signatures will be included in an upcoming release.

How are McAfee / Intel Security Products Affected?

The McAfee PSIRT team is currently investigating the exposure of any McAfee products. Please check back here for guidance on updates and patches, if necessary.

What should users do?

Many Unix distributions have patches already available, and others will be available soon. Vulnerable systems should be patched as soon as possible, according to guidance from affected vendors/products.

The post What you need to know about the Bash Bug aka Shellshocked appeared first on McAfee.

SiteLock Doesn’t Do Basic Part of Proper Hack Cleanup

A few weeks ago we wrote about the web security company SiteLock failing to do a basic security check, checking to make sure software running on a website was up to date when labeling before labeling the website as secure. Based on that we weren’t surprised at our next interaction with their work.

A couple of days ago we were contacted by someone who looking for help after their website had been hacked and SiteLock had been hired to clean it up. After SiteLock had said that they had removed all the malware the owner of the website had requested their web host to bring the website back online. The web host told them that they couldn’t do that since they detected files for outdated software, Joomla 1.5.25, on the website (despite the website using Joomla 2.5). At that point we were contacted about finding and removing those files and in reply we told them they should go back to SiteLock since that should be something SiteLock should do for them. In response they let us know that SiteLock told them they “don’t have the capability to remove or update outdated CMS content”. That is rather troubling since getting the software running on a hacked website up to date is a basic part of a hack cleanup, as it is a basic part of making a website secure. In this type of situation, where a proper hack cleanup hasn’t been done we would only get involved if we are going to do a full cleanup, since we don’t want to be involved in leaving a website insecure, so we suggested that since they were only interested in having the Joomla 1.5.25 files removed they could probably find someone else to do it for less than having a full cleanup done.

The idea that a company is cleaning up hacked websites without doing such basic part of the work is pretty troubling, so we wanted to double check that it wasn’t just that they were refusing to remove some out of date files and instead that they don’t actually update the software running on the website when doing a cleanup. Since the website is running Joomla it is easy to check if the website is up to date with our Joomla Version Check extension for Chrome. After the website came back online we checked and found that website was running an outdated version:

Joomla version 2.5.22

That confirms that SiteLock isn’t doing some of the basic work of the hack cleanup, which is pretty good reason to not to use them for that or any other service they provide since they don’t appear to actually be interested in properly securing websites.

Using ASAN as a protection

AddressSanitizer, or ASAN, is an excellent tool for detecting subtle memory errors at runtime in C / C++ programs. It is now a productionized option in both the clang and gcc compilers, and has assisted in uncovering literally thousands of security bugs.

ASAN works by instrumenting compiled code with careful detections for runtime errors. It is primarily a detection tool. But what if we attempted to use is as a tool for protection?

The case for using ASAN-compiled software as a protection is an interesting one. Some of the most severe vulnerabilities are memory corruptions used to completely compromise a victim's machine. This is particularly the case for a web browser. If an ASAN-compiled build can help defend against these bugs, perhaps it has value to some users? An ASAN build is slower enough that no production software is likely to ship compiled with ASAN. But the slow down is not so bad that a particularly paranoid user wouldn't be able to easily accept it on a fast machine.

With that trade-off in mind, let's explore: does ASAN actually provide protection? To answer that, let's break memory corruption down into common vulnerability classes:

1. Linear buffer overflow (heap, stack, BSS, etc.)
A linear buffer overflow is one where every byte past the end of a buffer is written in sequence, up to some end point (example). For example, a memcpy() or strcpy() based overflow is linear. Because of the way ASAN works, I believe it will always catch a linear buffer overflow. It uses a default "redzone" of at least 16 bytes, i.e. touching _any_ address within 16 bytes of a valid buffer will halt the program with an error. Under ASAN, a linear buffer overflow condition will always hit the redzone.
This is great news because linear buffer overflows are one of the more common types of security bugs, and they are quite serious, affording the attacker a lot of control in corrupting program state.

2. Non-linear buffer overflow
A non-linear buffer overflow is one where data is written at some specific (but often attacker-controlled) out-of-bounds offset relative to a buffer (example). These bugs can be extremely powerful. Unfortunately, because of their power, they are both favored by attackers and also not stopped by ASAN if the attacker knows they are targeting an ASAN build. Example C program:

int main()
{
  char* p = malloc(16);
  char* p2 = malloc(16);
  printf("p, p2: %p, %pn", p, p2);
  p2[31] = '';
}

Compile it with ASAN (clang -fsanitize=address) and then run it and no error will be detected. The bad dereference "jumps over" the redzone to corrupt p2 via pointer p.

3. Use-after-free / double-free
ASAN does detect use-after-frees very reliably in the conditions that matter for current use cases: normal usage, and under fuzzing. However, if the attacker is specifically targeting an exploit against an ASAN build, they can pull tricks to still attempt the exploit. By churning the memory allocator hard (as is trivially possible with JavaScript), the condition can be hidden. Example C program:

int main()
{
   int n = 257 * 1024 * 1024;
   char* p2;
   char* p = malloc(1024);
   printf("p: %pn", p);
   free(p);
   while (n) {
     p2 = malloc(1024);
     if (p2 == p) printf("reused!!n");
     free(p2);
     n -= 1024;
   }
   n = 30 * 1024 * 1024;
   while (n) {
     p2 = malloc(1024);
     if (p2 == p) printf("reused!!n");
     n -= 1024;
   }
   p[0] = 'A';
}

The bad reference is not trapped with default ASAN values. The default values can be changed such that the bad reference is trapped:

ASAN_OPTIONS=quarantine_size=4294967295 ./a.out

It's a shame that setting this value to "unlimited" may not be possible due to a probable integer truncation in parameter parsing, see how this behaves differently:

ASAN_OPTIONS=quarantine_size=4294967296 ./a.out

4. Uninitialized value
Uninitialized values are harder to categorize. The impact varies drastically depending on where the uninitialized value is a pointer or an integer. For example, for an uninitialized pointer, effects similar to "non-linear buffer overflow" might even apply. Or if the uninitialized value is a copy length then perhaps it's more similar to "linear buffer overflow".
Or, if it's an uninitialized raw function pointer, that's a bigger problem. Indirect jumps are not checked. The behavior of the following ASAN-compiled program is instructive (run it in the debugger):

void subfunc1()
{
  unsigned long long blah = 0x0000414141414141ull;
}

void subfunc2()
{
  int (*funcptr)(void);
  funcptr();
}

int main()
{
  subfunc1();
  subfunc2();
}

If the uninitialized value is a pointer to a C++ class then similar (indirect) problems apply.

5. Bad cast
The effects of a bad cast are fairly varied! Perhaps the bad cast involves mistakenly using an integer value as a pointer. In this instance, effects similar to "non-linear buffer overflow" might be achievable. Or perhaps if a pointer for a C++ object is expected, but it is mistaken with a pointer to a raw buffer, then a bad vtable gets used, leading to program flow subversion. One final C++ example to illustrate this. Run under ASAN to observe a raw crash trying to read a vtable entry from 0x0000414141414141:

class A
{
public:
  long long val;
};

class B
{
public:
  virtual void vfunc() {};
};

int main()
{
  class A a;
  a.val = 0x0000414141414141ull;
  class B* pb = (class B*) &a;
  pb->vfunc();
}


Safer ASAN?
There's certainly scope for a safer variant of ASAN, specifically designed to provide safety rather than detection. It would be based on various changes:

  • Change the dereference check from "is this dereference address ok?" to "is this address in bounds for this specific pointer?". This takes care of the nasty "non-linear buffer overflow" as well as some of the worst effects of bad casts. This is not an easy change.
  • Initialize more variables: pointer values on the stack and heap. (This is not as easy as it sounds, particularly for the heap case, where the casting operator may become a point of action.)
  • Make the quarantine size for use-after-free unlimited. This burns a lot of memory, of course, but may be acceptable if fully unused pages are returned to the system with madvise() or even a crazy remap_file_pages() trick.


Remaining risks

Of course, even a "safer ASAN" build would not be bullet-proof. Taking the specific case of an safer-ASAN compiled Chromium, there would still be additional attacks possible:

  • Plug-ins. Many plug-ins are closed source and therefore cannot be replaced with ASANified versions. The safer build of Chromium would have plug-ins disabled: --disable-plugins or even at compile time.
  • Native attack surfaces called by the browser. For example, what happens when the browser encounters a web font. It'll probably get passed to a system library which parses this dangerous format using native code. In extreme cases, such as older Chromium on Windows, fonts were parsed in the kernel(!). --disable-remote-fonts, probably other flags.
  • Native attack surfaces triggerable by the browser. Less obviously, there can be operating system mechanisms that kick in simply because a file is downloaded or appears on disk. Anti-virus is notoriously buggy in this regard.
  • The v8 JIT engine. Any logic error in the JIT engine resulting in the emission of bad opcode sequences, or sequences with buggy bounds checks, are pretty toxic.
  • Pure logic vulnerabilities. UXSS vulnerabilities will remain unmitigated. In extremely rare but spectacular cases, unsandboxed code execute has been achieved without the need for memory corruption at all.

That all said, a stock ASAN build -- and even more so a hypothetical safer-ASAN build -- provide significant mitigation potential against memory corruption vulnerabilities. One measure of how strong a mitigation is, is whether is totally closes the door on a subset of bug classes or bugs. Even for the stock ASAN case, it appears that it does (linear buffer overflows for a start).

There is certainly more room for exploration in this space.

Using ASAN as a protection

AddressSanitizer, or ASAN, is an excellent tool for detecting subtle memory errors at runtime in C / C++ programs. It is now a productionized option in both the clang and gcc compilers, and has assisted in uncovering literally thousands of security bugs.

ASAN works by instrumenting compiled code with careful detections for runtime errors. It is primarily a detection tool. But what if we attempted to use is as a tool for protection?

The case for using ASAN-compiled software as a protection is an interesting one. Some of the most severe vulnerabilities are memory corruptions used to completely compromise a victim's machine. This is particularly the case for a web browser. If an ASAN-compiled build can help defend against these bugs, perhaps it has value to some users? An ASAN build is slower enough that no production software is likely to ship compiled with ASAN. But the slow down is not so bad that a particularly paranoid user wouldn't be able to easily accept it on a fast machine.

With that trade-off in mind, let's explore: does ASAN actually provide protection? To answer that, let's break memory corruption down into common vulnerability classes:

1. Linear buffer overflow (heap, stack, BSS, etc.)
A linear buffer overflow is one where every byte past the end of a buffer is written in sequence, up to some end point (example). For example, a memcpy() or strcpy() based overflow is linear. Because of the way ASAN works, I believe it will always catch a linear buffer overflow. It uses a default "redzone" of at least 16 bytes, i.e. touching _any_ address within 16 bytes of a valid buffer will halt the program with an error. Under ASAN, a linear buffer overflow condition will always hit the redzone.
This is great news because linear buffer overflows are one of the more common types of security bugs, and they are quite serious, affording the attacker a lot of control in corrupting program state.

2. Non-linear buffer overflow
A non-linear buffer overflow is one where data is written at some specific (but often attacker-controlled) out-of-bounds offset relative to a buffer (example). These bugs can be extremely powerful. Unfortunately, because of their power, they are both favored by attackers and also not stopped by ASAN if the attacker knows they are targeting an ASAN build. Example C program:

int main()
{
  char* p = malloc(16);
  char* p2 = malloc(16);
  printf("p, p2: %p, %pn", p, p2);
  p2[31] = '';
}

Compile it with ASAN (clang -fsanitize=address) and then run it and no error will be detected. The bad dereference "jumps over" the redzone to corrupt p2 via pointer p.

3. Use-after-free / double-free
ASAN does detect use-after-frees very reliably in the conditions that matter for current use cases: normal usage, and under fuzzing. However, if the attacker is specifically targeting an exploit against an ASAN build, they can pull tricks to still attempt the exploit. By churning the memory allocator hard (as is trivially possible with JavaScript), the condition can be hidden. Example C program:

int main()
{
   int n = 257 * 1024 * 1024;
   char* p2;
   char* p = malloc(1024);
   printf("p: %pn", p);
   free(p);
   while (n) {
     p2 = malloc(1024);
     if (p2 == p) printf("reused!!n");
     free(p2);
     n -= 1024;
   }
   n = 30 * 1024 * 1024;
   while (n) {
     p2 = malloc(1024);
     if (p2 == p) printf("reused!!n");
     n -= 1024;
   }
   p[0] = 'A';
}

The bad reference is not trapped with default ASAN values. The default values can be changed such that the bad reference is trapped:

ASAN_OPTIONS=quarantine_size=4294967295 ./a.out

It's a shame that setting this value to "unlimited" may not be possible due to a probable integer truncation in parameter parsing, see how this behaves differently:

ASAN_OPTIONS=quarantine_size=4294967296 ./a.out

4. Uninitialized value
Uninitialized values are harder to categorize. The impact varies drastically depending on where the uninitialized value is a pointer or an integer. For example, for an uninitialized pointer, effects similar to "non-linear buffer overflow" might even apply. Or if the uninitialized value is a copy length then perhaps it's more similar to "linear buffer overflow".
Or, if it's an uninitialized raw function pointer, that's a bigger problem. Indirect jumps are not checked. The behavior of the following ASAN-compiled program is instructive (run it in the debugger):

void subfunc1()
{
  unsigned long long blah = 0x0000414141414141ull;
}

void subfunc2()
{
  int (*funcptr)(void);
  funcptr();
}

int main()
{
  subfunc1();
  subfunc2();
}

If the uninitialized value is a pointer to a C++ class then similar (indirect) problems apply.

5. Bad cast
The effects of a bad cast are fairly varied! Perhaps the bad cast involves mistakenly using an integer value as a pointer. In this instance, effects similar to "non-linear buffer overflow" might be achievable. Or perhaps if a pointer for a C++ object is expected, but it is mistaken with a pointer to a raw buffer, then a bad vtable gets used, leading to program flow subversion. One final C++ example to illustrate this. Run under ASAN to observe a raw crash trying to read a vtable entry from 0x0000414141414141:

class A
{
public:
  long long val;
};

class B
{
public:
  virtual void vfunc() {};
};

int main()
{
  class A a;
  a.val = 0x0000414141414141ull;
  class B* pb = (class B*) &a;
  pb->vfunc();
}


Safer ASAN?
There's certainly scope for a safer variant of ASAN, specifically designed to provide safety rather than detection. It would be based on various changes:

  • Change the dereference check from "is this dereference address ok?" to "is this address in bounds for this specific pointer?". This takes care of the nasty "non-linear buffer overflow" as well as some of the worst effects of bad casts. This is not an easy change.
  • Initialize more variables: pointer values on the stack and heap. (This is not as easy as it sounds, particularly for the heap case, where the casting operator may become a point of action.)
  • Make the quarantine size for use-after-free unlimited. This burns a lot of memory, of course, but may be acceptable if fully unused pages are returned to the system with madvise() or even a crazy remap_file_pages() trick.


Remaining risks

Of course, even a "safer ASAN" build would not be bullet-proof. Taking the specific case of an safer-ASAN compiled Chromium, there would still be additional attacks possible:

  • Plug-ins. Many plug-ins are closed source and therefore cannot be replaced with ASANified versions. The safer build of Chromium would have plug-ins disabled: --disable-plugins or even at compile time.
  • Native attack surfaces called by the browser. For example, what happens when the browser encounters a web font. It'll probably get passed to a system library which parses this dangerous format using native code. In extreme cases, such as older Chromium on Windows, fonts were parsed in the kernel(!). --disable-remote-fonts, probably other flags.
  • Native attack surfaces triggerable by the browser. Less obviously, there can be operating system mechanisms that kick in simply because a file is downloaded or appears on disk. Anti-virus is notoriously buggy in this regard.
  • The v8 JIT engine. Any logic error in the JIT engine resulting in the emission of bad opcode sequences, or sequences with buggy bounds checks, are pretty toxic.
  • Pure logic vulnerabilities. UXSS vulnerabilities will remain unmitigated. In extremely rare but spectacular cases, unsandboxed code execute has been achieved without the need for memory corruption at all.

That all said, a stock ASAN build -- and even more so a hypothetical safer-ASAN build -- provide significant mitigation potential against memory corruption vulnerabilities. One measure of how strong a mitigation is, is whether is totally closes the door on a subset of bug classes or bugs. Even for the stock ASAN case, it appears that it does (linear buffer overflows for a start).

There is certainly more room for exploration in this space.