На главную | Содержание | Назад | Вперёд
Наши друзья

 

 

Переполнение буфера и Java

Широко распространено мнение, что Java-код не подвержен проблемам, связанным с переполнением буфера. В целом это соответствует действительности. Поскольку в Java используется модель управления памятью, в которой обеспечивается безопасность типов, то невозможно "нырнуть" в одном объекте и "вынырнуть" в другом. Это блокирует многие атаки на переполнение буфера. И действительно миллионы долларов были потрачены на создание виртуальной машины Java с целью сделать среду исполнения программного обеспечения неуязвимой для многих классических атак. Однако, как мы уже знаем, любое предположение о полной безопасности объекта является ложным (и требует пересмотра). Со структурной точки зрения J VM может быть безукоризненна, но успешные атаки на Java-технологии не раз обсуждались в форумах хакеров.
Программы атаки на системы на основе Java обычно являются атаками с использованием свойств языка (атака "смешение типов") и атаками с использованием доверительных отношений (ошибки при использовании цифровой подписи аплетов), однако иногда возможны даже атаки на переполнение буфера против Java-программ. Проблема переполнения буфера чаще всего возникает в программах поддержки, которые являются внешними по отношению к JVM.
Сама JVM часто пишется на языке С для конкретной платформы, т.е. без должного внимания к деталям реализации машина JVM может сама оказаться уязвимой для атак на переполнение буфера. Однако стандартная реализация JVM от компании Sun Microsystems проверена достаточно хорошо, и статические проверки, которые выполянются для вызовов уязвимых функций, не позволяют получить каких-либо полезных результатов.
Кроме JVM, многочисленные проблемы переполнения буфера характерны для систем, в которых используется Java, и конкретно для программ поддержки работы с Java. В качестве примера рассмотрим систему управления реляционными базами данных Progress, в которой встроенная программа jvmStart предназначена для запуска виртуальной Java-машины. В jvmStart есть ошибка проверки правильности входных данных, предоставленных в командной строке (ошибка строки форматирования). Данные включаются в строку через функцию printf () как аргумент строки. Это еще раз подтверждает идею, согласно которой разработчики программного обеспечения должны рассматривать всю систему в целом, а не просто создавать отдельные компоненты. Хотя наиболее важные компоненты могут быть надежно защищены, но большинство программных систем настолько надежны, насколько надежен их самый уязвимый компонент. Что касается системы Progress, слабым звеном оказывается код обслуживающей программы.
Во многих службах на основе Java используются компоненты и службы, которые написаны на языках, не обеспечивающих безопасность типов, например на С и C++. В таких ситуациях собственно использование Java-служб предоставляет доступ к значительно более уязвимым компонентам C/C++. При этом атака может быть проведена с помощью серверных протоколов, распределенных транзакций, хранимых процедур, которые обращаются к службам операционной системы и вспомогательным библиотекам.
Совместное использование Java и C/C++
Интеграция Java-систем с обслуживающими библиотеками, написанными на C/C++, является широко распространенной практикой. Java поддерживает загрузку библиотек DLL и библиотек программного кода. Экспортированные из библиотек функции затем непосредственно могут использоваться из Java. При подобной интеграции возникает реальная вероятность того, что переполнения буфера и другие недостатки в поддерживающих библиотеках будут использованы для проведения атак. Рассмотрим Java-программу, которая поддерживает интерфейс для работы с низкоуровневыми пакетами (raw packet). Такая Java-программа может, например, проводить анализ пакетов и создавать низкоуровневые пакеты. Такие действия вполне возможны после загрузки библиотеки пакетов из Java-программы.
public class MyJavaPacketEngine extends Thread {
public MyJavaPacketEngine () {
>
static {
System.loadLibrary("packet_driver32");
}
}
Представленный выше Java-класс загружает библиотеку DLL под названием packet_driver32.DLL. После этого вызовы могут осуществляться непосредственно к этой библиотеке. Предположим, что Java-программа позволяет задать адаптер для выполнения действий с пакетами. А теперь рассмотрим, что произойдет, если программный код внутри библиотеки DLL передает в буфер строку для привязки к адаптеру, не ограничивая при этом размер входных данных.
PVOID PacketOpenAdapter(LPTSTR p_AdapterName)
{
wsprintf(lpAdapter->SyimbolicLink, TE»OT«"\\\\.\\%s%s"J, DOSNAMEPREFIX, *> p_AdlaptteriNia«ee ) ;
}
Здесь вполне вероятно может произойти переполнение буфера. Независимо от того, связано ли это каким-либо образом с Java или нет, но уязвимые места в ядре системы все равно остаются.
Хранимые процедуры и библиотеки DLL
Хранимые процедуры значительно расширяют возможности работы с базами данных и позволяют делать многие дополнительные вызовы к функциям "за пределами" системы управления базой данных. В некоторых случаях хранимые процедуры используются для вызовов функций из библиотечных модулей, созданных на небезопасном языке, например С. А дальше вы уже знаете, что происходит: выявляются уязвимые места, связанные с переполнением буфера, и проводятся успешные атаки.
Особенно много подобных уязвимых мест в интерфейсе между базой данных и модулями, написанными на других языках программирования. Проблема в том, что "границы доверия" подвергаются изменениям. В результате то, что кажется вполне безопасным и разумным для Java, может привести к разрушительным последствиям при выполнении программы на С в реальном времени.

 

На главную | Содержание | Назад | Вперёд
 
Яндекс.Метрика