В данном документе предлагается метод по борьбе с атаками, но не с самими уязвимостями. Перед тем, как перейти к делу, взглянем на Slammer (в очередной раз).
Что сделало Slammer столь успешным?
Решающий фактор, сделавший его столь успешным, - его способность к распространению. А распространение его сделал неизбежным простой факт - у каждого уязвимого SQL Server/MSDE по адресу 0x42B0C9DC была расположена команда "jmp esp". Именно этот адрес использовался для получения контроля над SQL Server'ом и передачи управления в ту точку, где находился внедренный червем "произвольный код".
Этот адрес находится во внутренностях динамически загружаемой библиотеки (DLL) sqlsort.dll, базовый адрес которой - 0x42AE0000.
У каждого исполняемого файла или DLL есть так называемый базовый адрес, определяющий желательное расположение в памяти, по которому файл будет загружен системным загрузчиком (Не хочу здесь отвлекаться на то, что происходит в случае конфликта. Посмотрите документацию.) (Строго говоря, в Win32 происходит не загрузка, а отображение исполняемого файла на адресное пространство процесса, хотя это не влияет на суть обсуждаемой темы. Упомянутый конфликт может произойти при загрузке DLL в том случае, если по указанному адресу не нашлось достаточно места для ее отображения. Тогда осуществляется поиск подходящего участка памяти и автоматическая модификация адресов внутри DLL. - Прим.переводчика).
Если бы базовый адрес в некоторой системе оказался равным 0x42AF0000, червь был бы не в состоянии ее заразить. Искомая команда "jmp esp" вместо адреса 0x42B0C9DC в этой системе находится по адресу 0x42B1C9DC, так что червь просто промахнулся бы. SQL Server, запущенный на этой системе, оставаясь беззащитным перед переполнением буфера, окажется вполне устойчивым к атакам червя. Да, конечно, он может упасть - но не будет заражен.
Это все похоже на историю с серповидными эритроцитами. Некоторые люди рождаются с геном, приводящим к малокровию с серповидными эритроцитами - это болезнь крови, которая поражает многих выходцев из Западной Африки. Характерной особенностью этой болезни является то, что носители этого гена не страдают от болезненных последствий малярии, болезни, обычно распространяемой москитами. Хотя они могут заболеть малярией, этот ген приводит к такой мутации гемоглобина в их крови, что они становятся невосприимчивыми к ослабляющим побочным эффектам и последствиям малярии, приводящим к расстройству памяти, коме и смерти. Т.е. у серповидных эритроцитов есть очевидное эволюционное преимущество - учтите, что эволюция заботится не о продолжительности жизни особи, но о том, чтобы она прожила достаточно долго для передачи своих генов (у страдающих малокровием бывают кризисные периоды, сопровождаемые острой болью, так что выгода, конечно, сомнительна). В странах, где малярия является обычной причиной смерти, оказаться носителем подобного гена означает возможность прожить достаточно долго, чтобы оставить потомство. Дарвиновский естественный отбор в действии.
Беда операционных систем в том, что у всех у них одинаковый "генетический код", который делает их все и каждую в отдельности уязвимыми перед новыми атаками. Следовательно, нам надо сделать их разными, что может быть достигнуто с помощью смены базового адреса модуля. После этого DLL/EXE-файл окажется загруженным в другую точку виртуального адресного пространства.
Возвращаясь к Slammer'у, если бы я переместил базовый адрес sqlsort.dll на 0x41410000, моя система оказалась бы невосприимчивой к червю. Если будет написан другой червь, использующий команду "jmp esp" в kernel.dll, я опять окажусь уязвимым. Тогда я перемещаю базовый адрес kernel.dll. Далее очередной червь использует другую DLL, и я перемещаю и ее базовый адрес. В конце концов, я сдвигаю базовые адреса всех DLL, используемых SQL Server'ом, "мутируя" его "генетический код", и делая его существенно отличным от любой другой инсталляции SQL Server'а на планете. Фактически, если я сдвину базовые адреса для всех DLL и исполняемых файлов в системе, я оказался бы практически неуязвимым к данной атакой. Это не означает, что моя система получила иммунитет к уязвимостям с переполнением буфера - она просто оказалась невосприимчивой к атакам, их использующим. Для захвата системы, защищенной таким образом, потребовалось бы знание новых адресов загрузки для всех модулей.
Возникает вопрос, как просто сдвинуть базовые адреса DLL и EXE-файлов? Очень просто. Microsoft предусмотрела для этого отдельную функцию, ReBaseImage(), экспортируемую imagehlp.dll. При этом новый адрес должен быть кратен 64к. (Собственно, ровно этот механизм используется для разрешения конфликтов при загрузке DLL. Кроме того, в состав Visual Studio входит отдельная утилита ReBase.Exe, выполняющая ту же работу. - Прим.переводчика).
Осталась последняя проблема - Windows File Protection. После того как вы сдвинули базовый адрес DLL, вам необходимо скопировать ее файл поверх старого, но Windows File Protection вам этого не позволит. Для решения этой проблемы используйте функцию MoveFileEx с флагом MOVEFILE_DELAY_UNTIL_REBOOT. Это добавит значение "PendingFileRenameOperations" к ключу реестра HKLM\System\CurrentControlSet\Control\Session Manager\. Далее надо добавить еще одно значение типа DWORD "AllowProtectedRenames", установив его в 1, и перезагрузить систему. После перезагрузки будут загружены новые версии DLL с измененными базовыми адресами.
Например, вот результат работы listdlls после сдвига базовых адресов kernel32.dll и and ws2_32.dll:
Copyright (C) 1997-2000 Mark Russinovich http://www.sysinternals.com ---------------------------------------------------------------------------- WINLOGON.EXE pid: 208 Command line: winlogon.exe Base Size Version Path 0x01000000 0x2e000 \??\C:\WINNT\system32\winlogon.exe 0x77f80000 0x7b000 5.00.2195.5400 C:\WINNT\System32\ntdll.dll 0x78000000 0x46000 6.01.9359.0000 C:\WINNT\system32\MSVCRT.dll 0x4a4a0000 0xb1000 5.00.2195.6011 C:\WINNT\system32\KERNEL32.dll 0x77db0000 0x5b000 5.00.2195.5992 C:\WINNT\system32\ADVAPI32.dll 0x77d30000 0x71000 5.00.2195.5419 C:\WINNT\system32\RPCRT4.dll 0x54530000 0x13000 5.00.2195.4874 C:\WINNT\system32\WS2_32.dll .. ..
Теперь о том, почему я подчеркивал "практическую неуязвимость" системы. Для некоторых уязвимостей может оказаться достаточным перезаписать сохраненный адрес возврата, указатель на функцию или что-нибудь еще, умещающееся в нескольких байтах. Например, допустим, что сохраненный адрес возврата - 0x44784500, по адресу 0x44784536 расположена команда "jmp ebx", и ebx указывает на наш код. Тогда нам достаточно изменить адрес возврата всего на один байт - добавив 0x36. Т.е. знание базового адреса модуля в этом случае не понадобится. Однако, это может произойти настолько редко (если вообще), что не преуменьшает эффект от применения смещения адресов. Кроме того, возможны другие пути для обхода этого способа.
Некоторые идеи на тему предотвращения возможных будущих атак.
В качестве новых базовых адресов используйте адреса вида 0x**000000 или 0x00**0000. Наличие NULL в большей части адресного пространства может помочь (конечно, это мало что меняет в случае юникодных переполнений).
Убедитесь, что хотя бы одна (основная) DLL имеет базовый адрес 0x00119400. Это приведет к тому, что обычное место для стека 0x00120000 окажется занятым, и система будет вынуждена найти для него новое место. Идея, думаю, ясна.
ReBaseImage(), http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/base/rebaseimage.asp
MoveFileEx(), http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/movefileex.asp
обсудить | все отзывы (0) | |
[24307; 7; 6.85] |
|
|