Sec Bug->Bug #76143 [Asn]: Memory corruption: arbitrary NUL overwrite

From: Date: Mon, 26 Mar 2018 23:54:37 +0000
Subject: Sec Bug->Bug #76143 [Asn]: Memory corruption: arbitrary NUL overwrite
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-214495@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=76143&edit=1 ID: 76143 Updated by: stas@php.net Reported by: cpicard at openmailbox dot org Summary: Memory corruption: arbitrary NUL overwrite Status: Assigned -Type: Security +Type: Bug Package: phpdbg Operating System: Windows/Linux PHP Version: 7.2.3 Assigned To: krakjoe Block user comment: N Private report: Y New Comment: 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 Previous Comments: ------------------------------------------------------------------------ [2018-03-26 12:07:50] 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-23 15:34:07] 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')" ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=76143&edit=1

« previous php.bugs (#214495) next »