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

Unicode-Buffer Overflows

Мысла Владислав

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


Листинг

00 00 add byte ptr [eax],al

...

00 03 add byte ptr [ebx],al

...

00 20 add byte ptr [eax],ah

...

00 23 add byte ptr [ebx],ah

...

и инкрементирования данных в памяти:

FF 00 inc dword ptr [eax]

FE 00 inc byte ptr [eax]

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

Математические операции над числами

Используя операцию mov, можно заносить в r32 регистры нужные данные. Но опять не все так просто. Заносить можно исключительно числа в формате 0хХХ00ХХ00: B8 00 ХХ 00 ХХ mov eax,0ХХ00ХХ00h. Такие же ограничения поставлены и на операцию add для r32 регистров: 05 00 ХХ 00 ХХ add eax,0ХХ00ХХ00h.

Также у тебя есть все возможности, чтобы воспользоваться суммированием данных в r8 регистрах:

Листинг

...

00 C3 add bl,al

...

00 C7 add bh,al

...

00 E3 add bl,ah

...

00 E7 add bh,ah

...

Для зануления регистров r8 ты можешь использовать:

Листинг

B0 00 mov al,0

B1 00 mov cl,0

...

B4 00 mov ah,0

B5 00 mov ch,0

...

Можно также закинуть в стек нуль и забрать в какой-либо регистр. Если тебе придется использовать операцию XOR, то имей в виду, что она подходит только для модификации регистра eax, причем второй операнд должен иметь вид 0хХХ00ХХ00 (далее просто UnicodeDW).

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

Работа со стеком

В стек ты можешь записывать все r32 регистры:

50 push eax

53 push ebx

Можешь записывать числа в формате UnicodeDW и нуль:

68 00 FF 00 FF push 0FF00FF00h

6A 00 push 0

С помощью команды pop имеешь возможность забирать данные со стека в любой r32 регистр: 58 pop eax, сохранять в стеке состояния всех регистров или же загружать их оттуда:

61 popad

60 pushad

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

Использование наших возможностей

Теперь перейдем непосредственно к написанию shell-кода.

Для начала пишем небольшую программу, которая будет средой обитания нашего shell-кода.

Листинг

int _tmain(int argc, _TCHAR* argv[]) {

__asm {

call set_stack_pointer_to_eip

set_stack_pointer_to_eip:

pop esp

/* ESP now point to the start address of shellcode: */

// TODO: shellcode here :) }

return 0; }

Мы предполагаем, что переполняемый буфер находится на вершине стека, поэтому eip = esp. Чтобы не писать весь shell-код в Unicode, ты можешь использовать старые заготовки стандартных shell-кодов. Правда, после конвертирования они перестанут работать. Поэтому следует написать декриптор в Unicode так, чтобы он превращал свою вторую часть (основной shell-код) в нормальный вид. Для этого самым экономным и простым вариантом будет создание алгоритма для считывания 2 байт (\х00\х[код]) из стека и записи второго байта в область памяти, доступную для записи:

Назад на стр. 045-056-2  Содержание  Вперед на стр. 045-056-4