PHP :: Bug #76143 :: Memory corruption: arbitrary NUL overwrite
php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76143 Memory corruption: arbitrary NUL overwrite
Submitted: 2018-03-23 15:34 UTC Modified: 2018-03-26 23:54 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: cpicard at openmailbox dot org Assigned: krakjoe (profile)
Status: Closed Package: phpdbg
PHP Version: 7.2.3 OS: Windows/Linux
Private report: No CVE-ID: None
 [2018-03-23 15:34 UTC] cpicard at openmailbox dot org
Description:
------------
The issue
=========

phpdbg suffers from a memory corruption allowing any one byte on the stack to be overwritten by a NUL byte.

The bug is in sapi/phpdbg/phpdbg_io.c:phpdbg_create_listenable_socket.

The following snippet is used multiple times in the function:

303   char buf[256];
304   int wrote;
305
306   wrote = snprintf(buf, 256, "Host '%s' not found. %s", addr, estrdup(gai_strerror(rc)));
307   buf[wrote] = '\0';
308   zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, buf, strlen(buf));

snprintf returns the number of bytes it would have written had there not been
any truncation, not the number of bytes actually written. Therefore if
passing more than 256 bytes the variable "wrote" will point outside the
buffer.

Line 307 will therefore write a NUL byte somewhere on the stack at a position
controlled by the attacker through the host name length.

The use of "strlen(buf)" next line prevents any other overwrite.

Possible exploitation
=====================

Hard.

The only path I found to this function is through the command line. This
reduces the exploitation possibilities drastically. Furthermore exploiting a
single stack NUL byte overwrite isn't easy, the best strategy would be to
change the stack pointer to point to a section of the stack that is
controlled by the attacker in order to gain arbitrary code execution by
guiding the program toward a stack function pointer call controlled by the
attacker. Nothing easy.

However, as history has shown, memory corruption bugs should never be
underestimated so I'll leave it to you to determine whether this fits PHP's
security model.

Correction
==========

Replacing line 307 with:

  buf[MIN(wrote, strlen(buf)] = '\0';

should do the trick.

Test script:
---------------
# This should segfault on a linux x86_64 system

phpdbg -l 8000 -a "$(perl -e 'print "A"x268')" 


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-03-26 12:07 UTC] cmb@php.net
Hmm, I wonder whether phpdbg is used in production environments –
otherwise this would not be a security issue.

Anyhow, manually writing the trailing NUL byte is not necessary at
all, since snprintf() is supposed to do that anyway.  Using
slprintf() instead, could spare the strlen() call, though.

Joe, could you have a look at this issue, please?
 [2018-03-26 12:31 UTC] cmb@php.net
-Assigned To: +Assigned To: krakjoe
 [2018-03-26 23:54 UTC] stas@php.net
-Type: Security +Type: Bug
 [2018-03-26 23:54 UTC] stas@php.net
phpdbg by definition is a debug facility, so it is not a security issue. See https://wiki.php.net/security#not_a_security_issue: 

requires the use of debugging facilities - ex. xdebug, var_dump
 [2018-04-10 08:34 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=8cfb648761229727fd66866092f7fa84dd3922fc
Log: Fixed bug #76143 (Memory corruption: arbitrary NUL overwrite)
 [2018-04-10 08:34 UTC] laruence@php.net
-Status: Assigned +Status: Closed
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Tue Aug 21 23:01:31 2018 UTC