Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #48, НОЯБРЬ 2004 г.

Эксплоит для сетевого чата

sba (sba@list.ru)

Спецвыпуск: Хакер, номер #048, стр. 048-034-4


Исследование Network Assistant изнутри

Итак, перед нами находится готовая к принятию специальным образом сформированного пакета уязвимая к переполнению процедура-обработчик поступивших пакетов (находится по адресу 0x004BB938; ее можно найти, поставив брейк на API-функцию recvfrom). Не будем рассказывать, каким образом мы обнаружили ограничения в ней. Немного фантазии, немного опыта, и дело в шляпе. Суть ограничений сводится к тому, что чужой код работает по заранее оговоренному автором плану, и он не приспособлен к тому, чтобы принять наш неправильный пакет, да еще и корректно его обработать. Первое, что мы нарушаем, переполняя стек, – затираем большую часть локальных переменных уязвимой процедуры, но совсем не факт, что такая огромнейшая процедура, как парсер пакетов, использует все локальные переменные. Не знаю, почему нам так понравился пакет с ID=0x0F, но, изучив код процедуры, мы пришли к выводу, что та часть процедуры, которая отвечает за обработку пакета 0x0F, НЕ ИСПОЛЬЗУЕТ локальных переменных, затертых в процессе срыва стека. Что у нас есть? 16-байтовый массив под название хоста (dword ptr EBP-80h), именно его мы и будем переполнять. Суть переполнения сводится к тому, что запись названия хоста из полученного пакета в этот массив производится без проверки длины. Авторы программы наивно полагались на то, что длина названия хоста не может превышать 15 символов. Та же нам очень повезло, что копирование стрингов производится не с помощью строковых функций, а посредством старой доброй CopyMemory. Этот факт избавляет нас от огромнейшей головной боли – не придется формировать стринг-эксплоит (в нем нельзя использовать управляющие символы, и, самое главное, символ ‘\0’, так как ни одна строковая функция не обрабатывает символы, находящиеся после ‘\0’). Другими словами, мы формируем обычный пакет для Network Assistant и записываем в него данные в том виде, в каком они есть. Это значительно упростит как написание эксплоита, так и его код, избавляя нас от необходимости внедрения в эксплоит декодера. Для того чтобы дотянуться до адреса возврата в стеке, нам придется записать в переполняемый массив 80h байт (от греха подальше будем записывать исключительно нули, так как анализ процедуры показал, что все локальные переменные инициализируются нулями, и, наверное, где-то алгоритм на это полагается, но нам нет нужды проверять сие предположение) плюс еще 4 байта (в стеке сохраняется старое значение регистра EBP). Дальше следуют три аргумента функции. А за ними мы разместим прыжок на следующую часть эксплоита. Почему так сложно? По-другому нельзя, так как переполняемый буфер слишком короткий, чтобы разместить в нем весь код целиком. Проблема в том, что хотя в эти 80h байт можно запихать кучу кода, но к тому времени, как к нам перейдет управление, там будет мусор, а не дельный код. Поэтому и приходится размещать код по кускам, в тех местах стека, в которые гарантированно не производится запись в процессе исполнения уязвимой процедуры. Мы обошлись всего тремя частями. Во второй части мы осуществляем разбор пакета, аналогично самому Network Assistant. Двигаемся по заголовку пакета, пока не дойдем до основной части эксплоита, размещенной в пакете вместо текста сообщения. Вот на эту третью часть кода и передаем управление. Эта часть самая длинная, порядка нескольких килобайт, но самого кода там всего-то несколько строк – поиск системной директории, запись в нее DLL (серверная часть) и собственно загрузка DLL в адресное пространство Network Assistant, после чего возвращается управление последнему. Далее в пакете размещается серверная DLL, которая создает отдельный поток для захвата пакетов из сети, анализа их на предмет пакетов от клиента.

Назад на стр. 048-034-3  Содержание  Вперед на стр. 048-034-5