Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #45, АВГУСТ 2004 г.

Пишем shell-код!

Коваленко Дмитрий aka Ingrem

Спецвыпуск Xakep, номер #045, стр. 045-014-4


Допустим, на отладке видно, что адрес в eax обычно не превышает 100 байт от начала буфера. Тогда при написании shell-кода этот интервал нужно заполнить nop'ами, а уже после них разместить какой-то полезный код.

После выполнения jmp eax управление попадет на один из nop’ов. Когда все nop'ы, идущие после, выполнятся, управление в конце-концов попадет на полезный код. Эта техника так и называется – "большой буфер с nop'ами".

Тонкости написания строкового shell-кода

Большинство реальных переполнений – строковые. С одной стороны, это хорошо. Когда мы ищем уязвимость, то знаем, что длинные строки надо пробовать в первую очередь. С другой стороны, возникает небольшая проблема. Если shell-код внедряется в приложение в виде строки, он не должен содержать нулевых байт. При чтении строки с shell-кодом в буфер ноль будет воспринят как ее конец и shell-код внедрится не полностью. А это не есть гуд :(. Вот почему shell-код обычно делят на две части. Первая часть ("тело" shell-кода) – это небольшой переносимый код, который открывает консоль с админскими правами или закачивает троян из инета, в общем, делает что-то полезное. После того как тело написано и отлажено, хакер его шифрует так, чтобы в нем не было нулевых байт. Естественно, в зашифрованном виде тело работать не может. Поэтому к нему цепляется вторая часть ("голова") – небольшой код-дешифровщик, также не содержащий нулей. Сперва управление получает голова. Она дешифрует "тело" и отдает управление ему, после чего shell-код спокойно делает свои темные делишки ;-).

Шифровка тела shell-кода и написание головы – не такие уж простые занятия. Большинство авторов рекомендуют шифровать побайтно, с помощью последовательного применения инструкций ADD и XOR.

Что такое ADD? Всего лишь сложение! Если мы зашифровали байт, добавив к нему что-то, мы можем так же просто его расшифровать, нужно только это "что-то" отнять. XOR – это вообще прелесть! "Поксорив" байт, например, на 0xFF, мы его зашифровываем. "Поксорив" его опять на то же самое 0xFF, расшифровываем.

Листинг

Процедура шифрования с использованием инструкций ADD и XOR

; eax - адрес тела

; ecx - его длина

crypt_exploit:

mov bl, byte ptr[eax] ; читаем очередной байт тела в bl

xor bl, XOR_KEY; ксорим его на XOR_KEY

add bl, ADD_KEY; добавляем к нему ADD_KEY

mov byte ptr[eax], bl ; записываем зашифрованный байт в тело

inc eax ; перемещаем указатель на следующий байт тела

loop crypt_exploit; если ecx не равно 0 - новый виток цикла

ret

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

Листинг

Голова (процедура расшифровки тела shell-кода)

exploit_head:

; заносим в ecx длину тела shell-кода (для простоты считаем, что

Назад на стр. 045-014-3  Содержание  Вперед на стр. 045-014-5