Обход рандомизации адресного пространства (ASLR)

Обход рандомизации адресного пространства (ASLR)

Большинство современных операционных систем содержат несколько механизмов защиты памяти вроде DEP или ASLR. Данная статья сосредоточена на механизме ASLR, его реализации, ограничениях и, наконец, различных методах обхода данного вида защиты.

Автор: Toby 'TheXero' Reynolds

1 Введение

Большинство современных операционных систем содержат несколько механизмов защиты памяти вроде DEP или ASLR. Данная статья сосредоточена на механизме ASLR, его реализации, ограничениях и, наконец, различных методах обхода данного вида защиты.

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

Чтобы ASLR был эффективен, все запущенные процессы и библиотеки должны быть скомпилированы с поддержкой ASLR – так они смогут загружаться по новому адресу после каждой перезагрузки.

Хотя приведенные выше снимки экрана показывают одни и те же инструкции из библиотеки USER32.DLL, их адреса в памяти немного различаются (760F и 75DA). Дело в том, что USER32.DLL – библиотека ядра, в которой включен ASLR.

2 Метод первый – частичная перезапись

Наверное вы помните, как несколько лет назад появился печально известный ANI-эксплоит, к которому были уязвимы все версии Windows вплоть до Vista включительно. Поскольку до Windows Vista не было ASLR, процесс эксплуатации уязвимости на предшествующих версиях системы был довольно прост: требовалось лишь перейти по указателю, хранящемуся в EBX (JMP PTR EBX), а затем сделать пару коротких прыжков через ANI-заголовок, пока вы не приземлитесь на начале шелл-кода.

В случае Windows Vista и наличия ASLR вы не можете просто посмотреть на системную библиотеку SHELL32.DLL, чтобы добраться до выбранного регистра, так как базовый адрес также будет меняться после каждой перезагрузки. Поскольку аварийное завершение происходило в библиотеке USER32.DLL, в эксплоите для Windows Vista было сделано нечто действительно особенное, и для совершения необходимого прыжка в начало ANI-файла использовалась частичная перезапись EIP.

Наблюдая в отладчике за Internet Explorer в момент его аварийного завершения с помощью демонстрационного эксплоита ms07-017, мы видим, что EIP полностью перезаписан значением 43434343.

Сократив передаваемые в буфер данные на два байта, мы можем добиться частичной перезаписи EIP и обойти ASLR. Нам придется изменить заголовок ANI-файла, иначе мы можем не получить рабочий адрес возврата, поскольку тогда пришлось бы использовать метод грубой силы (что не слишком увлекательно).

Если перезаписать лишь два нижних байта регистра EIP адресом из USER32.DLL и оставить другую половину нетронутой, то верхние два байта не изменят своего первоначального значения (именно они рандомизируются ASLR). Теперь нам нужно лишь найти опкод, который позволит успешно обойти ASLR и выполнить наш код.

Ни один из регистров не указывает на наш буфер напрямую, однако первые 4 байта EBX указывают на адрес, предшествующий началу нашего ANI-заголовка. Поэтому нам нужно найти инструкцию JMP PTR [EBX] в текущей библиотеке USER32.DLL.

Найдя такую инструкцию, мы заменяем использовавшееся ранее для частичной перезаписи EIP тестовое значение 4343 на два байта ее адреса.

Как видно из показанного выше, мы выставили точку останова на нашем адресе возврата, поскольку при запуске данной инструкции JMP PTR мы окажемся в самом начале ANI-файла. Мы не можем просто заменить ANI-заголовок своим шелл-кодом, так как Windows в этом случае не распознала бы этот файл как ANI-файл, что не дало бы аварийного завершения. К счастью, раз мы приземлились в самом начале, на нашем пути нет байтов, могущих испортить стек до того, как мы достигнем пары байтов, позволяющих сделать короткий прыжок: мы уже нашли несколько байтов в ANI-заголовке, которые можно заменить, не лишаясь аварийного завершения.

Мы можем заменить 5 и 6 байты ANI-заголовка коротким прыжком на 22 байта, где мы можем использовать другую пару байтов, чтобы прыгнуть на 123 байта и на нашу полезную нагрузку.

3 Метод 2 – не-ASLR процесс

Другой неплохо работающий метод, который похож на предыдущий метод частичной перезаписи, состоит в использовании жестко закодированного адреса из существующей библиотеки (процесса), не поддерживающей ASLR.

Например, предположим, что вы нашли баг в музыкальном медиаплеере и находитесь под ОС с поддержкой ASLR вроде Windows Vista, а данный плеер подгружает во время выполнения несколько библиотек - скажем, MP3.DLL и т. д.

В данном примере мы собираемся портировать эксплоит для ’Free MP3 CD Ripper 1.1’ на Windows Vista. Исходный эксплоит можно найти здесь: http://www.exploit-db.com/exploits/17727/. Так как адрес возврата этого эксплоита указывает на dll-библиотеку ядра, загружающуюся по адресу ’76B43ADC’, это будет точным адресом для инструкции JMP ESP конкретно для ‘Windows XP SP3 English’. Это означает, что данный эксплоит вряд ли приведет к запуску кода на машине под управлением ‘Windows XP SP2 English’ или под еще какой-нибудь системой.

Если найти инструкцию JMP ESP, не используя системную библиотеку, у нас появится шанс не только сделать эксплоит универсальным, но и обойти ASLR.

Во время поиска загруженных библиотек программы ’Free MP3 CD Ripper 1.1’ я заметил, что ни программа, ни загружаемые ей библиотеки не поддерживают ASLR, а значит при открытии будут загружаться по одному и тому же адресу в памяти. Затем я смог исследовать загруженные библиотеки на предмет надежной инструкции JMP ESP instruction, однако таковой не нашел.

Значит, чтобы добраться до шелл-кода и получить полный контроль над процессом, нужно было заглянуть в поисках JMP ESP внутрь самой программы. Однако, данный метод сработает, только если процесс или библиотека, которая содержит искомую инструкцию, не поддерживает ASLR. Вам также нужно знать о недопустимых символах (в их число как правило входит нулевой байт), которые могут прервать наш буфер, либо иметь еще какие-нибудь последствия. В этом случае, однако, нам повезло, поскольку наш буфер не никак пострадал, и, пока на машине отсутствует DEP, эксплоит будет прекрасно работать в различных операционных системах.

В сетевых приложениях, которые обычно заканчивают сообщение нулевым байтом, нулевой байт считается недопустимым символом. В приложениях такого типа вы можете попробовать другой прием: попытаться обнаружить недопустимые символы, поскольку всегда есть вероятность, что недопустимый символ превратится в нулевой байт или что-нибудь подобное, что в данной ситуации может помочь обойти ASLR. Как только вы обойдете ASLR, вы в большинстве случаев вероятно найдете место для вашей полезной нагрузки и получите контроль над целевым приложением.

4 Метод 3 – метод грубой силы

Последний из рассматриваемых методов – метод грубой силы, который состоит в многократной передаче эксплоита целевому приложению до тех пор, пока вы не получите подходящий адрес. Это не слишком подходит для атаки на стороне клиента или если целевой сервис не перезапускается автоматически после аварийного завершения.

Этот метод ненадежный и очень медленный, поскольку для успешного запуска кода требует перебрать большое число различных базовых адресов, а данный процесс занимает длительное время. Так как, вероятно, каждый раз придется посылать полный код эксплоита, атаку будет очень просто обнаружить, особенно если в сети присутствуют такие защитные устройства, как IDS (системы обнаружения вторжения) или даже IPS (системы предотвращения вторжений).

Несмотря на то, что этот метод ужасающе ненадежен и требует большого количества времени, существуют открытые эксплоиты, которые используют его, чтобы справиться с ASLR: например, эксплоит, использующий уязвимость переполнения буфера при вызове функции trans2open в Samba, включенный во фреймворк Метасплоит: http://www.exploit-db.com/exploits/16861/.

5 Заключение

Хотя ASLR впервые появился в Windows Vista, очень многие производители ПО (в том числе ПО с открытым кодом) не торопились реализовать этот механизм защиты памяти. Например, в июне 2010 года Mozilla (производитель браузера Firefox) не реализовала полной поддержки ASLR в своем браузере, а Google – в своем (Chrome). Учитывая методологию ПО с открытым кодом, вы могли подумать, что новые механизмы защиты памяти вроде ASLR станут активно использоваться вскоре после появления, однако большинство производителей опровергают подобное суждение.

Microsoft включила поддержку ASLR во все программные пакеты, выпущенные ей с 2007 года, что сделало неэксплуатирумыми уязвимости в некотором ПО. Тем не менее, если переполнение буфера нельзя эксплуатировать для запуска кода, оно все еще может вызвать отказ в обслуживании (DoS), который сделает недоступным приложение/сервис. Если таким приложением окажется открытый наружу веб-сервер, это может иметь неблагоприятные финансовые последствия.

Хотя я рассматривал лишь ASLR в Windows Vista, подобные методы окажутся применимы и для других версий Windows (поддерживающих ASLR), вроде Windows Server 2008 и выше, а также для основанных на Linux дистрибутивов и, возможно, для таких систем, как Mac OS и Solaris.

Устали от того, что Интернет знает о вас все?

Присоединяйтесь к нам и станьте невидимыми!