Overflow
В этой небольшой статье Андрей Соколов расскажет об одной достаточно распространенной уязвимости называемой переполнением буфера. Будет написана небольшая программа, в которой будет присутствовать уязвимость. Все эксперименты проводяться в OS Solaris.
Вот программа, демонстрирующая хак через переполнение буфера.
#include <stdio.h> #include <stdlib.h> void funcException(){ printf("Overflow!!!!\n"); exit(0); } int funcRead(){ int buf[10]; int i = 0; for(;;) if(!fread(&buf[i++],sizeof(buf[i++]),1,stdin)) break; return 0; } int main(int argc, char** argv) { if(funcRead()) funcException(); else printf("No overflow\n"); return (EXIT_SUCCESS); }
Если анализировать код, то можно сделать вывод, что управление на функцию funcException никогда не должно быть передано: funcRead всегда возвращает 0, а конструкция if в функции main в этом случае передает управление по ветке else. Однако первое впечатление обманчиво. Обратим внимание на то, что в функции funcRead при чтении данных в массив buf не выполняется проверка на переполнение массива. Значит запись может быть выполнена за границы данного массива.
Данная программа была написана в Sun Studio 12 и скомпилирована в отладочном варианте со всеми параметрами по умолчанию. Стек внутри funcRead выглядит так:
i
buf[0]
buf[1]
.....
buf[9]
возвращаемое значение
ebp
адрес возврата
Для ознакомления со структурой стека рекомендую поглядеть ассемблерный листинг, формируемый по исходнику командой: cc -S <исходник>.
Таким образом, если в buf[12] будет записан адрес функции funcException, то управление будет передано на нее. Значит надо подать на стандартный ввод программы файл, в котором 13-ое двойное слово содержит этот адрес.
Чтобы узнать адрес используем отладчик mdb:
mdb <имя исполняемого файла>
выполняем в отладчике команду просмотра соответствия символьных имен адресам (::nm). Вот часть ее вывода:
> ::nm
Value Size Type Bind Other Shndx Name
0x00000000|0x00000000|NOTY |LOCL |0x0 |UNDEF |
0x0805095c|0x00000000|FUNC |GLOB |0x0 |UNDEF |printf
0x08050990|0x0000008e|FUNC |GLOB |0x0 |12 |_start
0x0805094c|0x00000000|FUNC |GLOB |0x0 |UNDEF |_exit
0x08050aa0|0x00000022|FUNC |GLOB |0x0 |12 |funcException
0x08060bf0|0x00000000|OBJT |GLOB |0x0 |18 |_DYNAMIC
0x00000000|0x00000000|NOTY |WEAK |0x0 |UNDEF |__1cG__CrunMdo_exit_code6F_v_
0x08050bc5|0x00000000|OBJT |GLOB |0x0 |16 |_etext
Итак, 13-ое двойное слово должно содержать значение 0x08050aa0.
Создаем файл из 52 байт, а потом при помощи двоичного редактора ghex2 заменяем последние 4 байта, не забывая про то, что младший байт располагается по младшему адресу. Этот файл, будучи поданным на стандартный ввод обеспечит вывод на консоль сообщения "Overflow!"
Ваши замечания и предложения можно оставлять тут.
Андрей Соколов (keremet[собачка]bk.ru)
