Penetration Test Report (Cure53): pentest report pcre

Pentest-Report PCRE2 09.-10.2015
Cure53, Dr.-Ing. Mario Heiderich, Jann Horn, Mike Wege
Index
Introduction
Scope
Identified Vulnerabilities
PCRE -01-003 Mutex Allocation in allocator _ grab _ lock () is racy ( Medium )
PCRE -01-005 Buffer Overflow on Stack during Length Estimation Pass ( Critica l)
PCRE -01-008 Buffer Overflow when Handling large Offsets in regerror () ( Medium )
PCRE -01-009 Incorrec t Replacemen t Length Handling in pcre 2_ substitute () ( Low )
PCRE -01-010 pcre 2_ substitute () has quadratic Runtime in UTF Mode ( Low )
PCRE -01-012 Unini t Stack Read in pcre 2_ substitute () ( Medium )
PCRE -01-013 Ou t - o f - bounds Read behind replacemen t in pcre 2_ substitute () ( Low )
PCRE -01-015 Unsafe ou t - o f - bounds Pointer UTF - tested in pcre 2_ match () ( Medium )
PCRE -01-017 2 nd find _ fixedlength Resul t no t stored as re -> max _ lookbehind ( Low )
PCRE -01-018 Problematic Truncation o f max _ lookbehind ( Low )
PCRE -01-023 Match Star t after End causes pcre 2_ substitute to repea t Inpu t ( Low )
PCRE -01-024 Simultaneous Freeing o f unserialized Patterns is racy ( Medium )
PCRE -01-025 Invalid UTF in Substitution Outpu t through in t Overflow ( Low )
PCRE -01-026 Exponentia l Pattern Compilation Time using Subroutine Calls ( Low )
PCRE -01-028 Cal l to open _ dev _ zero () is racy ( Low )
Miscellaneous Issues
PCRE -01-001 Outdated Comments in pcre 2_ compile () ( Info )
PCRE -01-002 Brittle Buffer Overflow Check in scan _ for _ captures () ( Low )
PCRE -01-004 Lower bound in find _ minlength () can be too high ( Low )
PCRE -01-006 Configuration o f 16/32 bi t EBCDIC is no t prevented ( Info )
PCRE -01-007 Inconsisten t Error Handling in regerror () ( Low )
PCRE -01-011 Return Value o f pcre 2_ substitute () is ambiguous ( Low )
PCRE -01-014 Dead Code causes use o f wrong memct l in pcre 2_ match () ( Low )
PCRE -01-016 Ou t - o f - bounds Pointer in non - UTF OP _ REVERSE Handling ( Low )
PCRE -01-019 Hardening : Abor t on Memory Safety Error ( Low )
PCRE -01-020 Missing NULL check in regcomp () ( Low )
PCRE -01-021 Unsafe Pointer Subtraction in DFA OP _ REVERSE Matching ( Low )
PCRE -01-022 Empty substitution match before CRLF handled weirdly ( Info )
PCRE -01-027 Runtime Complexity Increase through globa l Substitution ( Low )
PCRE -01-029 Potentia l ou t - o f - bounds array read in regcomp () ( Low )
Conclusion
1/31
Introduction
“The PCRE library is a set of functions that implement regular expression pattern
matching using the same syntax and semantics as Perl 5. PCRE has its own native API,
as well as a set of wrapper functions that correspond to the POSIX regular expression
API. The PCRE library is free, even for building proprietary software.
PCRE was originally written for the Exim MTA, but is now used by many high-profile
open source projects, including Apache, PHP, KDE, Postfix, Analog, and Nmap. PCRE
has also found its way into some well known commercial products, like Apple Safari.
Some other interesting projects using PCRE include Chicken, Ferite, Onyx, Hypermail,
Leafnode, Askemos, Wenlin, and 8th.”
From http :/ / www . pcre . org /
The source code audit against the PCRE2 library was carried out by two testers and one
test-lead from the Cure53 team throughout September and October 2015. The project
was initiated by Open Technology Fund1 and the Mozilla Foundation2, pioneering a new
open source security grant scheme called SOS.
The audit took twenty days to complete and yielded an overall of 29 issues. Only one of
the results was considered to be of a critical severity, while the remaining majority of
other problems oscillated around moderate and low severity levels. This strongly
indicates that the library's code is of good quality and the application’s level of maturity is
rather high. However note that the audit was performed manually and did not involve any
fuzzing or other automated tool-assisted techniques.
This report describes and discusses the security issues identified during the source code
audit and delivers fix recommendations. In addition, the documentation provides other
insights into why a given issue should be considered a security problem and how an
attacker might be able to abuse it. Finally the report closes with conclusions, further
addressing some more general findings, like the patterns of the spotted vulnerability and
thoughts on the coding practices.
Scope
• PCRE2 Sources
◦ http :/ / vcs . pcre . org / pcre 2 / code / trunk /
◦ Note that the file pcre2_serialize.c (serialization of compiled patterns) as well as all
tests and any example code are considered out-of-scope for this assignment. All
maintenance and command line tools, especially pcre2grep.c, were also excluded
from the audit.
1 https :// www . opentech . fund /
2 https :// www . mozilla . org / en - US / foundation /
2/31
Identified Vulnerabilities
The following sections list both vulnerabilities and implementation issues spotted during
the testing period. Note that findings are listed in a chronological order rather than by
their degree of severity and impact. The aforementioned severity rank is simply given in
brackets following the title heading for each vulnerability. Each vulnerability is
additionally given a unique identifier (e.g. PCRE-01-001) for the purpose of facilitating
any future follow-up correspondence.
PCRE-01-003 Mutex Allocation in allocator_grab_lock() is racy (Medium)
The multithreaded version of allocator_grab_lock() for Windows in sljit/sljitUtils.c
uses a mutex to prevent concurrent access to the allocator (please note it also applies to
sljit_grab_lock(), which this is not in use at this point). This mutex is initialized on
the first use of allocator_grab_lock() but this initialization is not appropriately
protected against a concurrent execution:
static HANDLE allocator_mutex = 0;
static SLJIT_INLINE void allocator_grab_lock(void)
{
[...]
if (!allocator_mutex)
allocator_mutex = CreateMutex(NULL, TRUE, NULL);
else
WaitForSingleObject(allocator_mutex, INFINITE);
}
If allocator_grab_lock() has not been called yet and two threads call it at the same
time, it is possible for both threads to take the first branch since allocator_mutex is still 0.
Both threads will create locked mutexes and access the allocator under different
mutexes, making races in the allocator possible.
It is recommended to perform initialization of the allocator_mutex with a function that is
executed through InitOnceExecuteOnce() to prevent races. This can be done as
follows:
static HANDLE allocator_mutex = 0;
INIT_ONCE allocator_mutex_init = INIT_ONCE_STATIC_INIT;
static BOOL allocator_init_lock(PINIT_ONCE io, PVOID param, PVOID *context)
{
allocator_mutex = CreateMutex(NULL, FALSE, NULL);
return TRUE;
}
static SLJIT_INLINE void allocator_grab_lock(void)
{
if (!allocator_mutex)
3/31
if (InitOnceExecuteOnce(&allocator_mutex_init,
allocator_init_lock,
NULL, NULL) == 0)
/* fatal error, cancel program execution somehow */;
WaitForSingleObject(allocator_mutex, INFINITE);
}
Note that InitOnceExecuteOnce() is only available from Windows Vista version
onwards. If compatibility with Windows XP is required, it is necessary to either add a
library initialization function, which would have to be called by the surrounding program,
to PCRE. Alternatively, the threads would have to be synchronized in some other way
(e.g. with a spinlock implementation in the user-space employing the Interlocked API3,
which would be less desirable in terms of clarity and cleanliness of this approach).
PCRE-01-005 Buffer Overflow on Stack during Length Estimation Pass (Critical)
When a pattern is compiled using pcre2_compile(), the function compile_regex()
(responsible for translating the pattern text into bytecode) is called twice. First call
instance occurs to determine the required output buffer size, while the second one is
aimed at writing into an output buffer with the correct size. Because compile_branch()
(called by compile_regex()) reads some of the inf