[New-bugs-announce] [issue24602] SRE_SEARCH Integer Underflow

JohnLeitch report at bugs.python.org
Fri Jul 10 05:12:53 CEST 2015


New submission from JohnLeitch:

The Python 2.7 regular expression module suffers from an integer underflow in the SRE_SEARCH function of _sre.c, which leads to a buffer over-read condition. The issue is caused by unchecked subtraction performed while handling SR_OP_INFO blocks:

    if (pattern[0] == SRE_OP_INFO) {
        /* optimization info block */
        /* <INFO> <1=skip> <2=flags> <3=min> <4=max> <5=prefix info>  */

        flags = pattern[2];

        if (pattern[3] > 1) {
            /* adjust end point (but make sure we leave at least one
               character in there, so literal search will work) */
            end -= pattern[3]-1; <<<< Pattern[3] is a potentially untrusted value
                                      controllable via regex.
            if (end <= ptr) <<<< A check is performed end is less than or equal to
                                 ptr (which is still start at this point), but no
                                 check is performed to determine if end has been
                                 underflowed to a value greater than ptr.
                end = ptr+1;
        }

        [...]
    }

A script that demonstrates control of Pattern[3] is as follows:

import re
re.search(r"\b((A){304665458})",u"A")

When the script is executed, the min quantifier value ends up in pattern[3] of an SRE_OP_INFO block. The value underflows end, resulting in a large number that satisfies the existing validation. In cases where the regular expression is exposed as attack surface, it may be possible to exploit this vulnerability to scan and read arbitrary memory. This could then potentially be used to disclose secrets and/or bypass mitigations such as ASLR/DEP.

An exception produced by this condition is as follows:

0:000> !analyze -v -nodb
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************


FAULTING_IP: 
python27!sre_uat+b7 [c:\build27\cpython\modules\_sre.c @ 369]
1e010dd7 0fb746fe        movzx   eax,word ptr [esi-2]

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 1e010dd7 (python27!sre_uat+0x000000b7)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 01e0f000
Attempt to read from address 01e0f000

CONTEXT:  00000000 -- (.cxr 0x0;r)
eax=01d38518 ebx=0027f8b0 ecx=0027f8b0 edx=01d23eb4 esi=01e0f002 edi=01d3851a
eip=1e010dd7 esp=0027f82c ebp=01f2b010 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010212
python27!sre_uat+0xb7:
1e010dd7 0fb746fe        movzx   eax,word ptr [esi-2]     ds:002b:01e0f000=????

FAULTING_THREAD:  00000518

DEFAULT_BUCKET_ID:  INVALID_POINTER_READ

PROCESS_NAME:  python.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_PARAMETER1:  00000000

EXCEPTION_PARAMETER2:  01e0f000

READ_ADDRESS:  01e0f000 

FOLLOWUP_IP: 
python27!sre_uat+b7 [c:\build27\cpython\modules\_sre.c @ 369]
1e010dd7 0fb746fe        movzx   eax,word ptr [esi-2]

NTGLOBALFLAG:  70

APPLICATION_VERIFIER_FLAGS:  0

APP:  python.exe

ANALYSIS_VERSION: 6.3.9600.17029 (debuggers(dbg).140219-1702) x86fre

PRIMARY_PROBLEM_CLASS:  INVALID_POINTER_READ

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_READ

LAST_CONTROL_TRANSFER:  from 1e0115e8 to 1e010dd7

STACK_TEXT:  
0027f834 1e0115e8 01d23eb4 0027f8b0 01e0f004 python27!sre_uat+0xb7
0027f85c 1e012882 01d23e78 01ddb9f0 00000000 python27!sre_umatch+0x178
0027f888 1e014995 01d23eb4 1e0148b0 01f3ea08 python27!sre_usearch+0x212
0027fc08 1e0aafeb 01d23e78 01ddb9f0 00000000 python27!pattern_search+0xe5
0027fc24 1e0edd10 01f3ea08 01ddb9f0 00000000 python27!PyCFunction_Call+0x5b
0027fc50 1e0f017a 0027fca8 01d9df98 00000001 python27!call_function+0x2b0
0027fcc0 1e0f1150 01f49198 00000000 01dce030 python27!PyEval_EvalFrameEx+0x239a
0027fcf4 1e0ec862 01d9df98 01f49198 00000000 python27!PyEval_EvalCodeEx+0x690
0027fd30 1e0edd87 0027fdb4 00000002 00000000 python27!fast_function+0xe2
0027fd5c 1e0f017a 0027fdb4 01d46b18 01d46b18 python27!call_function+0x327
0027fdcc 1e0f1150 01d74030 00000000 01d46b18 python27!PyEval_EvalFrameEx+0x239a
0027fe00 1e0f11b2 01d46b18 01d74030 01d4aa50 python27!PyEval_EvalCodeEx+0x690
0027fe2c 1e11707a 01d46b18 01d4aa50 01d4aa50 python27!PyEval_EvalCode+0x22
0027fe44 1e1181c5 01e0a3b0 01d4aa50 01d4aa50 python27!run_mod+0x2a
0027fe64 1e118760 68e87408 01f02e63 00000101 python27!PyRun_FileExFlags+0x75
0027fea4 1e1190d9 68e87408 01f02e63 00000001 python27!PyRun_SimpleFileExFlags+0x190
0027fec0 1e038d35 68e87408 01f02e63 00000001 python27!PyRun_AnyFileExFlags+0x59
0027ff3c 1d00116d 00000002 01f02e40 01f01928 python27!Py_Main+0x965
0027ff80 75847c04 7ffde000 75847be0 ba7d18ea python!__tmainCRTStartup+0x10f
0027ff94 77c9b90f 7ffde000 b83a1635 00000000 KERNEL32!BaseThreadInitThunk+0x24
0027ffdc 77c9b8da ffffffff 77c80707 00000000 ntdll!__RtlUserThreadStart+0x2f
0027ffec 00000000 1d001314 7ffde000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  .cxr 0x0 ; kb

FAULTING_SOURCE_LINE:  c:\build27\cpython\modules\_sre.c

FAULTING_SOURCE_FILE:  c:\build27\cpython\modules\_sre.c

FAULTING_SOURCE_LINE_NUMBER:  369

FAULTING_SOURCE_CODE:  
   365:     case SRE_AT_BOUNDARY:
   366:         if (state->beginning == state->end)
   367:             return 0;
   368:         thatp = ((void*) ptr > state->beginning) ?
>  369:             SRE_IS_WORD((int) ptr[-1]) : 0;
   370:         thisp = ((void*) ptr < state->end) ?
   371:             SRE_IS_WORD((int) ptr[0]) : 0;
   372:         return thisp != thatp;
   373: 
   374:     case SRE_AT_NON_BOUNDARY:


SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  python27!sre_uat+b7

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: python27

IMAGE_NAME:  python27.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  5488ac17

FAILURE_BUCKET_ID:  INVALID_POINTER_READ_c0000005_python27.dll!sre_uat

BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_READ_python27!sre_uat+b7

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:invalid_pointer_read_c0000005_python27.dll!sre_uat

FAILURE_ID_HASH:  {a7161322-9fae-40b8-8c7f-dd4ebe6d6b79}

Followup: MachineOwner
---------

To fix this issue, SRE_SEARCH should check end following the subtraction operation to ensure that the value has not underflowed. A proposed patch is attached.

----------
components: Regular Expressions
files: _sre.c.patch
keywords: patch
messages: 246540
nosy: JohnLeitch, ezio.melotti, mrabarnett
priority: normal
severity: normal
status: open
title: SRE_SEARCH Integer Underflow
type: security
versions: Python 2.7
Added file: http://bugs.python.org/file39887/_sre.c.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue24602>
_______________________________________


More information about the New-bugs-announce mailing list