Consider this small PHP script:
<?php
$dir = $_GET[‘dir’];
if (substr($dir, 0, 2) == ‘..’ || strpos($dir, ‘/..’) !== false || strpos($dir, "\\..") !== false)
die;
?>
<!doctype html>
<html>
<head><title>Show dir</title></head>
<body>
<?php
if ($dh = opendir(dirname(__FILE__)."/$dir")) {
while (($file = readdir($dh)) !== false) {
echo ‘filename: ‘.htmlspecialchars($file)." : filetype: " . filetype($dir . $file) . "\n";
}
closedir($dh);
} ?>
$dir = $_GET[‘dir’];
if (substr($dir, 0, 2) == ‘..’ || strpos($dir, ‘/..’) !== false || strpos($dir, "\\..") !== false)
die;
?>
<!doctype html>
<html>
<head><title>Show dir</title></head>
<body>
<?php
if ($dh = opendir(dirname(__FILE__)."/$dir")) {
while (($file = readdir($dh)) !== false) {
echo ‘filename: ‘.htmlspecialchars($file)." : filetype: " . filetype($dir . $file) . "\n";
}
closedir($dh);
} ?>
Looks fairly innocent, right?
Well it has a hidden XSS vulnerability if display_errors is activated and error_reporting contains E_WARNING. Consider the generated code when calling it with this querystring:
?dir=<script>window.alert('foobar!');</script>
What happens? Well the path (most likely) doesn’t exists, so opendir gives a warning of level E_WARNING – containing the unescaped path that couldn’t be found:
Uhm php, maybe you could at least escape the error messages when the content type currently being outputted is text/html?…