php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Sec Bug #74103 heap-use-after-free when unserializing invalid array size
Submitted: 2017-02-15 19:06 UTC Modified: 2017-08-18 17:18 UTC
From: cyoung at tripwire dot com Assigned: nikic (profile)
Status: Closed Package: *Data Exchange functions
PHP Version: 7.1.2RC1 OS: Linux (4.4.0-59-generic)
Private report: No CVE-ID: 2017-12932
 [2017-02-15 19:06 UTC] cyoung at tripwire dot com
Description:
------------
Fuzzing var_dump(unserialize(<<data>>)) with various instrumentations and USE_ZEND_ALLOC=0 has revealed a possible security flaw in PHP.
From ASAN:
==14786==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000024855 at pc 0x0000015fad75 bp 0x7ffefa744310 sp 0x7ffefa744308
READ of size 1 at 0x603000024855 thread T0
    #0 0x15fad74 in zend_string_release /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_string.h:270:7
    #1 0x15fad74 in zend_array_destroy /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_hash.c:1312
    #2 0x1591132 in _zval_dtor_func /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_variables.c:43:5
    #3 0x1546489 in i_zval_ptr_dtor /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_variables.h:48:4
    #4 0x1546489 in _zval_ptr_dtor /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_execute_API.c:550
    #5 0x133d550 in var_destroy /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var_unserializer.re:233:4
    #6 0x133cd61 in php_var_unserialize_destroy /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var_unserializer.re:52:3
    #7 0x13016c4 in zif_unserialize /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var.c:1131:2
    #8 0x1831ce2 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_vm_execute.h:675:2
    #9 0x16eeff5 in execute_ex /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_vm_execute.h:432:7
    #10 0x16efda6 in zend_execute /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_vm_execute.h:474:2
    #11 0x15519cd in zend_eval_stringl /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_execute_API.c:1093:4
    #12 0x1552343 in zend_eval_stringl_ex /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_execute_API.c:1134:11
    #13 0x1552343 in zend_eval_string_ex /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_execute_API.c:1145
    #14 0x193b0aa in do_cli /home/cyoung/php/afl/php-src-php-7.1.2RC1/sapi/cli/php_cli.c:1024:8
    #15 0x1938dd4 in main /home/cyoung/php/afl/php-src-php-7.1.2RC1/sapi/cli/php_cli.c:1381:18
    #16 0x7ff566fd682f in __libc_start_main /build/glibc-t3gR2i/glibc-2.23/csu/../csu/libc-start.c:291
    #17 0x4809c8 in _start (/home/cyoung/php/afl/php-src-php-7.1.2RC1/sapi/cli/php+0x4809c8)

0x603000024855 is located 5 bytes inside of 32-byte region [0x603000024850,0x603000024870)
freed by thread T0 here:
    #0 0x5076b2 in free (/home/cyoung/php/afl/php-src-php-7.1.2RC1/sapi/cli/php+0x5076b2)
    #1 0x14af197 in _efree /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_alloc.c:2428:4

previously allocated by thread T0 here:
    #0 0x507992 in __interceptor_malloc (/home/cyoung/php/afl/php-src-php-7.1.2RC1/sapi/cli/php+0x507992)
    #1 0x14b03ca in __zend_malloc /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_alloc.c:2820:14
    #2 0x1342e0b in process_nested_data /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var_unserializer.re:396:8
    #3 0x1342e0b in php_var_unserialize_internal /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var_unserializer.re:822
    #4 0x133e3ba in php_var_unserialize /home/cyoung/php/afl/php-src-php-7.1.2RC1/ext/standard/var_unserializer.re:584:11
    #5 0x1831ce2 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_vm_execute.h:675:2

SUMMARY: AddressSanitizer: heap-use-after-free /home/cyoung/php/afl/php-src-php-7.1.2RC1/Zend/zend_string.h:270 zend_string_release
Shadow bytes around the buggy address:
  0x0c067fffc8b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fffc8c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fffc8d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c067fffc8e0: fa fa fa fa fa fa fa fa fa fa fa fa 00 00 02 fa
  0x0c067fffc8f0: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
=>0x0c067fffc900: fd fd fa fa fd fd fd fd fa fa[fd]fd fd fd fa fa
  0x0c067fffc910: fd fd fd fa fa fa 00 00 00 fa fa fa 00 00 00 00
  0x0c067fffc920: fa fa 00 00 00 fa fa fa 00 00 00 00 fa fa 00 00
  0x0c067fffc930: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa
  0x0c067fffc940: 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00 00 fa
  0x0c067fffc950: fa fa 00 00 00 fa fa fa 00 00 00 fa fa fa 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==14786==ABORTING

From a partially MSAN instrumented PHP CLI:
==14802==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x5636d9634089 in zend_array_destroy (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x20b3089)
    #1 0x5636d94f43d4 in _zval_dtor_func (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x1f733d4)
    #2 0x5636d94276db in _zval_ptr_dtor (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x1ea66db)
    #3 0x5636d8f7eeff in var_destroy (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x19fdeff)
    #4 0x5636d8f7d9a1 in php_var_unserialize_destroy (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x19fc9a1)
    #5 0x5636d8ec42b0 in zif_unserialize (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x19432b0)
    #6 0x5636d9d4b367 in ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x27ca367)
    #7 0x5636d98c4bbb in execute_ex (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x2343bbb)
    #8 0x5636d98c869e in zend_execute (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x234769e)
    #9 0x5636d9441c0e in zend_eval_stringl (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x1ec0c0e)
    #10 0x5636d9442718 in zend_eval_stringl_ex (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x1ec1718)
    #11 0x5636d94429a8 in zend_eval_string_ex (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x1ec19a8)
    #12 0x5636da1042e5 in do_cli (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x2b832e5)
    #13 0x5636da0fec9b in main (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x2b7dc9b)
    #14 0x7f4df5c0382f in __libc_start_main /build/glibc-t3gR2i/glibc-2.23/csu/../csu/libc-start.c:291
    #15 0x5636d7679658 in _start (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0xf8658)

SUMMARY: MemorySanitizer: use-of-uninitialized-value (/home/cyoung/php/MSAN/php-src-php-7.1.2RC1/sapi/cli/php+0x20b3089) in zend_array_destroy

Test script:
---------------
<?php
unserialize('a:7:{i:0;i:04;s:1:"a";i:2;i:00009617006;i:4;s:1:"a";i:4;s:1:"a";R:5;s:1:"7";R:3;s:1:"a";R:5;;s:18;}}');
?>


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-02-20 11:46 UTC] laruence@php.net
USE_ZEND_ALLOC=0 is usually used for debug purpose..
 [2017-02-20 15:22 UTC] cyoung at tripwire dot com
I understand that USE_ZEND_ALLOC=0 is intended for debugging.  I am using this option to disable the ZEND allocator so that I can instead use the instrumentation provided by ASAN which is able to catch memory safety issues that might not cause a crash otherwise.  It is my understanding that many of the security bugs found in PHP through fuzzing are identified with this option.  Hanno Böck notes it here: https://fuzzing-project.org/tutorial-tips.html 

There are also many other bug reports in PHP where this option is referenced.  As some examples from a Google search:
https://bugs.php.net/bug.php?id=71527
https://bugs.php.net/bug.php?id=72227
https://bugs.php.net/bug.php?id=72241
https://bugs.php.net/bug.php?id=73825
 [2017-07-02 20:39 UTC] stas@php.net
-Summary: heap-use-after-free zend_string.h:270 zend_string_release (READ of 1) +Summary: heap-use-after-free when unserializing invalid array size
 [2017-07-07 21:15 UTC] nikic@php.net
I believe this has been introduced by https://github.com/php/php-src/commit/fd545f4f44ff44bba9f75ae3f044dc2ba9c61083, which is a followup to https://github.com/php/php-src/commit/91fb1edbbffe106d02929fe554ecbd1e5e33f5d1. zend_hash_index_del in unserialize is a very bad idea :/
 [2017-08-12 11:43 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2017-08-14 13:16 UTC] cyoung at tripwire dot com
Can someone assign a CVE to this issue?
 [2017-08-18 11:11 UTC] henri at nerv dot fi
Please use CVE-2017-12932 for this issue.
 [2017-08-18 17:18 UTC] kaplan@php.net
-CVE-ID: +CVE-ID: 2017-12932
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 07:01:32 2024 UTC