Переполнение буфера в heap. 1 серия
kas1e
Xakep, номер #057, стр. 057-074-1
Сегодня я рассмотрю относительно новую технику переполнений, базирующуюся на так называемом "переполнении в heap области". Информация об этом виде переполнения начала просачиваться с 98 года, и в начале 99 в свет вышла знаменитая дока от w00w00 и Matt Conover, которая так и называлась: "w00w00 on Heap Overflows". В ней описывались основы переполнения heap и bss областей и даже приводились кое-какие примеры. Спустя пару лет, в 2001 году вышел действительно хороший текст от Michel "MaXX" Kaempf, который носил название "Vudo - An object superstitiously believed to embody magical powers", хотя на самом деле "Smashing The Heap For Fun And Profit" будет точнее :). В этом тексте разжевывается heap технология на примере эксплуатации Sudo и показывается, зачем нужно знать malloc() функцию как свои пять пальцев.
Для того чтобы иметь полное представление об описываемой проблеме, стоит детально проштудировать оба этих текста. Но опять же, предполагая, что ты человек занятой/ленивый, я постараюсь в двух статьях дать понятное описание этой техники. Однако для начала, я думаю, тебя волнует более насущный вопрос: "А где же все-таки нехорошие люди это используют?" А используется эта техника в таких нашумевших в свое время эксплоитах как: apache_scalp, openssl2open и т.д. Также в этот список попали: pine, php, wu-ftpd. Не обошло стороной и виндовые iis ;).
Для того чтобы вникнуть в проблему, тебе стоит хотя бы прочитать и понять мои предыдущие статьи о переполнении буфера в стеке. Соответственно, подразумевается, что ты уже знаешь С, Assembler, немного unix и умеешь работать с памятью (ну и т.д. и т.п). Итак, поехали.
Структура образа ELF программы в памяти
Выполнение любой программы начинается с создания ее образа в памяти. В этом механизме участвует довольно много процессов. Подробно я их рассматривать не буду, а остановлюсь лишь на наиболее важных для нас. Плюс рассмотрим непосредственно структуру образа в этой самой памяти. Образ программы состоит из нескольких сегментов:
1. Внешние переменные: имя, путь программы и так далее (более подробно я об этом рассказывал во второй части статьи про переполнение буфера в стеке).
2. Segment stack (сегмент стека). Сегмент, называющийся "стековый", где динамические переменные (на C жаргоне "автоматические" переменные) определяются и убиваются; и где временно запоминаются адреса возвратов для функций.
3. Heap область - это область памяти, динамически распределяющаяся приложением, причем само приложение имеет возможность управлять ростом сегмента данных, выделяя дополнительную память из этой же heap области.
В большинстве систем heap растет вверх (к верхнему адресу). Т.е. если мы скажем "X идет за Y", это означает, что X ниже в памяти, чем Y, в то время как стек растет вниз (т.е. начиная от самого большого адреса и заканчивая меньшим).
4. Data segment (сегмент данных, также известен как bss section). В этом сегменте инициализируются и деинициализируются данные. К примеру, если мы не знаем значения глобальной переменной на этапе компиляции (char hahah[32];), то в таком случае, при создании образа в памяти, в bss сегменте выделится необходимое количество памяти, заполненное нулями (кстати, переполнение в bss области похоже на heap переполнение).