Научная статья на тему 'Преобразование программного кода для использования уязвимостей переполнения буфера'

Преобразование программного кода для использования уязвимостей переполнения буфера Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
429
67
i Надоели баннеры? Вы всегда можете отключить рекламу.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Аграновский А. В., Карнюша С. И., Селин Р. Н.

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Преобразование программного кода для использования уязвимостей переполнения буфера»

А.В. Аграновский, С.И. Карнюша, Р.Н. Селин

Россия, г. Ростов-на-Дону, ФГНУ НИИ «Спецвузавтоматика»

ПРЕОБРАЗОВАНИЕ ПРОГРАММНОГО КОДА ДЛЯ ИСПОЛЬЗОВАНИЯ УЯЗВИМОСТЕЙ ПЕРЕПОЛНЕНИЯ БУФЕРА

В настоящее время количество различного используемого программного обеспечения увеличивается большими темпами, что не всегда можно сказать о его качестве, надежности и безопасности. Существующие на сегодняшний день технологии и средства разработки не позволяют отследить и ликвидировать ошибки в программном обеспечении, связанные с так называемым "человеческим фактором". Это не сказывается положительным образом на безопасности программного кода, используемого конечными потребителями. С другой стороны, приемы, которыми пользуются злоумышленники, при атаках на уязвимые сетевые узлы совершенствуются. Чтобы организовать соответствующую защиту своих программных продуктов, проводить их тестирование, следует хорошо понимать методы и приемы, применяемые злоумышленниками.[1,2] Рассмотрим метод преобразования программного кода, позволяющий реализовывать технику "переполнения буфера" даже в том случае, если входные данные приложения подвергаются статической фильтрации.

Образ памяти процесса в архитектуре процессоров семейства x86

Типичный образ процесса, выполняющаяся в оперативной памяти выглядит как указано на рис.1. В порядке возрастания адресов обычно располагаются сегмент кода, затем сегмент данных, куча и сегмент стека.

Существует две основные регламентированные операции работы со стеком:

- PUSH - записать значения стек, и декремент указатель стека (ESP);

- POP - извлечение значение и инкремент указатель стека (ESP).

<5 EIP t % ESP 9

Код Данные Куча Стек

Направление роста адресов

Рис. 1. Образ памяти выполняющейся программы

Для вызова подпрограммы современными компиляторами обычно производится набор следующих действий:

- сохранение значения базового регистра в стек PUSH EBP;

- изменение базового регистра MOV EBP, ESP;

- выделение места в стеке под локальные переменные SUB ESP, size;

- сохранение в стеке адреса возврата из процедуры и передача управления подпрограмме по адресу proc_addr CALL proc_addr;

Выход из подпрограммы производится в обратном порядке, с передачей управления вызывающей процедуре командой RET. Пусть в некоторый момент времени выполняется одна из процедур, имеющая ряд локальных параметров в стеке. Если по адресу одной из локальных переменных процедуры записать достаточно длинный массив данных, то произойдет затирание некоторых локальных переменных текущей процедуры, старое значение регистра EBP и адреса возврата (на рис.2 стрелкой обозначено направление затирания, V1, V2, V3, V4 - некоторые локальные переменные). В результате, после завершения выполнения текущей процедуры инструкция RET передаст управление уже по другому адресу.

ESP

Локальные переменные процедуры

XXX V1 V2 V3 V4 Старый EBP Адрес возврата XXX Г

1 II 1 1 "

у

Стек

Рис. 2. Расположение элементов в стеке перед передачей управления процедуре

В такой ситуации чаще всего происходит аварийное завершение программы, в результате того, что она обращается к недопустимой странице памяти, однако, если подобрать длину и данные массива, то возможно перезаписать адрес возврата и изменить текущий ход выполнения программы, выполнив почти произвольные программные инструкции. Описанная техника является основой большинства атак на программное обеспечение, в которых используется "переполнение локального буфера" (или "buffer overflow"). Написание жизнеспособного кода оказывается весьма сложной задачей. Это объясняется рядом факторов:

- не всегда в исполняемой программе можно найти достаточную по размерам область памяти;

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

- некоторые аппаратные платформы не позволяют выполнять процессорные инструкции, находящиеся в сегменте стека;

- программы используют, как правило, ввод текстовых данных, с применением символьных фильтров. Их наличие делает невозможным использование процессорных инструкций с определенными кодами. Например, пропускаются только символы с кодами с 0x20 по 0x7E.

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

Можно предложить два подхода к решению данной задачи:

- использование альтернативного набора инструкций процессора;

- использование специализированного "кодировщика".

Использование альтернативного набора инструкций процессора

В первом случае весь шелл-код следует реализовывать лишь при помощи доступного (ограниченного) набора процессорных инструкций. В продолжении статьи будут представлены механизмы обхода этого ограничения, в случае использования в уязвимой программе наиболее употребительных фильтров, пропускающих только символы с кодами с 0x20 по 0x79. Ниже приведен перечень интересующих нас инструкций процессоров семейства x86 с кодами, находящимися в указанном "легальном" диапазоне:

Код

операции Символ Инструкция

2D '-' sub

30...35 '0'-'5' Семейство команд xor

39 '9' cmp

41 - 47 'A'-'G' inc...

48 - 4F H'-'O' dec.

50 - 57 'P'-'W' push...

58 - 61 'X'-'a' pop.

66 'f o16: (Замена разм. операнда)

68 <32бит значение> 'h' push <32бит знач.>

6A <8бит значение> 'j' push <8бит знач.>

70 -7A 'p'-'z' Семейство команд перехода jmp

В данном списке нет инструкций "MOV", "ADD". Есть несколько вариантов инструкций вычитания (SUB), инкремента и декремента регистров (INC, DEC). Инкрементировать регистр EAX также напрямую невозможно. Есть команды управления стеком. Существует ряд приемов, позволяющих выполнять определенные операции, при помощи ограниченного количества доступных процессорных инструкций. Некоторые из них описаны ниже:

1) MOV eax,VALUE - обнуление регистра EAX

push 'aaaa' 'a' 'a' 'a' 'a'

pop eax EAX будет содержать двойное слово 'aaaa'.

xor eax,'aaaa' EAX теперь содержит 0.

2) MOV reg1,reg2; XCHG reg1,reg2 - запись значения одного регистра в другой или обмен значениями. Необходимо положить в стек значения регистров в нужном порядке, а затем восстановить командой popad.

push eax push ecx push edx push ebx push ebp push esi push edi

popad Получение всех значений

и.т.д.

При помощи отладчика можно убедиться, что данный код транслируется в допустимую последовательность [3]. Использование на практике данной техники зачастую оказывается сложной задачей. В этой ситуации помогает другой способ обхода символьных фильтров - использование специального "кодировщика". Использование специального "кодировщика" шелл-кода Суть данного подхода его заключается в том, что основной шелл-код реализуется с полным необходимым набором процессорных инструкций, но перед передачей уязвимой процедуре специальным образом кодируется. Задача кодирования состоит в преобразовании исходного шелл-кода в последовательность байта, которая не будет содержать "запрещенных" символов и свободно пройдет через символьный фильтр уязвимой программы. После преобразования закодированный шелл-код вместе с декодировщиком передаются уязвимой процедуре таким образом, чтобы после переполнения адрес возврата из процедуры указывал на первую инструкцию декодировщика, который декодирует шелл-код, размещает его в нужной области памяти и передаёт ему управление. Декодировщик шелл-кода при этом так же не должен содержать "запрещенных" программных инструкций. В довольно широком спектре случаев это возможно сделать.

Будем предполагать, что встретившийся нам символьный фильтр пропускает инструкцию вычитания (код инструкции 0x2D). Как получать в регистре нулевое значение, было указано ранее (см. таблицы выше). Предлагаемый алгоритм будет оперировать двойными словами (32 бит). Путь b¡,i = 1..4 - байты в двойном слове

( b - младший байт, è4 - старший). Двойное слово, образуемое этими байтами

РРРРРБТТЬ максимум N =

+1 чисел, с указанными ограничениями (квад-

будем записывать как четверку (Ъ4, Ъ3, Ъ2, Ъх ). Десятичным значением данного числа будет Ъ4*1000000И + Ъ3*10000И + Ъ2*100И + Ъ^ Поскольку мы считаем, что имеется символьный фильтр, то на каждый байт данной четверки будет накладываться следующее ограничение:

К < Ъ < К, где 1 = 1. 4, 00И < Ц < Иг < РРИ . (1)

Введем величину 1 = К — К - длина интервала ограничения.

Покажем, что любое 4 - байтное число можно получить путем вычитания из " РРЬ"

_ 1 _

ратные скобки означают целую часть от деления). Пусть А = (а4,а3,а2,а1), 00И < а < РРЬД = 1..4- произвольное число, которое нам необходимо получить. Рассмотрим величину С0 = (РР^РР^РР^РРИ) — А (операция вычитания осуществляется покомпонентно, где С0 = (С4,С°,С2,С°) также без ограничений на компоненты). Рассмотрим вспомогательный случай:

Пусть К = 0 , тогда 1 = К. (2)

N

Найдем четверки С; = (С14,С3,С12,С11) такие, что С0 — I С; = 0. Компоненты

1=1

1—1

четверок С1 вычисляем по формулам: С* = тт(С°,1) , и С‘ = тш(С° — I ф)

к=1

для 1 > 1. В таком случае мы получаем, что все С1 е [ИГ,И1], и легко восстанавливаем исходное значение А = (РРЬ,РРЬ,РРЬ,РРИ) — Я или

N

А = (РР^РР^РР^РРИ) — IС1. Вектор (РРЬ,РРЬ,РРЬ,РРИ) при помощи ограни-

1=1

ченного набора команд мы получить можем, код операции вычитания (0х2Б) указанным символьным фильтром будет пропущен, все С е [Ц,Ц], для , > 0, а следовательно также не будут отфильтрованы. Поэтому можно сделать вывод, что при данных условиях возможно получение в памяти произвольного 4- байтного числа с использованием ограниченного набора процессорных инструкций. Следует отметить, что используемое нами покомпонентное вычитание в указанном случае совпадает с обычным вычитанием шестнадцатеричных чисел, поскольку вычитание всегда будет происходить без переноса разрядов из старших в младшие.

Общий случай:

Пусть теперь К , К - произвольные, удовлетворяющие (1). Сведем его к предыдущему. Считая 1 = Ьг — Ц, построим четверки С. как во вспомогательном

N

случае. Получим А = (ЕЕИ, ЕЕИ, ЕЕИ, ЕЕИ) — I Сг ,

1=1

где С е [0, К — К ]. Далее введем четверку Я = (К, К, К, К ), и обозначим

с, = я+с, где с,, я е [нг, к ]

Тогда в указанных обозначениях имеем:

N

A = (FFh, FFh, FFh, FFh)-£ (C - R). (3)

1=1

Здесь также справедливо замечание о том, что покомпонентное вычитание совпадает с обычным, поскольку переносов разрядов при выполнении операций не происходит. Возможно, что под знаком суммы равенства (3), начиная с некоторого i, будут получаться нули, которые так же можно отбросить, сократив количество шагов. В любом случае данный алгоритм позволяет построить код, состоящий только из допустимых символов, и похожий на данный, который изменит указатель стека и разместит в нем требуемый набор процессорных инструкций.

Заключение

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

БИБЛИОГРАФИЧЕСКИЙ СПИСОК

1. Аграновский А.В., Хади Р.А., Балакин А.В., Котов И.Н. "Информационная безопасность удаленного доступа в сети Интернет", "Information warfare, security of remote access in the Internet-community", Труды международной научно-методической конференции Телематика, - СПб: Русский том, - С. 40-41, 2001.

2. Касперски К. - Техника и философия хакерских атак, Солон-Р, 2004. - 272с.

3. Айрапетян Р.А. Отладчик SoftlCE. Подробный справочник, Солон-Пресс, 2003.- 304с.

А.Ф. Чипига, В.С. Пелешенко

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Россия, г. Ставрополь, СевКавГТУ

ФОРМАЛИЗАЦИЯ ПРОЦЕДУР ОБНАРУЖЕНИЯ И ПРЕДОТВРАЩЕНИЯ СЕТЕВЫХ АТАК

Постановка задачи. Формализовать обобщение сигнатурных и статических методов обнаружения и предотвращения сетевых атак. Представить методику совместного обнаружения сетевых атак сигнатурными и статистическими методами.

Решение задачи. Применяемые при обнаружении и предотвращении сетевых атак методы и модели сводятся к сетевому и хостовому анализу сигнатурных и статистических данных сетевого трафика с последующим выводом средств обнаружения атак (СОА) об осуществлении атаки. К таким выводам относятся сообщения на консоль или в журналы СОА о времени обнаружения и проведения, названии и типе атаки. Результатами работы СОА являются данные о номерах пакетов, содержащихся в сеансе атаки [1-4]. Сигнатурный анализ и контроль профилей при обнаружении компьютерных атак включает в себя анализ заданных заранее последовательностей, как самих анализируемых данных, так и последовательностей действий. Современные методики обнаружения сетевых атак достаточно разнородны и не сведены к единому критерию, по которому возможно оценивать эффективность их применения. Таким критерием может служить полнота охвата всех анализируемых параметров, необходимых для точного и наиболее вероятного выявления атаки с минимальным ложным срабатыванием [6]. Недостатками рассматриваемых моделей являются: для моделей, использующих статистические методики, - большое количество ложных тревог и ошибок второго рода, для моделей, использующих сигнатурные методики, - невозможность самостоятельного обнаружения новых атак и постоянная необходимость обновления базы сигнатур [7].

i Надоели баннеры? Вы всегда можете отключить рекламу.