Хочу отметить сразу, в этой статье речь пойдет о приеме преодоления защиты брандмауэра, давно известном компьютерным злоумышленникам (и не только им, поскольку я вот тоже этот прием знаю, хотя злоумышленником не являюсь ). Проблема в том, что очень часто старые и давно известные «дыры» плохо поддаются устранению. Именно об одной такой, широко известной, но до сих пор не решенной проблеме и возможных способах ее решения и пойдет далее речь.
DLL injection на службе spyware Представим себе простую и весьма распространенную ситуацию: spyware-программа периодически соединяется с неким сайтом, используя, например, протокол HTTP, и передает на этот сайт некую информацию, которую пользователь предпочел бы сохранить в секрете. Кроме программ удаления spyware, эффективность которых зависит от обстоятельств, помочь в данной ситуации может брандмауэр, не допускающий выхода в Сеть программ, которым это не положено, и позволяющий пользователю запретить выход в Сеть подозрительным программам. Но и spyware-программы (точнее – их создатели) могут пойти на хитрости. Одна из таких хитростей – использовать для выхода в Интернет другую программу, которой доступ к Сети заведомо разрешен. Одной из таких программ обычно является Internet Explorer. Программа spyware может использовать IE через интерфейс автоматизации. Этот способ получил название «process hijacking» и современные брандмауэры умеют с ним бороться. Да и интерфейс автоматизации IE позволит spyware-программе далеко не все, что ей хотелось бы. Но существует другой способ использования spyware-программами «доверенных» процессов в своих целях. Способ этот связан с техникой так называемой DLL injection (внедрение DLL). Внедрение DLL – классическая техника манипуляции процессами, описанная в столь же классической книге Джеффри Рихтера. Суть метода заключается в том, что в адресное пространство процесса загружается сторонняя DLL. При загрузке DLL процесс вызывает функцию DLLMain, которая может выполнить любой код в адресном пространстве процесса, например, подменить процедуру главного окна процесса своей собственной. При этом, после того, как код был внедрен, его, с точки зрения системы, невозможно отличить от собственного кода процесса, и все действия внедренного кода рассматриваются как действия процесса. Вообще-то внедрение DLL и замена оконной процедуры часто используются в благих целях. Но этими методами могут воспользоваться злоумышленники. Существует три способа внедрения DLL в другой процесс (мы не рассматриваем модификацию кода в образе программы в файле на диске). Самым «подходящим» для злоумышленника является внедрение DLL с помощью удаленного потока. Подобная атака известна давно и описана во многих источниках, например здесь: wwwsecurityfocus.com/archive/1/313695/ 2004-03-07/2004-03-13/0 Рассмотрим практический пример. Далее приводится текст консольной программы, которая заставляет один из запущенных в системе экземпляров Internet Explorer загрузить некую библиотеку C:Mylib.dll. #include "stdafx.h" #include #include #include void Inject(unsigned long PID) { char * fname = "C:Mylib.dll"; void * hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE, false, PID); int cch = strlen(fname) + 1; void * RemBlock = VirtualAllocEx(hProcess, NULL, cch, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, RemBlock, (PVOID) fname, cch, NULL); PTHREAD_START_ROUTINE ThreadProc = (PTHREAD_START_ROUTINE) GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA"); void * RemThread = CreateRemoteThread(hProcess, NULL, 0, ThreadProc, RemBlock, 0, NULL); } int main(int argc, char* argv[]) { PROCESSENTRY32 PE; void * hPS = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PE.dwSize = sizeof(PROCESSENTRY32); Process32First(hPS, &PE); do { if (!strcmp("IEXPLORE.EXE", PE.szExeFile)) { Inject(PE.th32ProcessID); break; } } while (Process32Next(hPS, &PE)); CloseHandle(hPS); return 0; } Что происходит, вернее, что может произойти, при загрузке библиотеки в адресное пространство IE, иллюстрирует следующий код библиотеки C:Mylib.dll: #include "stdafx.h" #include "windows.h" ... BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { // Ваш полезный или зловредный код здесь } return TRUE; } Естественно, что никакие встроенные средства безопасности IE не могут предотвратить зловредных действий, выполняемых внедренным кодом, ведь все механизмы защиты браузера ориентированы на внешние интерфейсы, будь то Java илиActiveX, а в данном случае враг оказывается внутри. Для того, чтобы проверить, как все это работает, я написал (совершенно безвредную) библиотеку Mylib.dll, которая считывала стартовую страницу одного Интернет-сайта. Брандмауэр Sygate Personal Firewall не заметил ни внедрения библиотеки в IE, ни, естественно, ее действий. Тогда я решил пошалить и внедрил ту же библиотеку в редактор notepad. На этот раз брандмауэр «очнулся» и выдал сообщение. Однако в данном брандмауэр «засек» несанкционированные действия только потому, что notepad.exe не числился в списке приложений, которым разрешено выходить в Сеть. В упомянутом выше Web-документе, авторство которого, между прочим, принадлежит разработчикам Sygate Personal Firewall, признается, что общего способа защиты от описанной атаки не существует. Sygate Personal Firewall считывает контрольные суммы исполнимых файлов и проверяет список модулей, загружаемых во время запуска процесса, но он ничего не может сделать с внедрением DLL во время выполнения процесса. Тем не менее некоторые лекарственные средства найти можно. В частности, мной была разработана система, ограничивающая возможности внедрения сторонних DLL в процессы и другие связанные с этим зловредные действия. Но, очевидно, нам нужно общее решение. Общее решение Поскольку на данный момент таковое отсутствует, остается только рассуждать о том, что могла бы сделать Microsoft для повышения безопасности своих ОС. Внимательный читатель, знакомый с программированием, заметит, что описанный трюк возможен благодаря наличию в составе Windows API таких функций как CreateRemoteThread и WriteProcessMemory. Читатель может задаться вопросом о целесообразности наличия этих функций и о целесообразности самой возможности внедрения сторонних DLL в выполняющиеся в системе процессы. Но тут не все так просто, как кажется. Функция CreateRemoteThread и ей подобные, равно как и возможность внедрения DLL, при всей потенциальной уязвимости, которую они создают, были введены сознательно и «не от хорошей жизни». Microsoft должна была предоставить сторонним разработчикам возможность модифицировать поведение компонентов системы, не раскрывая их исходных текстов. Менее очевидно, что описанный трюк становится возможным также благодаря тому факту, что при загрузке процесса в конкретной системе, системные модули, такие как kernel32, располагаются в виртуальном адресном пространстве каждого процесса с одним и тем же значением базового адреса. Именно благодаря этому мы можем быть уверены, системная функция LoadLibraryA будет иметь один и тот же адрес (точку входа) во всех процессах, выполняющихся в данной системе (что можно было бы исправить на уровне операционной системы, как это делается сейчас в Linux). Мне возразят, что фиксированное расположение системных модулей в адресном пространстве процесса учитывается некоторыми программами, на что я отвечу, что это – результат неграмотного и непереносимого проектирования (в Windows 64-бит расклад оперативной памяти – другой, значит такие программы придется переписывать). Большинство же программистов совершенно не интересуется тем, где находится нижняя граница адресного пространства системных модулей, а многие даже и не знают – где. Но не это главное. DAC и MAC От многопользовательских систем 80-х годов Windows NT унаследовала дискреционный (добровольный) контроль доступа (DAC), в то время как современные системы безопасности (SELinux, TrustedBSD) все чаще реализуют мандатный (обязательный) контроль доступа (MAC). Различий между DAC и MAC много, я остановлюсь на одном. При дискреционном контроле доступа каждый процесс, запущенный пользователем, обладает всеми правами пользователя, в том числе доступом ко всем объектам файловой системы, к которым имеет доступ сам пользователь. Легко понять, как эта возможность может использоваться spyware и подобными им программами. Мандатный контроль доступа исходит из принципа «наименьших необходимых привилегий». В соответствии с этим принципом, например, каждая программа, запущенная пользователем, обладает только теми правами, которые ей необходимы, и может получить доступ только к тем файлам и каталогам, которые ей действительно нужны. Например, пери мандатном контроле доступа IE мог бы быть настроен таким образом, чтобы ему было разрешено записывать файлы только в некоторые каталоги каждого пользователя, и считывать (только считывать) необходимые файлы из некоторых других каталогов. Подчеркиваю, контроль доступа реализуется не процессом, а ОС, поэтому никакое нарушение целостности процесса не смогло бы изменить его права. Подобная система, в сочетании с рандомизацией расположения компонентов процесса в адресном пространстве (подобные модели уже давно работают в UNIX-системах), существенно бы ограничила возможности spyware и других зловредных программ. Мандатный контроль доступа можно было бы реализовать в существующих системах Windows 2000/XP/2003 с помощью, например, инсталлируемых драйверов файловой системы (IFS), однако решение этой задачи потребует усилий не одного, а группы програмистов.