Информационная безопасность
[RU] switch to English


История одной уязвимости

 

Началось все с сообщения eEye [1] об очередной обнаруженной уязвимости переполнения буфера в IIS. Проблема заключалась в ISAPI фильтре от Index Service. Согласно отчету eEye уязвимость была обнаружена совершенно неожиданно во время одного из испытаний технологии CHAM (Common Hacking Attack Methods), когда стали падать IIS серверы.

Было установлено, что буфер переполнялся при получении следующего запроса

GET /a.ida?[big_string]=a HTTP/1.0
Host: hack

Или

GET /a.idq?[big_string]=a HTTP/1.0
Host: hack

При этом длина big_string примерно 240 байт.

По утверждению eEye буфер переполняется во время конвертации ASCII в wide char (на самом деле это утверждение не совсем точное, смотрите далее). Таким образом, символы

'AAAAA' будут трансформированы в строку вида '\0A\0A\0A\0A\0A'.

Очевидно, что написать "надежный" эксплоит для данной уязвимости очень не просто.

Как известно [10], каждая атака на переполнение буфера подразумевает решение двух задач:

  1. внедрение или подготовка кода эксплоита
  2. передача управления коду эксплоита

Поэтому сразу возникают вопросы:

Что делать с кодом, если строка так сильно трансформируется?

Как передать управление внедренному коду, если доступны только адреса из диапазона

0x00010001-0x00ff00ff (причем даже не все из них).

Действительно, обычная практика подразумевает использование адрес инструкции перехода (например: jmp/call esp, jmp/call ebp и т.д.), которая находится в одной из DLL или в коде самого атакуемого приложения. Однако все DLL и приложения расположены "по верхним" адресам (> 0x10000000 для DLL, >= 0x04000000 для image base приложения).

Сами "эксперты" eEye в шутку пишут, что речь идет об эксплоите, выходящем за пределы ниндзя. Помимо шуток, они предложили использовать адаптированный внедряемый код, который учитывает нулевые байты или состоит только из инструкций с первым нулевым байтом (ознакомится с перечнем доступных инструкций такого рода можно на http://www.sandpile.org). Ограниченный набор инструкций может быть использован только для декодирования основного кода.

Ввиду того, что inetinfo (процесс IIS сервера) для хранения полученных пакетов или сообщений использует кучи (heap), код эксплоита также окажется в этой области памяти, находящейся по доступным для нас "нижним" адресам (<0x00ff00ff). При этом будет осуществляться непосредственная передача управления коду эксплоита без обычного:

ret > jmp esp > эксплоит.

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

GET /a.ida?[big_string]=a HTTP/1.0
Host: hack
eEye: [injected_code]

По утверждению eEye им все же удалось (!) разработать Proof-Of-Concept эксплоит с использованием описанной технологии. Возможность функционирования такого эксплоита сильно зависит от текущего состояния кучи, которое несложно предсказать для вновь запущенного inetinfo. Здесь на помощь приходит Windows 2000 Service Control Manager, который перезапускает inetinfo всякий раз, после сбоя. Таким образом, для атаки первым посылается запрос, который просто "валит"(denial of service) IIS, а затем уже код эксплоита для вновь запущенного заботливым менеджером сервисов процесса inetinfo.

Однако такой фокус не проходит с NT4.0.

Примечательно, что eEye так и не выложили Proof-Of-Concept эксплоит для данной уязвимости, лишь пообещав это. Вероятно, это связано с тем, что экслоит работал крайне не стабильно, и они просто не смогли развить его, полагая, что это крайне сложно. Ранее eEye всегда старалась приводить Proof-Of-Concept эксплоит (например [2], и iishack).

Однако, что не сделали одни, обязательно сделают другие. Так стало и в этом случае.

Через три дня появляется нормальный рабочий эксплоит от hsj [3]. Автор эксплоита не стал ломать копья. Решение было очень простым - escape символы для Unicode wild char. Это кажется таким очевидным, что до сих пор непонятно зачем "эксперты" из eEye так все запутали.

Теперь строка эксплоита выглядела следующим образом:

 

GET /a.idq?[big_string] %u08eb%u16DE%u77E5%u%uC033%uB866%u031F%u0340%u8BD8

%u8B03%u6840%uDB33%u30B3%uC303%uE0FF=a HTTP/1.0
Shell: [injected_code]

Данный эксплоит это демонстрация уязвимости. Он работает лишь с определенной версией сервиспака. По сути, это то, что должны были и обещали сделать eEye.

Далее события развиваются еще более интересно. Появляется основанный на данной уязвимости червь под кодовым названием Code Red. Червь размножается, рассылкой своего кода по случайным (сгенерированным) адресам. Параллельно им производился дефейс на серверах с английской локализацией. С 24 по 27 числа месяца червь бомбардирует пакетами 198.137.240.91 (www1.whitehouse.gov).

Code Red способен атаковать любые системы с установленным IIS5 не зависимо от версии сервиспака. Данный факт сильно способствовал его всеобщему распространению. Имеются даже свидетельства успешной атаки и дефейса www.windowsupdate.com [5]. По некоторым оценкам [6], за короткое время с 10 июля по 20 июля были заражены практически все уязвимые хосты.

К счастью, "голая" статистика в данном случае не применима. Code Red, очевидно, не мог достичь всех возможных целей, ввиду ограничения интервала псевдослучайно генерируемых ip-адресов.

Сразу после публикации анализа червя [4], появляется его второе поколение. Новый червь стал незначительной модификацией первоначального варианта [7]. Отличие заключалось в исправленном алгоритме генерации ip-адресов и отключением механизма дефейса.

Рассмотрим функционирование червя более детально. Скороспелый анализ [4] содержит ряд ошибок и неточностей, поэтому пришлось прибегнуть к собственным изысканиям. Судя по всему "экспертам" очень не терпелось поскорей застолбить свое первенство и выложить хоть какой-то результат.

Итак, атака на уже знакомую нам уязвимость производится посредством следующего запроса:

GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNN%u9090%u6858 %ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090 %u6858%ucbd3%u7801%u9090%u9090%u8190%u00c3 %u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0
Content-type: text/xml
HOST:www.worm.com
Accept: */*
Content-length: 3569

Далее следует код эксплоита длиной 3569 байт.

Большая строка запроса модифицирует не адрес возврата из функции, как при обычном срыве стека, а адрес обработчика исключений (SEH Structured Exception Handling). Таким образом, при возникновении исключения вызывается исключение по адресу, который заложен в посылаемой строке запроса. Все это непосредственно происходит в функции DecodeURLEscapes (query.dll).

Приведем фрагмент кода, где устанавливается новый обработчик исключений с уже модифированным адресом.

68cc6a45 8938 mov [eax],edi
68cc6a47 e8623f0800 call query!ciDelete (68d4a9ae)
68cc6a4c 8b4df4 mov ecx,[ebp-0xc]
68cc6a4f 5f pop edi
68cc6a50 5e pop esi
68cc6a51 64890d00000000 mov fs:[00000000],ecx
68cc6a58 5b pop ebx
68cc6a59 c9 leave
68cc6a5a c21000 ret 0x10

В результате переполнения буфера, помимо модификации адреса обработчика исключений, внутри функции query!ciNew происходит вызов RtlAllocateHeap с крайне большим параметром числа выделяемых байт кучи. Далее, согласно обычной схеме, в случае ошибки query!ciNew генерирует исключение (вызов RaiseException), что в свою очередь приводит к вызову по адресу, модифицированному атакующей строкой запроса.

В данном случае это адрес инструкции call ebx (0x7801cbd3 msvcrt.dll). Регистр ebx указывает на область данных в стеке, которая принадлежит части атакующего запроса и выглядит следующим образом:

00fbf0e8 90 nop
00fbf0e9 90 nop
00fbf0ea 58 pop eax
00fbf0eb 68d3cb0178 push 0x7801cbd3
00fbf0f0 90 nop
00fbf0f1 90 nop
00fbf0f2 90 nop
00fbf0f3 90 nop
00fbf0f4 90 nop
00fbf0f5 81c300030000 add ebx,0x300
00fbf0fb 8b1b mov ebx,[ebx]
00fbf0fd 53 push ebx
00fbf0fe ff5378 call dword ptr [ebx+0x78]

К моменту выделенного вызова регистр ebx содержит адрес структуры EXTENSION_CONTROL_BLOCK. Эта структура используется для обмена информацией между IIS и его ISAPI расширениями. В текущий момент структура относится к уязвимому фильтру Index Service и содержит информацию об атакующем запросе, которая передавалась фильтру. Соответственно, поле lpbData, находящееся по смещению 0x78 содержит указатель на код эксплоита.

Описание червя можно проследить в дизассемблированном коде Code-Red.idb формата IDA (или в worm.asm), который является модифицированной версией оригинального http://www.eeye.com/html/advisories/codered.zip. В нем расставлены комментарии, соответствующие содержанию кода, исправлено масса ошибок и неточностей. Можно даже пошутить, что, судя по всему, результат данного дизассемблирования был первым опытом "экспертов" eEye с IDA. Часть некорректных меток и комментариев у меня так и не хватило терпения поправить.

В самом начале эксплоит устанавливает новый стек и новый обработчик исключений. Затем идет настройка адресов используемых эксплоитом функций. При этом используется алгоритм, основанный на поиске в памяти образа kernel32.dll. Поиск начинается с адреса 0x77E10000. В каждой последующей итерации прибавляется смещение 0x10000. Образ определяется по заголовку исполняемого файла. В найденной DLL производится поиск экспортируемой функции GetProcAddress, которая используется для загрузки адресов всех остальных необходимых функций.

Данный метод позволяет успешно атаковать IIS с любым сервиспаком. Обычно при атаках используется адрес jmp заглушки импортируемой GetProcAddress. Так как атакуемая программа неизменна (уязвимая версия), то этот адрес является константой и на его базе можно строить эксплоит. Однако, IIS постоянно патчится от фикса к фиксу и от сервиспака к сервиспаку, оставаясь при этом уязвимым. По этой причине, вероятно, был применен такой необычный алгоритм. Реализация также требует установки своего обработчика исключений, на случай, если во время поиска будет произведено обращение по некорректному адресу. Червь встраивает свой обработчик в цепочку, но он является фиктивным и при исключении в лучшем случае произойдет передача управления по адресу 0xCCCCCCCC, в худшем - повторное исключение и остановка inetinfo.

Однако вовсе необязательно искать kernel32.dll. Можно просто попробовать найти любой первый попавшийся образ исполняемого файла и найти в нем импортируемую GetProcAddress, так как практически любой файл импортирует эту функцию. Также можно воспользоваться собственной реализацией данной функции. И, на конец, самым простым и надежным способом было бы отыскать эту функцию в таблице импорта самого inetinfo.exe.

После настройки функций Code Red посылает ответ клиенту, с которого был послан. При этом активно используются поля структуры EXTENSION_CONTROL_BLOCK. Далее в стеке формируется следующий код из 12 байт:

push	pExtensionControlBlock
pop	ebx
push	ebx
push	ebx
jmp	[ebx+78]

Затем создается поток со стартовым адресом, указывающим на приведенный код. Как видно используется схема повторного запуска червя, которая аналогична схеме при первичном запуске.

Далее проверяется наличие файла c:\notworm. Если файл обнаружен, Code Red замораживает свою работу вызовом функции Sleep. Это является своеобразным ограничителем распространения вируса, сознательно заложенным авторами.

Затем производится проверка текущего числа месяца, после чего работа червя разветвляется. С 20-го по 27-е числа управление передается коду, наводняющему пакетами www1.whitehouse.gov, в остальные числа месяца запускается код размножения.

Интересно отметить, что предполагаемая атака на www.whitehouse.gov так и не удалась. Причина тому использование фиксированного ip-адреса, одного из серверов сайта www.whitehouse.gov. Как только эта особенность червя была обнаружена, администраторы www.whitehouse.gov заблокировали данный ip-адрес. Такие же меры приняли на ряде магистральных и корпоративных маршрутизаторов. Если бы вместо фиксированного адреса использовалось разрешение доменного имени www.whitehouse.gov, то все могло бы быть по другому.

Обратимся к коду размножения. Этот код базируется на генераторе псевдослучайных ip-адресов, который можно описать следующим фрагментом на Си:

DWORD GetRandomIp(DWORD ThreadCounter)
{
 DWORD ResultIP;
 SYSTEMTIME systime;
 DWORD temp1, temp2, temp3;
 DWORD SecMilisec;
 ResultIP = ThreadCounter*0x50F0668D;
 GetSystemTime(&systime);
 memcpy(&SecMilisec, &systime.wSecond, sizeof temp);
 temp1 = SecMilisec*SecMilisec*0xCD59E3;
 temp2 = SecMilisec*0x1E1B9;
 temp3 = ResultIP + temp1;
#ifdef  CRv1
 temp2 = temp2 + temp3;
#else
 ResultIP = temp2 + temp3;
#endif
 ResultIP = ResultIP*0xCF3383 + 0x76BFE53;
 temp2 = ResultIP & 0xff;
 if ((temp2 == 127) || (temp2 == 224)) {
  ResultIP = ResultIP + 0x20DA9;
 }
 return ResultIP;
}

Из листинга видно, что алгоритм сменился во втором поколении червя. Вероятно, была просто поправлена ошибка.

Генерируемый ip-адрес является функцией 3х параметров:

  1. номер потока (1-100),
  2. текущая секунда (0-59),
  3. текущая миллисекунда (0-999).

Отсюда максимально возможный неповторяющийся набор получаемых адресов равен:

100*60*1000 = 6000000 = 6 млн. ip-адресов.

Понятно, что все заявления по поводу инфицирования практически всех возможных целей не имеют под собой основания. 6 млн. ip-адресов это только 0,1 % всех теоретически возможных ip-адресов.

По полученному ip-адресу червь пытается послать свою копию, используя при этом данные из структуры EXTENSION_CONTROL_BLOCK. После чего вновь инициируется проверка наличия файла c:\notworm и алгоритм зацикливается.

Другой функциональной особенностью червя является наличие счетчика созданных потоков. Как только его значение будет равным 100, инициируется процесс дефейса, который достаточно детально описан в [4].

На сегодняшний момент можно говорить о преодолении нашествия Code Red. Однако не следует забывать о возможном появлении мутаций червя с рядом усовершенствований. К числу таких усовершенствований можно отнести развитие генератора ip-адресов, средств удаленного управления, сбора информации, апгрейда и т.д. Так как червь является полностью резидентным, обнаружить его присутствие на удаленном сервере достаточно сложно. Возможно, только определить наличие уязвимого IIS, что реализовано в Code Red Scanner http://www.eeye.com/html/Research/Tools/CodeRedScanner.exe. Новое поколение червя могло бы корректировать данную ошибку в памяти, создавая видимость отсутствия уязвимости и препятствуя возможности ее детектирования.

Как обнаружить и пропатчить уязвимые системы описано здесь [8]. Если сервера еще непропатчены, то в качестве профилактической меры можно порекомендовать перестартовать их. Подборку различной информации по червю Code Red можно найти по этой ссылке [9].

 

Итак, выводы:

  1. Почти любая теоретическая уязвимость рано или поздно становится практической, вопрос только во времени.
  2. Если достаточно опасную уязвимость "в упор не замечают" достаточно продолжительное время, последствия будут плачевными.
  3. Обязательно выпускать и устанавливать заплаты даже для дыр, не имеющих эксплоита.
  4. Эксперты могут ошибаться и заблуждаться
  5. Боюсь, что история данной уязвимости еще не закончена и новые мутации червя и другие атаки дадут о себе знать.

 

Ссылки:

  1. "All versions of Microsoft Internet Information Services Remote buffer overflow (SYSTEM Level Access)", 18 июня 2001, http://eeye.com/html/Research/Advisories/AD20010618.html
  2. "Windows 2000 IIS 5.0 Remote buffer overflow vulnerability (Remote SYSTEM Level Access)", 1 мая 2001, http://eeye.com/html/Research/Advisories/AD20010501.html
  3. http://www.geocities.co.jp/MotorCity/5319/iis5idq_exp.txt
  4. ".ida "Code Red" Worm", 18 июля 2001 года, http://eeye.com/html/Research/Advisories/AL20010717.html
  5. http://www.datarescue.com/fprot/virinfo/hackedbychinese.gif
  6. "Analysis of spread of the Code Red worm", Stuart Staniford, 21 июля 2001, http://www.silicondefense.com/cr/
  7. Marc Maiffret, "CodeRed: the next generation", BugTraq, http://www.securityfocus.com/archive/1/198347
  8. "CodeRed Scanner from eEye Digital Security", http://eeye.com/html/Research/Tools/codered.html
  9. "Special coverage: the Code Red worm", http://www.net-security.org/text/articles/coverage/code-red/
  10. "Атаки на переполнение буфера", http://www.security.nnov.ru/articles/bo.asp
  11. "Переполнение буфера в IIS (IDQ ISAPI buffer overflow)", http://www.security.nnov.ru/search/news.asp?binid=1265
О сайте | Условия использования
© SecurityVulns, 3APA3A, Владимир Дубровин
Нижний Новгород