В этой статье я собрал интересные на мой взгляд ошибки в php скриптах. Но для начала, дам описание некоторых параметров PHP-интерпретатора: Привожу список интересных тем: Sql инъекции, там где их на первый взгляд нет. - тут рассказано про фрагментированные sql инъекции, инъекции возможные из-за использования функций усечения строк, таких как (substr) Загрузка произвольных файлов через архив. - рассказывается о возможности загрузки произвольных файлов через архив, если при распаковки архива отсутствует фильтрация ../ И так начнем: [ + ] Ошибка заключается в том что переменные не были заранее определены в скрипте. На примере Openads 2.0.11-pr1 Уязвимость: XSS Условия: register_globals = ON >> adcontent.php PHP: ~~~~~~~~~~~~~~~~~~~~ //*** Переменная $row не определена if (isset($zoneid) && $zoneid > 0) { ~~~~~~~~~~~~~~~~~~~~ $row['bannerid'] = (int)$bannerid; $row['zoneid'] = $zoneid; $row['prepend'] = $prepend; $row['append'] = $append; } else { $row['bannerid'] = (int)$bannerid; $row['zoneid'] = 0; //*** Переменная $row['prepend'] и $row['append'] не установлена } /* Функция делает запрос к базе(кэшу), возвращает массив состоящий из информации о баннере, но среди полей нет append и prepend */ $details = phpAds_getBannerDetails($row['bannerid']); ~~~~~~~~~~~~~~~~~~~~ //*** Тут происходит объединение 2х массивов $row = array_merge($row, $details); //*** Передача данных функции для формирования html кода баннера $output = phpAds_prepareOutput($row, '_blank', $source, false); ~~~~~~~~~~~~~~~~~~~~ >> includes/lib-view-main.inc.php PHP: ~~~~~~~~~~~~~~~~~~~~ function phpAds_prepareOutput($row, $target, $source, $withtext){ global $phpAds_config; $outputbuffer = ''; /* Тут мы видим что в html код баннера добавляется содержание переменной $row['prepend']; */ if (isset($row['prepend'])) $outputbuffer .= $row['prepend']; ~~~~~~~~~~~~~~~~~~~~ /* Тут мы видим что в html код баннера добавляется содержание переменной $row['append']; */ if (isset($row['append'])) $outputbuffer .= $row['append']; ~~~~~~~~~~~~~~~~~~~~ Сплоит: Описание: В данном случае мы имеем xss, из-за того что массив row не был определен в начале скрипта. И мы можем спокойно передать в параметре row[prepend] любые данные. [ + ] Обход удаления глобальных переменных Во многих скриптах, чтобы не возникло ситуации как с Openads 2.0.11-pr1 (в случае register_globals = ON), просто удаляют переменные переданные скрипту через POST, GET и т.д. из массива GLOBALS, но не всегда делают это правильно ))) На примере Coppermine gallery 1.3.3 Уязвимость: Загрузка произвольных файлов Условия: register_globals = ON allow_url_fopen = ON >> include/init.inc.php PHP: ~~~~~~~~~~~~~~~~~~~~ //*** Удаление глобальных переменных переданных методом POST if (is_array($HTTP_POST_VARS)) { foreach ($HTTP_POST_VARS as $key => $value) { if (!is_array($value)) $HTTP_POST_VARS[$key] = strtr($value, $HTML_SUBST); if (isset($$key)) unset($$key); //*** Удаляется глобальная переменная } } //*** Аналогично только для GET if (is_array($HTTP_GET_VARS)) { foreach ($HTTP_GET_VARS as $key => $value) { $HTTP_GET_VARS[$key] = strtr($value, $HTML_SUBST); if (isset($$key)) unset($$key); } } if (is_array($HTTP_COOKIE_VARS)) { foreach ($HTTP_COOKIE_VARS as $key => $value) { if (isset($$key)) unset($$key); } } ~~~~~~~~~~~~~~~~~~~~ >> picEditor.php PHP: require('include/init.inc.php'); ~~~~~~~~~~~~~~~~~~~~ if (isset($HTTP_GET_VARS['id'])) { $pid = (int)$HTTP_GET_VARS['id']; } elseif (isset($HTTP_POST_VARS['id'])) { $pid = (int)$HTTP_POST_VARS['id']; } else { $pid = -1; } //*** Если id не передавать, то $CURRENT_PIC - будет не определена if ($pid > 0){ $result = db_query("SELECT * FROM {$CONFIG['TABLE_PICTURES']} WHERE pid = '$pid'"); $CURRENT_PIC = mysql_fetch_array($result); mysql_free_result($result); $pic_url = get_pic_url($CURRENT_PIC,'fullsize'); } ~~~~~~~~~~~~~~~~~~~~ if (!$img_dir) $img_dir = IMG_DIR; if ($_GET['id']){ ~~~~~~~~~~~~~~~~~~~~ }else if(!isset($newimage)){ $newimage = $_POST['newimage']; } ~~~~~~~~~~~~~~~~~~~~ if(isset($_POST["save"])) { ~~~~~~~~~~~~~~~~~~~~ //*** Копируем файл copy($img_dir.$newimage,$CONFIG['fullpath'].$CURRENT_PIC['filepath'].$CURRENT_PIC['filename']); Сплоит: Описание: В данном случае POST запросом передаем переменную HTTP_GET_VARS. В файле init.inc.php, при удалении глобальных переменных переданных методом POST будет удалена переменна HTTP_GET_VARS. В следствии чего переменные переданные методом GET остануться нетронутыми. А так как переменные img_dir и CURRENT_PIC не были определены, мы можем пeредать им любые значения и загрузить файл на сервер через функцию copy(). [ + ] Небезопасное использование preg_replace с модификатором /e На примере roundcube 0.2-3 Уязвимость: Выполнение произвольного php кода http://www.milw0rm.com/exploits/7549 >> lib/html2text.php PHP: ~~~~~~~~~~~~~~~~~~~~ //*** Шаблоны с /e разрешают выполнение php кода var search = array( '/<a [^>]*href=("|\')([^"\']+)\1[^>]*>(.+?)<\/a>/ie', // <a href=""> '/<b[^>]*>(.+?)<\/b>/ie', // <b> '/<th[^>]*>(.+?)<\/th>/ie', // <th> and </th> ~~~~~~~~~~~~~~~~~~~~ //*** Шаблоны для замены var $replace = array( '$this->_build_link_list("\\2", "\\3")', // <a href=""> 'strtoupper("\\1")', //*** Обратим внимание что используются " (двойные кавычки) "strtoupper(\"\t\t\\1\n\")", // <th> and </th> ~~~~~~~~~~~~~~~~~~~~ $text = preg_replace($this->search, $this->replace, $text); Дополнительная информация: Сплоит: Описание: Думаю тут все понятно, передаем скрипту <b>{${phpinfo()}}</b>, и выполняется код strtoupper("{${phpinfo()}}"); [ + ] Небезопасное использование функций call_user_func_array(); call_user_func(); На примере Wordpress plugin WP-Syntax <= 0.9.1 Уязвимость: Выполнение произвольных команд Условия: register_globals = ON http://www.milw0rm.com/exploits/9431 >> wp-content/plugins/wp-syntax/test/index.php PHP: //*** переменная $test_filter не определена function apply_filters($tag, $string) { global $test_filter; if (!isset($test_filter[$tag])) return $string; uksort($test_filter[$tag], "strnatcasecmp"); foreach ($test_filter[$tag] as $priority => $functions) { if (is_null($functions)) continue; foreach($functions as $function) { //*** Вызов функции переданной в $test_filter $string = call_user_func_array($function, array($string)); } } return $string; } Сплоит: Описание: Сначала вызываем функцию session_start, чтобы инициализировать сессию, затем с помощью функции session_id получаем ссылку на id сессии, которая будет передана в функцию system. Теперь через PHPSESSID можно передавать нужные нам параметры для функции system [ + ] Небезопасное использование функции urldecode На примере phpBB 2.0.10 Уязвимость: Выполнение произвольного php кода >> viewtopic.php PHP: ~~~~~~~~~~~~~~~~ $highlight_match = $highlight = ''; if (isset($HTTP_GET_VARS['highlight'])) { /* Если передать $HTTP_GET_VARS['highlight'] = %2527, как видно никаких опасных символов нет, addslashes ничего экранировать не будет. Но после urldecode($HTTP_GET_VARS['highlight']), %2527 превратится в %27, что эквивалентно ' */ $words = explode(' ', trim(htmlspecialchars(urldecode($HTTP_GET_VARS['highlight'])))); for($i = 0; $i < sizeof($words); $i++) { if (trim($words[$i]) != '') { //*** Подготовка $highlight_match для поиска совпадений $highlight_match .= (($highlight_match != '') ? '|' : '') . str_replace('*', '\w*', phpbb_preg_quote($words[$i], '#')); } } unset($words); $highlight = urlencode($HTTP_GET_VARS['highlight']); } ~~~~~~~~~~~~~~~~ // // Highlight active words (primarily for search) // if ($highlight_match) { //*** Используя ' в $highlight_match, можно внедрить php код $message = str_replace('\"', '"', substr(preg_replace('#(\>(((?>([^><]+|(?R)))*)\<))#se', "preg_replace('#\b(" . $highlight_match . ")\b#i', '<span style=\"color:#" . $theme['fontcolor3'] . "\"><b>\\\\1</b></span>', '\\0')", '>' . $message . '<'), 1, -1)); } Сплоит: Описание: Соответственно если urldecode будет находиться после блока который отвечает за фильтрацию переменных (например addslashes), то в полне вероятно что этот фильтр можно будет обойти. Я хотел показать в этой статье что по мимо обычных ошибок в php скриптах, которые видно сразу, существуют ещё и ошибки менее заметные, но при этом не менее опасные и о них надо знать.