Математическая морфология.
Электронный математический и медико-биологический
журнал. - Т. 7. -
Вып. 4. - 2008. - URL:
http://www.smolensk.ru/user/sgma/MMORPH/TITL.HTМ
http://www.smolensk.ru/user/sgma/MMORPH/N-20-html/TITL-20.htm
http://www.smolensk.ru/user/sgma/MMORPH/N-20-html/cont.htm
БЕЗОПАСНОЕ ПРОГРАММИРОВАНИЕ В API WIN32
Ó 2008 г. Малашенкова И. В., Панкратова Е. А., Семенова О. В.
В статье содержится обзор функций Win 32 API, некорректное использование
которых приводит к ошибкам и делает возможным проведение сетевых атак. Небезопасные
функции сгруппированы по видам уязвимостей,
к которым приводит некорректное использование функций, и предложены методы создания защищенного
программного кода.
Ключевые слова: функции Win32 API, сетевые атаки, троянские программы.
В библиотеках различных языков
программирования и в API операционных систем имеется ряд функций, некорректное
использование которых приводит к ошибкам и делает возможным проведение сетевых
атак. Разработчикам программного обеспечения для написания безопасного кода необходимо
хорошо представлять, к каким последствиям может привести использование той или
иной «небезопасной» функции.
«Небезопасные» функции условно разбиваются
на следующие группы:
1)
функции,
некорректно, работающие с буферами памяти и указателями;
2)
функции,
ненадежные по отношению к манипулированию именами;
3)
функции,
позволяющие запускать процессы и выполнять DLL на удаленных компьютерах;
4)
функции
передачи оконных сообщений;
5)
API-функции
олицетворения;
6)
функции,
требующие монопольного доступа к ресурсам;
7)
сетевые API-функции;
8)
функции для
работы с файлами, наследующие ACL по умолчанию.
Описание
функций первой группы приведено в таблице 1 [1].
Функции |
Назначение |
Уязвимости |
strcpy, lstrcpy и аналогичные функции Delphi, объявленные в модуле SysUtils |
Копирование строки в буфер |
Функции не проверяют размер
буфера-приемника и значение указателей, не отметают указателей на nil (null) или с другими некорректными
значениями. Если буфер-источник не завершается нулем, результат такой функции
непредсказуем. |
strcat, lstrcat, и т.п. |
Добавление одной строки к другой |
Те же
недостатки, что и в предыдущем случае. Этим функциям необходимо, чтобы
буферы — источник и приемник — завершались нулем. |
strlen, lstrlen, и т.п. |
Данные функции возвращают длину строки в
байтах (ANSI
версия) или в символах (UNICODE версия) |
Данные функции в состоянии корректно обработать
буфер только при условии, что он завершается нулем. Их вызов не приводит к
«эксплуатируемому» переполнению буфера, но способен вылиться в ошибку
нарушения доступа, если функция попытается прочитать память, расположенную за
пределами буфера. |
strcmp, lstrcmp и т.п. |
Выполняет сравнение двух строк |
Сравниваемые строки должны заканчиваться
двоичным нулем. Функция не проверяет корректность значения указателей. |
Перечисленные
в таблице 1 уязвимости позволяют злоумышленнику реализовать ряд атак, таких как нарушение целостности и нарушение
работоспособности.
Поэтому при
разработке программного обеспечения следует:
· проверять корректность указателей на
строки;
· размер строки ( данный размер не должен
проверять размер буфера);
· наличие завершающего строку двоичного
нуля.
Описание функций второй
группы приведено в таблице 2 [2].
Функция |
Описание |
CreateDirectory |
Создание новой папки |
CreateEvent |
Создание объекта «Событие». Если
объект с указанным именем уже существует,
то функция выполняет открытие существующего объекта |
CreateFile |
Создание или открытие файла |
CreateFileMapping |
Создание или открытие файла,
проецируемого в память |
CreateJobObject |
Создание или открытие объекта ядра
«Задание» |
CreateMailslot |
Создание или открытие почтового ящика
Windows |
CreateMutex |
Создание или открытие объекта ядра «Mutex» |
CreateNamedPipe |
Создание или открытие именованного
канала |
CreateSemaphore |
Создание или открытие объекта ядра
«Семафор» |
CreateWaitableTimer |
Создание или открытие объекта ядра
«Ожидаемый таймер» |
К
данной группе относятся также классы, инкапсулирующие эти функции.
Любой вызов API-функции, в ходе которого создается нечто,
имеющее имя, подвержен атакам с манипулированием
именами (name-squatting), так как взломщик в
состоянии угадать, какой файл или иной объект будет создан, и заблаговременно
создать и «подсунуть» свой с таким же именем.
Например, если во время
редактирования текстовый процессор создает файл в папке c:\temp с именем, которое легко предугадать,
взломщик может заранее создать такой файл с разрешениями на чтение и затем
манипулировать моим файлом.
Возможна и другая атака,
которая состоит в том, что взломщик создает ссылку на файл, на запись которого
у него нет прав, и заставляет администратора удалить файл или, того хуже,
изменить разрешения.
При использовании данных
функций в разрабатываемом программном обеспечении следует:
·
Предоставить
каждому пользователю его «личное» временное пространство, в Microsoft Windows 2000 и более поздних это папка Documents and Settings. Если нужно создавать временные файлы или каталоги в общедоступной
области, лучше всего генерировать действительно случайные имена;
·
При создании
файлов установить флаг CREATE_NEW,
который заставит функцию завершиться с ошибкой, если файл уже существует.
· Никогда не следует предполагать, что файл
или каталог не существуют, даже если проверили его отсутствие. Взломщик может
воспользоваться временем между проверкой существования и созданием файла.
Несмотря на то, что временной промежуток слишком мал, множество успешных
разрушающих атак были проведены на UNIX-системы в условиях конкуренции за ресурсы, и имеется
несколько свидетельств об успешных нападениях такого типа на Windows.
Функции третьей группы
(функции, позволяющие запускать процессы и выполнять DLL на удаленных компьютерах) уязвимы для
«Троянских программ», то есть при некорректном использовании данных функций
становится возможным загрузка и исполнение приложением «постороннего» кода.
Описание функций третьей
группы приведено в таблице 3 [2].
Функции, позволяющие запускать процессы и выполнять DLL на удаленных компьютерах
Функции |
Назначение |
Уязвимости |
CreateProcess (NULL,...) |
Создание процесса |
В данных функциях один из аргументов — путь к приложению, второй
— командная строка. Если путь к приложению указать как nil (null), а в
командной строке содержится пробел в пути к приложению, возможно выполнение
«не того» приложения. Например, если аргумент С:\Program Files\MyApp\MуАрр.ехе, то при наличии соответствующего файла
выполнится программа C:\Progrат.ехе. |
CreateProcessAsUser |
Создание процесса в контексте указанного пользователя |
|
WinExec |
Запуск внешней программы |
Данная функции ведет себя так же, как CreateProcess(NULL,
). Кроме того, функция WinExec позволяет указывать путь к файлу длиной не
более 80 символов |
ShellExecute |
Запуск внешней программы и открытие документа |
Данная функции ведет себя так же, как CreateProcess(NULL,
). |
LoadLibrary |
Загрузка DLL в адресное пространство процесса |
Во многих версиях Windows при загрузке файлов поиск начинается с текущего
каталога. Если попытаться загрузить DLL, указав неполный путь (например file.dll вместо c:\dir\dir\ftle.dll), программа сначала просмотрит текущий каталог, и если там
окажется подложный файл, то загрузится именно он. В Windows XP SP1 и Windows .NET Server 2003 подобной проблемы не возникает,
поиск в них выполняется по-другому - вначале просматриваются системные
каталоги и только затем текущий |
LoadLibraryEx |
Загрузка DLL в адресное пространство процесса |
|
SearchPath |
Поиск файла |
При использовании данных
функций в разрабатываемом программном обеспечении следует:
·
При использовании функций CreateProcess (NULL,...), CreateProcessAsUser,
WinExec, ShellExecute всегда указать путь к приложению в первом аргументе;
· При
использовании функции WinExec проверять длину пути, чтобы она не превышала
80 символов;
· При использовании функций LoadLibrary, LoadLibraryEx и SearchPath всегда указывать полный путь.
Функции
четвертой группы (функции
передачи оконных сообщений) SendMessage и PostMessage являются одними из наиболее часто
используемых функций ОС Windows [2]. Для
передачи сообщения необходимо знать только дескриптор окна получателя. Но
некоторые стили окна и типы элементов
управления представляются опасность с точки зрения безопасности:
·
Сообщения ТВ_GETBUTTONTEXT, LVM_GETISEARCHSTRING и TVM_GETISEARCHSTRING копируют данные из элемента управления в буфер,
следовательно, необходимо проверять, что IParam установлен в nil, чтобы сначала получить размер буфера.
·
TTM_GETTEXT — не существует способа ограничить размер буфера; предполагается,
что размер источника не превышает 80 символов.
·
СЕ_GETLBTEXT, CB_GETLBTEXTLEN, SB_GETTEXT, SB_GETTEXTLENGTH, SB_GETTIPTEXT, LB_GETTEXT и LB_GETTEXTLEN — в общем
случае следует прежде всего отправлять сообщение GETTEXTLENGTH, чтобы узнать размер входной строки. Однако
это не всегда избавляет от ошибок: размер данных может измениться в промежутке
между определением размера и приемом текста, в результате чего возникнет
переполнение. Кроме того, пока не существует способа запросить длину текста
всплывающей подсказки (ToolTip) строки состояния при посредстве сообщения SB_GETTIPTEXT.
·
ES_PASSWORD — в окне этого стиля в поле ввода все вводимые символы отображаются
в виде звездочек (*). Необходимо очищать буфер, который передается функциям GetWindowText или SetWindowText, чтобы пароль не оставался в памяти открытым
текстом.
Функции
пятой группы (API-функции
олицетворения) описаны в таблице 4 [3].
Олицетворение
(impersonation) – мощное средство, часто
используемое в модели защиты Windows 2000. Олицетворение также применяется в модели
программирования клиент-сервер. Например, серверное приложение может
экспортировать ресурсы (файлы, принтеры
или базы данных). Клиенты, которые хотят обратиться к этим ресурсам посылают
серверу запрос. Получив запрос, сервер должен убедиться, что у клиента есть
разрешение на выполнение над ресурсом запрошенных операций. Windows 2000 в таких случаях
предоставляет серверу сервисы олицетворения.
Олицетворение позволяет серверу временно заимствовать профиль защиты клиента, запрашивающего
ресурс. После этого сервер может обращаться к ресурсам от имени клиента. Обычно
серверу доступен долее широкий круг ресурсов, чем клиенту и при олицетворении
сервер может терять часть исходных прав доступа [3].
API-функции олицетворения
Функция |
Описание |
RpcImpersonateClient |
Вызов серверным потоком клиентской удаленной
процедуры. Если сервер взаимодействует с клиентом через RPC, с помощью данной процедуры сервер
выдает запрос на олицетворение. |
ImpersonateLoggedOnUser |
Вызов потока, имеющего другие атрибуты
секретности, чем у вызывающего потока |
ImpersonateNamedPipeClient |
Олицетворение через именованный
канал. С помощью данной функции
сервер, взаимодействующий с клиентом через именованный канал подменяет собой
пользователя на другом конце канала |
ImpersonateDdeClient |
Если сервер взаимодействует с клиентом
через DDE, с помощью данной процедуры сервер
выдает запрос на олицетворение. |
ImpersonateSecurityContext |
С помощью данной функции пакет SSPI (Security Support Provider Interface) может олицетворять своих клиентов |
ImpersonateSelf |
Поток создает маркер олицетворения
просто как копию маркера своего процесса |
SetThreadToken |
Выполнение олицетворения для потока |
SetSecurityDescriptorDacl(...,...,NULL,...) |
Создание дескриптора защиты |
При выполнении функций, перечисленных в таблице 4 возможно появление
следующих уязвимостей:
·
Если вызов
функции олицетворения по каким-либо причинам терпит сбой, олицетворения не
происходит и запрос выполняется в контексте безопасности вызывающего процесса.
Таким образом, становится возможным превышение полномочий, если процесс
работает в контексте высоко привилегированной учетной записи, например SYSTEM или члена группы администраторов. Поэтому
очень важно всегда проверять возвращенное значение. Если вызов завершился
неудачно, немедленно следует прервать выполнение клиентского запроса.
·
SetSecurityDescriptorDacl(...,...,NULL,...) —
не рекомендуется создавать дескрипторы
защиты, имеющие нулевые (NULL) DACL,
то есть, при создании которых третий параметр (pDacl) равен NULL. Такая
DACL никак не защищает
объект. Более того, ничто не мешает взломщику определить АСЕ запись Full Control: Deny для группы Everyone, что запретит доступ к объекту всем, в
том числе и администраторам.
Выполнение функций шестой группы
(функции, требующие монопольного доступа к ресурсам) может привести к возникновению условий для отказа в обслуживании
(DoS атака), особенно
при недостатке памяти [2].
К таким функциям относятся:
·
InitializeCriticalSection (инициализация критической секции) и EnterCriticalSection (вход в критическую секцию), которые в условиях недостатка памяти инициируют исключения, и если
исключение не перехватывается, приложение завершается аварийно. Взамен
рекомендуется использовать функцию InitializeCriticalSectionAndSpinCount. Причем, EnterCriticalSection не инициирует исключения в Windows XP, Windows .NET Server и последующих ОС. Также необходимо
следить, чтобы не выполнять блокирующих сетевых вызовов из критической секции
или других блокируемых участков программы. Код внутри критической секции
следует проверять с особой тщательностью. Любые исключения должны
перехватываться в самой критической секции, в противном случае программа
«вывалится» в обработчик исключения до вызова LeaveCriticalSection. В критической секции надо выполнять лишь необходимый минимум
операций.
·
TerminateThread (завершение потока) и TerminateProcess (завершение процесса)
— обе эти функции следует вызывать только в
крайнем случае. Особенно TerminateThread. Память, дескрипторы и системные ресурсы, которыми владел поток, не
очищаются и не освобождаются.
Некорректное использование функций
седьмой группы может вызвать ошибки при выполнении сетевых приложений.
К таким функциям относятся следующие:
·
bind (определение номера порта и IP-адреса
по которому сервер будет принимать
данные) — создавая привязку к INADDR_ANY (все
интерфейсы) — есть опасность, что сервер станет прослушивать все имеющиеся сетевые интерфейсы;
·
recv (получение данных по сети) — у этой функции три возможных возвращаемых значения, и не всегда
все они обрабатываются. На ошибку указывает — 1, при корректном разрыве соединения (или достижении
конца буфера) возвращается 0, положительное
число сигнализирует об удачном завершении. Функция recv, работающая в
блокирующем сокете может навсегда «подвесить» поток.
·
send - отправляет данные в сокет, с которым
установлено соединение. Не следует считать, что все данные успешно переданы,
если send не возвращает ошибки. Соединения иногда разрываются между
вызовами connect и send. Кроме
того, если злоумышленник намеренно задал размер окна TCP очень маленьким, существует лишь один
путь заметить это — если при вызове send возникнет тайм-аут. Если сокет является блокирующим или не
проверяется значение, возвращаемое функцией, есть вероятность проведения атаки отказ в обслуживании.
К функции восьмой группы относятся CopyFile и MoveFile. Возможные проблемы с этими функциям связаны
с тем, как они работают с ACL. Файлы, копируемые вызовом CopyFile, наследуют ACL по умолчанию каталога, в который
копируются, а файлы, переносимые посредством MoveFile, сохраняют
свои ACL. При работе с
данными функциями необходимо проверять, что объект используется только локально
только локально и н и в коем случае
не устанавливать флаг CLSCTX_REMOTE_SERVER.
В
данной статье был рассмотрен ряд функций, некорректное выполнение которых может
привести к изъянам защиты, и предложены методы, позволяющие избежать возможных
нарушений безопасности.
1.
Ховард М., Лебланк
Д. Защищенный код. Пер. с англ. –
2-е изд., испр. М.: Издательско-торговый дом «русская редакция»,
2004. – 704 стр.: ил.
2.
Рихтер Дж. Windows для профессионалов:
создание эффективных Win32-приложений
с учетом специфики 64-разрядной версии Windows. ./ Пер. с англ. – 4-е изд. – СПб.: Питер; М.:
Издательско-торговый дом «Русская редакция», 2004 – 749 с.:ил.
3.
Соломон Д., Руссинович
М. Внутреннее устройство Microsoft Windows
2000. Мастер-класс./ Пер. с англ. –
СПб.: Питер; М.: Издательско-торговый дом «Русская редакция», 2001 – 752 с.:ил.
SAFE
PROGRAMMING USING API WIN32
Malashenkova I. V., Pankratova H. A., Semenova O. V.
The article
contains a review of Win 32 API-functions, which’s incorrect usage leads to
mistakes and makes successful network attacks possible. Unsafe functions has been
grouped together by types of
brittleness, can be caused by incorrect usage of the functions, and
techniques of secured programming
code’s creation are offered.
Key words: Win 32 API-functions, network attacks, Troyan Horses.
Поступила в редакцию 8.12.2008.