Статьи Null Byte уязвимость в PHP и защита от неё

Discussion in 'Статьи' started by [aCR]RASSVET, 5 Oct 2009.

  1. [aCR]RASSVET

    [aCR]RASSVET New Member

    Joined:
    27 Apr 2008
    Messages:
    19
    Likes Received:
    2
    Reputations:
    0
    Здравствуйте, дорогие читатели. :)
    Расскажу об одной уязвимости в PHP, которая называется «Null Byte» («нулл-байт» - нулевой байт).

    Суть уязвимости заключается в следующем. Большинство PHP-функций обрабатывают строки символов как набор двоичных данных (в PHP, в отличие от C, строки знают всё о своей длине. Но пока не знают ничего о кодировке - но это другая история.). Но есть несколько функций, как и в самом PHP, так и вне его, которые обрабатывают строки в C-стиле, то есть, считают байт 0x00 (Null-байт) концом строки.

    Пример 1. Допустим, у нас есть в системе 3 файла: index.php (контроллер), page.tpl (шаблон) и config.php (конфигурационный файл).

    index.php:
    PHP:
    <?php

    // получаем файл страницы
    $mode = (string)@$_GET['mode'];

    // убираем слэши, чтобы было невозможно выйти из текущей директории
    $mode str_replace('/'''$mode);

    // приписываем расширение, чтобы другие файлы не подключались
    $mode .= '.tpl';

    // если файл страницы существует
    if (file_exists($mode)) {
        
    // выводим его пользователю
        
    echo htmlspecialchars(file_get_contents($mode));
    }
    // если нет
    else {
        
    // сообщаем об ошибке
        
    echo "Error!";
    }

    ?>
    Если мы наберём в браузере путь_к_сайту/index.php?mode=page, то в браузер будет выведено содержимое файла page.tpl - что и требуется. Допустим, хакер закочет прочитать файл config.php, в котором хранятся важные настройки системы. Казалось бы, из-за того, что к странице приписывается расширение ".tpl", это сделать невозможно. А на самом деле - возможно, для этого нужно набрать в браузере путь_к_сайту/index.php?mode=config.php%00. Таким образом, в строке окажется нулевой байт 0x00, который сработает для файловой системы как конец строки!

    Поэтому, нужно всегда фильтровать нулевой байт, если строка будет обрабатываться в C-стиле. Например, так:
    PHP:
    // фильтруем нулевой байт  
    $mode preg_replace('/\0/s'''$mode);
    Если строка передаётся в функцию для работы с файловой системой и пр. (вне PHP) - всегда фильтруйте нулевой байт!

    Также следует помнить, что некоторые функции в самом PHP работают в C-стиле. Например, «ereg»-функции (ereg, eregi, ereg_ replace, eregi_ replace, split, spliti, sql_regcase, mb_ereg* и другие).

    Пример 2.
    index.php:
    PHP:
    <?php  
      
    // получаем кусок текста  
    $text = (string)@$_GET['text'];  
      
    // если в нём нет запрещённых символов - выводим на экран  
    if (!ereg('<|>|&'$text)) {  
        echo 
    $text;  
    }  
      
    ?>
    Для того, чтобы обойти фильтр, надо в браузере набрать путь_к_сайту/index.php?text=%00<script>alert(/XSS/)</script>.


    Спасибо за внимание.

    Взято с Figaroo.ru