Ошибки сегментации и безопасность: куча
Содержание:
1. Модель памяти процесса и атаки на переполнение буфера, стек;
2.Куча (Вы читаете данный раздел);
3. Средства защиты, способы их обхода и слова-канарейки;
4. «Канарейки» в glibc и NX-бит;
5. Коммерческая сторона и конкуренты;
Схожим образом можно организовать и атаки на переполнение буферов, располагающихся в куче. Ведь один из часто используемых типов данных - это указатель на функцию, и некорректное изменение какого-либо указателя может привести к краху программы или вызову «неожиданной» функции.
С перезаписью нужных переменных в куче могут возникнуть сложности, поскольку при распределении памяти в куче могут применяться достаточно сложные алгоритмы и гарантированно вычислить взаимное расположение переменных в памяти можно не всегда. Поэтому далеко не всякую ошибку сегментации в куче легко обратить в цель для атаки.
Впрочем, если атакуемый буфер располагается «недалеко» от переменной, которую нужно перезаписать (например, внутри одной структуры или класса), то проблем возникнуть не должно.
Например, рассмотрим следующий код:
Здесь мы считываем с помощью функции gets() в поле a.str строку, никак не контролируя ее длину, в то время как размер поля составляет всего два байта. В процессе выполнения программы считываемая строка будет записываться в структуру А начиная с первого байта поля str. Начиная с некоторого размера строки, она перекроет поле funo (в зависимости от разрядности вашей системы и опций компиляции, влияющих на выравнивание полей структур в памяти, критическая длина строки может оказаться различной). В результате, при вызове a.funo() процессор попробует выполнить отнюдь не функцию f(). Нетрудно подобрать такую строку, которая перезапишет поле a.funo чем-то осмысленным. Например, в моей рабочей системе мне удалось подобрать строку, ввод которой приводил к повторному вызову gets().
В заключение отмечу, что помимо стека и динамических переменных в куче, популярной целью для атак являются таблицы GOT (Global Offset Table) и PLT (Procedure Linkage Table). Такие таблицы есть у каждого процесса, использующего динамически скомпонованные библиотеки (практически все бинарные приложения в дистрибутивах Linux используют те или иные библиотеки). Таблицы GOT и PLT указывают, по каким адресам в памяти процесса находятся библиотечные данные и функции. Они располагаются в области данных процесса и могут быть изменены злоумышленником, в результате чего адрес некоторой библиотечной функции будет подменен адресом вредоносной процедуры.
Подобные правила к защите безопасности применяются и к сервера, которые осуществляют такую популярную нынче операцию как рассылка смс (http://redsms.ru/). Востребованность данной услуги на современном рынке понятна - рекламодатель получает сотни потенциальных клиентов, непосредственно заинтересованных в предлагаемом товаре, за сущие копейки!
1. Модель памяти процесса и атаки на переполнение буфера, стек;
2.
3. Средства защиты, способы их обхода и слова-канарейки;
4. «Канарейки» в glibc и NX-бит;
5. Коммерческая сторона и конкуренты;
Схожим образом можно организовать и атаки на переполнение буферов, располагающихся в куче. Ведь один из часто используемых типов данных - это указатель на функцию, и некорректное изменение какого-либо указателя может привести к краху программы или вызову «неожиданной» функции.
С перезаписью нужных переменных в куче могут возникнуть сложности, поскольку при распределении памяти в куче могут применяться достаточно сложные алгоритмы и гарантированно вычислить взаимное расположение переменных в памяти можно не всегда. Поэтому далеко не всякую ошибку сегментации в куче легко обратить в цель для атаки.
Впрочем, если атакуемый буфер располагается «недалеко» от переменной, которую нужно перезаписать (например, внутри одной структуры или класса), то проблем возникнуть не должно.
Например, рассмотрим следующий код:
#include
void f() {
printf("Here I am!n");
}
struct A { char str[2]; void(*func)(void);
} a;
void main() {
a.func = f;
gets(a.str);
a.func();
}
void f() {
printf("Here I am!n");
}
struct A { char str[2]; void(*func)(void);
} a;
void main() {
a.func = f;
gets(a.str);
a.func();
}
Здесь мы считываем с помощью функции gets() в поле a.str строку, никак не контролируя ее длину, в то время как размер поля составляет всего два байта. В процессе выполнения программы считываемая строка будет записываться в структуру А начиная с первого байта поля str. Начиная с некоторого размера строки, она перекроет поле funo (в зависимости от разрядности вашей системы и опций компиляции, влияющих на выравнивание полей структур в памяти, критическая длина строки может оказаться различной). В результате, при вызове a.funo() процессор попробует выполнить отнюдь не функцию f(). Нетрудно подобрать такую строку, которая перезапишет поле a.funo чем-то осмысленным. Например, в моей рабочей системе мне удалось подобрать строку, ввод которой приводил к повторному вызову gets().
В заключение отмечу, что помимо стека и динамических переменных в куче, популярной целью для атак являются таблицы GOT (Global Offset Table) и PLT (Procedure Linkage Table). Такие таблицы есть у каждого процесса, использующего динамически скомпонованные библиотеки (практически все бинарные приложения в дистрибутивах Linux используют те или иные библиотеки). Таблицы GOT и PLT указывают, по каким адресам в памяти процесса находятся библиотечные данные и функции. Они располагаются в области данных процесса и могут быть изменены злоумышленником, в результате чего адрес некоторой библиотечной функции будет подменен адресом вредоносной процедуры.
Подобные правила к защите безопасности применяются и к сервера, которые осуществляют такую популярную нынче операцию как рассылка смс (http://redsms.ru/). Востребованность данной услуги на современном рынке понятна - рекламодатель получает сотни потенциальных клиентов, непосредственно заинтересованных в предлагаемом товаре, за сущие копейки!