gnarff
Goto Top

Hohes Sicherheitsrisiko im Sessionmanagment PHP 5.2.0 session.save path safe mode und open basedir bypass

Autor: Maksymilian Arciemowicz (SecurityReason)
Verfasst am: 02.10.2006
Veroeffentlicht am: 08.12.2006
SecurityAlert Id: 43
Sicherheitsrisiko: Hoch
Betrifft: PHP 5.2.0
Original-Advisory : http://securityreason.com/achievement_securityalert/43,
bugtraq 08.12.2006, 2:59pm
Vendor: http://www.php.net

Beschreibung:

Durch Session Support in PHP besteht die Moeglichkeit Zugriffsdaten auch bei nachfolgenden
Sessions zu schuetzen. Dabei wird einen Benutzer eine persoenliche ID [unique ID],
auch Session-ID gennant, zugewiesen. Die Session-ID wird in einem
Cookie auf dem Rechner des Benutzers abgelegt und in der URL angezeigt.

session.save_path definiert den Parameter der an den save handler uebergeben wird.
Bei Benutzung des standard files handler, ist dies der Pfad wo die Dateien erstellt werden.
Standardmaessig in /tmp.
Vgl. session_save_path().

Als Option gibt es den Parameter N der die Anzahl der Verzeichnisebenen bestimmt,
auf die die session files verteilt werden.

Ein '5;/tmp' z.B. kann dazu fuehren, dass ein session file erstellt wird, an einem Ort wie
/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If .

Um N benutzen zu koennen, muessen zunaechtst alle diese Verzeichnisse
geschaffen werden

Dafuer gibt es ein shell-script in ext/session, mit Namen mod_files.sh.

Zu beachten ist, dass wenn die Option N benutzt wird und groesser als 0
ist, funktioniert die automatische Speicherbereinigung nicht mehr.
Vgl. php.ini fuer weiter Informationen

Ebenfalls ist sicherzustellen, dass bei der Benutzung des Parameters N,
session.save_path in "quotes" einzubetten, weil der Separator
(;) auch fuer die comments in der php.ini benutzt wird.

1. session.save_path safe mode und open basedir bypass

Der session.save_path kann festgelegt werden mit der ini_set(), session_save_path() Funktion.
In session.save_path muss der Pfad zu dem Ort angegeben werden wo die tmp-files gespeichert werden sollen
Der Syntax fuer session.save_path kann so aussehen:

[/PATH]

oder

[N;/PATH]

N - kann eine Zeichenkette sein.

Beispiele:

1. session_save_path("/DIR/WHERE/YOU/HAVE/ACCESS")
2. session_save_path("5;/DIR/WHERE/YOU/HAVE/ACCESS")

und

3. session_save_path("/DIR/WHERE/YOU/DONT/HAVE/ACCESS\0;/DIR/WHERE/YOU/HAVE/ACCESS")


-- -1477-1493--- Code from PHP520 ext/session/session.c [START]
PHP_FUNCTION(session_save_path)
{
	zval **p_name;
	int ac = ZEND_NUM_ARGS();
	char *old;

	if (ac < 0 || ac > 1 || zend_get_parameters_ex(ac, &p_name) == FAILURE)
		WRONG_PARAM_COUNT;
	
	old = estrdup(PS(save_path));

	if (ac == 1) {
		convert_to_string_ex(p_name);
		zend_alter_ini_entry("session.save_path", sizeof("session.save_path"), Z_STRVAL_PP(p_name), Z_STRLEN_PP(p_name), PHP_INI_USER, PHP_INI_STAGE_RUNTIME);  
	}
	
	RETVAL_STRING(old, 0);
}
- -1477-1493--- Code from PHP520 ext/session/session.c [END]

Die Werte werden an hash_memory uebergeben, doch bevor dies passiert ueberpruefen safe_mode and open_basedir Diese.
Wenn die Session dann gestartet wird, z.B. mit  session_start(), 
wird der Wert von session.save_path von function PS_OPEN_FUNC(files) ueberprueft..

-- -242-300--- Code from PHP520 ext/session/mod_files.c [START]
PS_OPEN_FUNC(files)
{
	ps_files *data;
	const char *p, *last;
	const char *argv[3];
	int argc = 0;
	size_t dirdepth = 0;
	int filemode = 0600;

	if (*save_path == '\0') {  
		/* if save path is an empty string, determine the temporary dir */
		save_path = php_get_temporary_directory();
	}
	
	/* split up input parameter */
	last = save_path;
	p = strchr(save_path, ';');  
	while (p) {
		argv[argc++] = last;
		last = ++p;
		p = strchr(p, ';');  
		if (argc > 1) break;
	}
	argv[argc++] = last;

	if (argc > 1) {
		errno = 0;
		dirdepth = (size_t) strtol(argv, NULL, 10);
		if (errno == ERANGE) {
			php_error(E_WARNING, 
					"The first parameter in session.save_path is invalid");  
			return FAILURE;
		}
	}
	
	if (argc > 2) {
		errno = 0;
		filemode = strtol(argv[1], NULL, 8);
		if (errno == ERANGE || filemode < 0 || filemode > 07777) {
			php_error(E_WARNING, 
					"The second parameter in session.save_path is invalid");  
			return FAILURE;
		}
	}
	save_path = argv[argc - 1];

	data = emalloc(sizeof(*data));
	memset(data, 0, sizeof(*data));
	
	data->fd = -1;
	data->dirdepth = dirdepth;
	data->filemode = filemode;
	data->basedir_len = strlen(save_path);
	data->basedir = estrndup(save_path, data->basedir_len);
	
	PS_SET_MOD_DATA(data);
	
	return SUCCESS;
}
- -242-300--- Code from PHP520 ext/session/mod_files.c [END]


In session.save_path ist ein NULL byte vor dem ; gesetzt,
strchr() kann; nicht lesen und der Pfad ist dann /DIR/WHERE/YOU/DONT/HAVE/ACCESS.

Dieses Problem entseht, weil safe_mode und open_basedir den Pfad nach dem ; ueberpruefen.
Daher ist es noetig den Pfad nach dem ; korrekt zu bestimmen!

2. Wie man das Problem fixen kann
http://cvs.php.net/viewcvs.cgi/php-src/NEWS

saludos
gnarff

Content-Key: 46383

Url: https://administrator.de/contentid/46383

Ausgedruckt am: 29.03.2024 um 07:03 Uhr