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

Зоопарк переполняющихся буферов 

Крис Касперски aka мыщъх

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


f(char *psswd)

{

char buf[MAX_BUF_SIZE]; int auth_flag = PASSWORD_NEEDED;

printf("скажи пароль:"); gets(buf);

if (auth_flag != PASSWORD_NEEDED) return PASSWORD_OK;

return strcmp(passwd, buf);

}

Атака на указатели может преследовать три цели: а) передачу управления на посторонний код (аналог CALL); б) модификацию произвольной ячейки (аналог POKE); в) чтение произвольной ячейки (аналог PEEK).

Начнем с атаки, имеющей целью передачу управления, как наиболее мощной и разрушительной. Она делится на два подтипа:

I) передача управления на функцию, уже существующую в программе;

II) передача управления на код, сформированный самим злоумышленником (shell-код).

Проще всего кинуть ветку управления на уже существующую функцию. Это можно сделать, например, так (см. код #3). Зная адрес функции root (а его можно выяснить дизассемблированием), будет нетрудно перезаписать указатель zzz так, чтобы при вызове функции ffh управление получал root! Естественно, передавать управление на начало функции необязательно – "полезный" (для хакера) код может располагаться и в ее середине (можно, например, пропустить процедуру аутентификации и сразу запрыгнуть в центральный штаб). Определенная проблема возникает с инициализацией регистров и передачей параметров, однако всегда можно подобрать функцию, не принимающую никаких параметров, или передать их косвенным образом.

Где можно найти указатели на код? Прежде всего, это адрес возврата, расположенный внизу кадра стека, затем идут виртуальные таблицы и указатели this, без которых не обходится ни одна программа Си++, указатели на функции динамически загружаемых библиотек (LoadLibrary/GetProcAddress) также не редкость, ну и другие типы указателей тоже встречаются.

Код #3. Пример, демонстрирующий атаку на кодовые указатели

root() {...};

...

f()

{

char buf[MAX_BUF_SIZE]; int (*zzz)();

...

zzz = GetProcAddress(dllbase, "ffh");

...

gets(buf);

...

zzz();

}

Shell-код – намного более мощная штука, позволяющая вытворять с уязвимой программой что угодно. В плане возращения к коду #3 спросим себя: а что произойдет, если в переменную zzz занести указатель на сам переполняющийся буфер buf, в который внедрить хакерский код, организующий нам удаленный shell? Эта классическая схема атаки, описанная практически во всех факах и мануалах по безопасности, в действительности полная фигня. При практической реализации атаки сталкиваешься с таким количеством проблем, что чувствуешь себя верблюдом, попавшим на хавчик. Интересующихся мы отошлем к статье "Ошибки переполнения буфера извне и изнутри как обобщенный опыт реальных атак" на wasm.ru, а сами перейдем к указателям на данные.

Указатели на данные гораздо более распространены и коварны. Рассмотрим простейший пример (см. код #4). Если перезаписать указатель b вместе со скалярной переменной a, то мы получим своеобразный аналог бейсик-функции POKE, с помощью которой можно модифицировать любую ячейку программы (и указатели на код в том числе). Это самое мощное оружие, которое только существует в киберпространстве!

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