ericmckean / google-security-research

Automatically exported from code.google.com/p/google-security-research
0 stars 0 forks source link

Flash PCRE pcre_compile character class/ims options heap overflow #208

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
An issue exists in the handling of special regex character sets containing the 
\r or \n characters in conjunction with regex options, which can result in an 
exploitable heap overflow condition.

An example regex to trigger this issue is the following:

[\D](?i)||

During precompilation, when we compute the space required for the compiled 
regex, we skip some computation during compilation of the character class [\D] 
(inside compile_branch) 

(pcre_compile.cpp:3112)

/* Save time by not doing this in the pre-compile phase. */

if (lengthptr == NULL) switch (-c)
  {
  case ESC_d:
  for (c = 0; c < 32; c++) classbits[c] |= cbits[c+cbit_digit];
  continue;

  case ESC_D:
  for (c = 0; c < 32; c++) classbits[c] |= ~cbits[c+cbit_digit];
  inverted_class = TRUE;
  continue;

  … 
  }

/* In the pre-compile phase, just do the recognition. */

else if (c == -ESC_d || c == -ESC_D || c == -ESC_w ||
         c == -ESC_W || c == -ESC_s || c == -ESC_S) continue;

However, later in the same function we use the results of this computation: to 
set an external options flag, depending on whether this class can contain the 
\r or \n characters. 

(pcre/pcre_compile.cpp:3555)

/* Remember whether \r or \n are in this class */

if (negate_class)
  {
  if ((classbits[1] & 0x24) != 0x24) cd->external_options |= PCRE_HASCRORLF;
  }
else
  {
  if ((classbits[1] & 0x24) != 0) cd->external_options |= PCRE_HASCRORLF;
  }

This means that during precompilation, cd->external_options is not set to 
include the PCRE_HASCRORLF flag, but during the actual compilation of the 
regex, it is.

In compile_regex, the following code is used to emit an OP_OPT for each branch 
where it is required. 

(beautified extract from pcre_compile.cpp)

if ((options & PCRE_IMS) != oldims)
{
    oldims = options & PCRE_IMS;
    *code++ = OP_OPT;
    *code++ = oldims;
    length += 2;
}
…
if (!compile_branch(&options, … ))
{
… 
}

if (old_external_options != cd->external_options)
    oldims = cd->external_options & PCRE_IMS;

During the first pass, we will not enter the old_external_options case, since 
cd->external_options has not been changed. 

However during the second pass, we enter this case and set only the PCRE_IMS 
options - overwriting the updated PCRE_IMS options with the previous options. 
This doesn’t update the PCRE_HASCRORLF component that is causing us to decide 
that the options have changed, so for every following branch we will need to 
emit the OP_OPT and options constant during the first condition to fix the 
PCRE_IMS options; and so for the regex provided we will emit two bytes more 
than the original, computed length, overflowing into the following heap buffer.

Changing the check: 

if ((old_external_options & PCRE_IMS) != (cd->external_options & PCRE_IMS))
    oldims = cd->external_options & PCRE_IMS;

seems like a reasonable fix and will prevent the overflow from occurring. A 
patch is provided (bug.patch) against the github avmplus source code to apply 
this fix.

However, this will still leave a case where different external_options set 
during the first and second passes, which may result in other similar issues. 
It may additionally be necessary to always perform the full character class 
computation during the precompilation step to ensure that the options are 
consistent between both passes.

See attached for a .swf demonstrating the issue that has been verified to crash 
the latest Flash release.

Also attached is another patch which changes the behaviour on detection of an 
overflow during regex compilation to abort instead of returning an errorcode to 
Flash, making exploitation of issues similar to this significantly harder.

This bug was found using AFL, written by lcamtuf.

This bug is subject to a 90 day disclosure deadline. If 90 days elapse
without a broadly available patch, then the bug report will automatically
become visible to the public.

Original issue reported on code.google.com by markbr...@google.com on 3 Dec 2014 at 8:32

Attachments:

GoogleCodeExporter commented 9 years ago
Adobe tracking as PSIRT-3169.

Original comment by cev...@google.com on 4 Dec 2014 at 4:05

GoogleCodeExporter commented 9 years ago
Mark noted that the regex to trigger this new bug bears a certain similarity to 
the regex bug that turned up as an 0-day.

(Details of that 0-day are covered in the paper 
http://0xfeedface.org/sites/default/files/smashing_the_heap_with_vector_Li.pdf)

Original comment by cev...@google.com on 4 Dec 2014 at 4:12

GoogleCodeExporter commented 9 years ago
cc:ing Yang Dingning, who filed a duplicate issue as 
https://code.google.com/p/chromium/issues/detail?id=440205

Original comment by cev...@google.com on 11 Dec 2014 at 9:28

GoogleCodeExporter commented 9 years ago
Supplied another crash poc to adobe.

Original comment by markbr...@google.com on 18 Dec 2014 at 5:31

Attachments:

GoogleCodeExporter commented 9 years ago

Original comment by cev...@google.com on 4 Feb 2015 at 7:06

GoogleCodeExporter commented 9 years ago
https://helpx.adobe.com/security/products/flash-player/apsb15-04.html

Original comment by cev...@google.com on 6 Feb 2015 at 3:14

GoogleCodeExporter commented 9 years ago

Original comment by cev...@google.com on 12 Feb 2015 at 8:11