Поиск уязвимостей в веб приложениях на реальных примерах.

Discussion in 'Уязвимости' started by (Dm), 17 Oct 2009.

  1. (Dm)

    (Dm) Elder - Старейшина

    Joined:
    8 Apr 2008
    Messages:
    261
    Likes Received:
    440
    Reputations:
    275
    В этой статье я собрал интересные на мой взгляд ошибки в 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'$sourcefalse); 
    ~~~~~~~~~~~~~~~~~~~~
    >> 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 скриптах, которые видно сразу, существуют ещё и ошибки менее заметные, но при этом не менее опасные и о них надо знать.
     
    #1 (Dm), 17 Oct 2009
    Last edited: 21 Jan 2010
    17 people like this.