php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #72959 timelib_meridian out-of-bounds access
Submitted: 2016-08-28 22:32 UTC Modified: 2018-01-02 18:19 UTC
From: fernando at null-life dot com Assigned: derick (profile)
Status: Closed Package: Date/time related
PHP Version: 5.6.25 OS: *
Private report: No CVE-ID: None
 [2016-08-28 22:32 UTC] fernando at null-life dot com
Description:
------------
Invalid date format causes out-of-bounds read at timelib_meridian through timelib strtotime. This code can also be reached through "wddx_deserialize" function.


Source code 
https://github.com/php/php-src/blob/master/ext/date/lib/parse_date.re#L381

static timelib_sll timelib_meridian(char **ptr, timelib_sll h)
{
    timelib_sll retval = 0;

    while (!strchr("AaPp", **ptr)) {
        ++*ptr;
    }
    if (**ptr == 'a' || **ptr == 'A') {
        if (h == 12) {
            retval = -12;
        }
    } else if (h != 12) {
        retval = 12;
    }
    ++*ptr;                                        // out of bounds
    if (**ptr == '.') {                            // read
        *ptr += 3;
    } else {
        ++*ptr;
    }
    return retval;
}


GDB output:

gdb -q --args /home/operac/build3/bin/php -n poc.php
No symbol table is loaded.  Use the "file" command.
Breakpoint 1 (__asan_report_error) pending.
Reading symbols from /home/operac/build3/bin/php...done.
gdb-peda$ b timelib_meridian
Breakpoint 2 at 0x42ea3d: file ext/date/lib/parse_date.re, line 517.
gdb-peda$ r
Starting program: /home/operac/build3/bin/php -n poc.php
...
Breakpoint 2, 0x000000000042ea3d in timelib_meridian (ptr=ptr@entry=0x7fffffff9d60, h=0x0) at ext/date/lib/parse_date.re:517
517     }
gdb-peda$ p ptr
$1 = (char **) 0x7fffffff9d60
gdb-peda$ p **ptr
$2 = 0x0                  // the function "timelib_meridian" tries to parser null string




Test script:
---------------
<?php

$xml = <<<XML
<dateTime>Dec 08:00AM 0</dateTime>
XML;

$array = wddx_deserialize($xml);

strtotime("Jan 12:00AM 0");

Expected result:
----------------
No crash

Actual result:
--------------
ASan output:

==12822==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000235d at pc 0x00000042ebbe bp 0x7ffc63de5370 sp 0x7ffc63de5360
READ of size 1 at 0x60200000235d thread T0
    #0 0x42ebbd in timelib_meridian ext/date/lib/parse_date.re:396
    #1 0x4d417d in scan ext/date/lib/parse_date.re:1658
    #2 0x4d417d in timelib_strtotime ext/date/lib/parse_date.re:1786
    #3 0x48fbd8 in php_parse_date /home/operac/php-src-56/php-src/ext/date/php_date.c:1433
    #4 0x15b09c2 in php_wddx_process_data /home/operac/php-src-56/php-src/ext/wddx/wddx.c:1143
    #5 0x7fdd077a778f in xmlParseCharData (/usr/lib/x86_64-linux-gnu/libxml2.so.2+0x4678f)
    #6 0x7fdd077b7cd6  (/usr/lib/x86_64-linux-gnu/libxml2.so.2+0x56cd6)
    #7 0x7fdd077b862a in xmlParseChunk (/usr/lib/x86_64-linux-gnu/libxml2.so.2+0x5762a)
    #8 0x15fb62a in php_XML_Parse /home/operac/php-src-56/php-src/ext/xml/compat.c:605
    #9 0x15d2b3a in php_wddx_deserialize_ex /home/operac/php-src-56/php-src/ext/wddx/wddx.c:1176
    #10 0x15d3d97 in zif_wddx_deserialize /home/operac/php-src-56/php-src/ext/wddx/wddx.c:1392
    #11 0x1d6bc67 in zend_do_fcall_common_helper_SPEC /home/operac/php-src-56/php-src/Zend/zend_vm_execute.h:558
    #12 0x1c1773c in execute_ex /home/operac/php-src-56/php-src/Zend/zend_vm_execute.h:363
    #13 0x195afda in zend_execute_scripts /home/operac/php-src-56/php-src/Zend/zend.c:1341
    #14 0x16a889f in php_execute_script /home/operac/php-src-56/php-src/main/main.c:2613
    #15 0x1d749ef in do_cli /home/operac/php-src-56/php-src/sapi/cli/php_cli.c:994
    #16 0x4551b0 in main /home/operac/php-src-56/php-src/sapi/cli/php_cli.c:1378
    #17 0x7fdd06a4a82f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #18 0x455838 in _start (/home/operac/build3/bin/php+0x455838)

0x60200000235d is located 0 bytes to the right of 13-byte region [0x602000002350,0x60200000235d)
allocated by thread T0 here:
    #0 0x7fdd0901479a in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9879a)
    #1 0x4a24b5 in timelib_string ext/date/lib/parse_date.re:442
    #2 0x4d3cff in scan ext/date/lib/parse_date.re:1642
    #3 0x4d3cff in timelib_strtotime ext/date/lib/parse_date.re:1786
    #4 0x48fbd8 in php_parse_date /home/operac/php-src-56/php-src/ext/date/php_date.c:1433
    #5 0x15b09c2 in php_wddx_process_data /home/operac/php-src-56/php-src/ext/wddx/wddx.c:1143
    #6 0x7fdd077a778f in xmlParseCharData (/usr/lib/x86_64-linux-gnu/libxml2.so.2+0x4678f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ext/date/lib/parse_date.re:396 timelib_meridian

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-06 00:55 UTC] stas@php.net
-Assigned To: +Assigned To: derick
 [2016-09-06 00:55 UTC] stas@php.net
Looks like there's a deeper issue hiding here: 

When parsing Dec 08:00AM 0 it is interpreted as Dec being month and 08 being day, which makes 00 hour, and AM has disappeared when trying to get minute, so timelib_meridian never sees it. So looks like such string should be rejected, but it is not rejected. 

Derick, could you take a look? I can fix the read-past-end issue, but I feel like the real fix should be in other place.
 [2018-01-02 04:59 UTC] stas@php.net
-Status: Assigned +Status: Feedback
 [2018-01-02 04:59 UTC] stas@php.net
Doesn't seem to happen for me with recent code, is it still reproducible?
 [2018-01-02 18:16 UTC] stas@php.net
-Status: Feedback +Status: Closed
 [2018-01-02 18:19 UTC] stas@php.net
I see however that the patch was merged only into PHP 7. Since we still have security support for 5.6, could we also merge it into 5.6?
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Sun Sep 23 06:01:25 2018 UTC