ДС18в07-машинный-уровень-4-Данные (1238910), страница 2
Текст из файла (страница 2)
8MB)§ Например, локальные переменные и параметры¢Heap (куча)§ Динамически занимаемое пространство§ При вызове malloc(), calloc(), new()¢Data (данные)SharedLibraries§ Статически размещаемые данные§ Например, массивы и константные строки¢Text и Shared Libraries (исполняемый код)§ Исполняемые машинные инструкции§ Только чтениеАдрес400000000000HeapDataText35Не в масштабеПример распределения памятиStackchar big_array[1L<<24]; /* 16 MB */char huge_array[1L<<31]; /* 2 GB */int global = 0;int useless() { return 0; }int main (){void *p1, *p2, *p3, *p4;int local = 0;p1 = malloc(1L << 28); /* 256 MBp2 = malloc(1L << 8); /* 256 Bp3 = malloc(1L << 32); /*4 GBp4 = malloc(1L << 8); /* 256 B/* Несколько вызовов печати ...
*/}Где всё это размещается?SharedLibraries*/*/*/*/HeapDataText36Пример адресов x86-64Не в масштабе00007FFFFFFFFFFFStackдиапазон адресов ~247Heaplocalp1p3p4p2big_arrayhuge_arraymain()useless()0x00007ffe4d3be87c0x00007f7262a1e0100x00007f7162a1d0100x000000008359d1200x000000008359d0100x00000000806010600x00000000006010600x000000000040060c0x0000000000400590HeapDataText037Ещё машинный уровеньУправление и сложные данные¢¢Процедуры (x86-64)Массивы§ Одномерные§ Многомерные (массивы массивов)§ Многоуровневые¢Структуры§ Размещение§ Доступ§ Выравнивание¢¢¢ОбъединенияРаспределение памятиО переполнении буфера38Переполнение буфера – большая проблема¢Пишут “переполнение буфера”§ когда выходят за рамки адресов памяти, отведённых под массив¢Почему большая проблема?§ Техническая причина №1 нарушения безопасности§¢Причина №1 в целом – социальная инженерия / беспечность людейНаиболее частые случаи§ Непроверенные длины вводимых строк§ В частности для ограниченных массивом символов в стеке§иногда упоминается как «stack smashing»39Библиотечный код обработки строк¢Unix-реализация функции gets()/* Выбрать строку из stdin */char *gets(char *dest){int c = getchar();char *p = dest;while (c != EOF && c != '\n') {*p++ = c;c = getchar();}*p = '\0';return dest;}§ Невозможно ограничить количество вводимых символов¢Та-же проблема с другими библиотечными ф-циями§ strcpy, strcat: Копирование строк произвольной длины§ scanf, fscanf, sscanf со спецификацией преобразования %s40Код с уязвимостью переполнения буфера/* Эхо строки */void echo(){char buf[4];gets(buf);puts(buf);}/* Слишком мал! */çкстати, а «достаточно»это сколько?void call_echo() {echo();}unix>./bufdemoType a string:012345678901234567890123012345678901234567890123unix>./bufdemoType a string:0123456789012345678901234Segmentation Fault41Дизассемблирование переполнения буфераecho:00000000004006cf <echo>:4006cf: 48 83 ec 184006d3: 48 89 e74006d6: e8 a5 ff ff ff4006db: 48 89 e74006de: e8 3d fe ff ff4006e3: 48 83 c4 184006e7: c3submovcallqmovcallqaddretq$0x18,%rsp%rsp,%rdi400680 <gets>%rsp,%rdi400520 <puts@plt>$0x18,%rspcall_echo:4006e8:4006ec:4006f1:4006f6:4006fa:48b8e848c38300d983ec00ffc40800 00ff ff08submovcallqaddretq$0x8,%rsp$0x0,%eax4006cf <echo>$0x8,%rsp42Стек при переполнении буфераПеред вызовом getsСтековый кадрcall_echoАдрес возврата(8 байт)20 байтне использованы[3] [2] [1] [0] buf/* Эхо строки */void echo(){char buf[4];gets(buf);puts(buf);}/* Слишком мал! */%rspecho:subq $24, %rspmovq %rsp, %rdicall gets.
. .43Пример стека при переполнении буфераПеред вызовом getsСтековый кадрcall_echo0000 Address00 00Return00 (840bytes)06 f620 байтне использованы[3] [2] [1] [0] bufvoid echo(){char buf[4];gets(buf);. . .}echo:subq $24, %rspmovq %rsp, %rdicall gets. . .call_echo:. . .4006f1:4006f6:.
. .callqadd4006cf <echo>$0x8,%rsp%rsp44Пример стека при переполнении буфера 1После возврата из getsСтековый кадрcall_echo0000 Address00 00Return00 (840bytes)06 f600 32 31 3039 38 37 363534 unused33 3220 bytes31 30 39 3837 36 35 3433 32 31 30 bufvoid echo(){char buf[4];gets(buf);. .
.}echo:subq $24, %rspmovq %rsp, %rdicall gets. . .call_echo:. . .4006f1:4006f6:. . .callqadd4006cf <echo>$0x8,%rsp%rspunix>./bufdemoType a string:0123456789012345678901201234567890123456789012Буфер переполнен, но состояние не испорчено45Пример стека при переполнении буфера 2После возврата из getsСтековый кадрcall_echo0000 Address00 00Return00 (840bytes)00 3433 32 31 3039 38 37 363534 unused33 3220 bytes31 30 39 3837 36 35 3433 32 31 30 bufvoid echo(){char buf[4];gets(buf);.
. .}echo:subq $24, %rspmovq %rsp, %rdicall gets. . .call_echo:. . .4006f1:4006f6:. . .callqadd4006cf <echo>$0x8,%rsp%rspunix>./bufdemoType a string:0123456789012345678901234Segmentation FaultБуфер переполнен и испорчен адрес возврата46Пример стека при переполнении буфера 3После возврата из getsСтековый кадрcall_echo0000 Address00 00Return00 (840bytes)06 0033 32 31 3039 38 37 363534 unused33 3220 bytes31 30 39 3837 36 35 3433 32 31 30 bufvoid echo(){char buf[4];gets(buf);. . .}echo:subq $24, %rspmovq %rsp, %rdicall gets.
. .call_echo:. . .4006f1:4006f6:. . .callqadd4006cf <echo>$0x8,%rsp%rspunix>./bufdemoType a string:012345678901234567890123012345678901234567890123Буфер переполнен и испорчен адрес возврата но программа кажется работающей !47Пояснения к примеру стека 3После возврата из getsСтековый кадрcall_echo0000 Address00 00Return00 (840bytes)06 0033 32 31 3039 38 37 363534 unused33 3220 bytes31 30 39 3837 36 35 3433 32 31 30 bufregister_tm_clones:. . .400600:400603:400606:40060a:40060d:400610:400612:400613:movmovshraddsarjnepopretq%rsp,%rbp%rax,%rdx$0x3f,%rdx%rdx,%rax%rax400614%rbp%rsp“Возврат” не туда, куда надо.Многое меняется, без критической порчи состоянияСлучайно выполняется retq обратно в main48Атаки на основе переполнения буферов¢¢Ошибки переполнения позволяют удалённой машиневыполнять произвольный код на машинах жертвУдручающе часты в реальных программах§ Программисты делают одинаковые ошибки L§ Современные меры делают такие атаки много труднее¢Примеры прошедших десятилетий§§§§¢Первый “интернет-червь” (1988)“Битвы мессенжеров” (1999)Взлом Wii (2000s)… и многие, многие другиеМожно попробовать некоторые фокусы в attacklab§ Возможно это убедит вас не оставлять таких дыр в своихпрограммах!!49Злонамеренное использованиепереполнения буфера Стек после вызова gets()void foo(){bar();...}int bar() {char buf[64];gets(buf);...return ...;}¢¢¢Кадр fooАдрес возвратаABДанныезаписанныеgets()BкодвредоносаКадр barВводимая строка содержит байтовое представление исполняемого кодаЗатирает адрес возврата A адресом буфера BКогда bar() выполняет ret, управление передаётся вредоносу50Избегание уязвимости переполнения/* Эхо строки */void echo(){char buf[4]; /* Слишком мал! */fgets(buf, 4, stdin);puts(buf);}¢Используйте функции с ограничением длины строки§ fgets вместо gets§ strncpy вместо strcpy§ Не используйте scanf со спецификацией прообразования %s§§Используйте fgets для чтения строкиили используйте %ns где n подходящее целое51Защита на уровне системы¢Рандомизация сдвига стека§ При старте программы выделяется случайноепространство в стеке§ Затрудняет хакеру предсказание началавставляемого кода¢Неисполняемые сегменты памяти§ В x86, область памяти либо только чтениелибо изменяемая§ Может выполняться всё, что читается§ x86-64 добавляет явное разрешениеисполняемая§ Стек помечается как неисполняемый52Стековый индикатор¢Идея§ Разместить в стеке сразу за буфером специальное значение( индикатор )§ Проверять целостность перед выходом из функции¢Реализация GCC§ -fstack-protector§ сейчас включён по умолчанию (но не раньше)unix>./bufdemo-protectedType a string:01234560123456unix>./bufdemo-protectedType a string:01234567*** stack smashing detected ***53Дизассемблирование защищённого буфераecho:40072f:400733:40073c:400741:400743:400746:40074b:40074e:400753:400758:400761:400763:400768:40076c:submovmovxormovcallqmovcallqmovxorjecallqaddretq$0x18,%rsp%fs:0x28,%rax%rax,0x8(%rsp)%eax,%eax%rsp,%rdi4006e0 <gets>%rsp,%rdi400570 <puts@plt>0x8(%rsp),%rax%fs:0x28,%rax400768 <echo+0x39>400580 <__stack_chk_fail@plt>$0x18,%rsp54Установка индикатораПеред вызовом gets/* Эхо строки */void echo(){char buf[4];gets(buf);puts(buf);}Стековый кадрcall_echoАдрес возврата(8 байт)/* Слишком мал! */20Индикаторbytes unused(8 bytes)[3] [2] [1] [0] buf%rspecho:.
. .movqmovqxorl. . .%fs:40, %rax # Получить индикатор%rax, 8(%rsp) # Поместить в стек%eax, %eax# Стереть индикатор55Проверка индикатораПосле возврата из getsBefore call to getsСтековый кадрcall_echoАдрес возврата(8 байт)Saved %ebpSaved %ebx20Индикаторbytes unused(8Canarybytes)[3]00 [2]36 [1]35 [0]3433 32 31 30 buf/* Эхо строки */void echo(){char buf[4];gets(buf);puts(buf);}/* Слишком мал! */Ввод: 0123456%rspecho:. . .movqxorqjecall.L6:8(%rsp), %rax%fs:40, %rax.L6__stack_chk_fail. . .####Считать из стекаСравнить с исходнымСовпало? Дальше…ОШИБКА!56.