Отключите программно аппаратный механизм защиты процессора от переполнения буфера биос

Обновлено: 07.07.2024

Зависимость пропускной способности от выбранного режима DMA приведена в таблице:

Максимальная скорость передачи, МБ/с

DRAM Frequency – Частота памяти
[Auto] [DDR2-667 MHz] [DDR2-800 MHz] [DDR2-889 MHz] [DDR2-1067 MHz]
Позволяет вручную задать рабочую тактовую частоту (делитель или множитель) для установленных модулей памяти. Заметим, что в большинстве случаев BIOS автоматически правильно выставляет это параметр, т.к. он записан в идентификационной микросхеме SPD каждого модуля памяти. Изменять параметр стоит: в сторону увеличения в случае использования разогнанных или разгоняемых «оверклокерских» модулей памяти; в сторону уменьшения при разгоне процессора, т.к. с увеличением его частоты или частоты системной шины обычно разгоняется и память, разгонный предел которой самый низкий в системе.

DRAM Static Read Control - Функция ускорения работы памяти
[Auto] [Disabled] [Enabled]
Опция Enabled включает функцию ускорения подсистемы памяти.

DRAM Timing Control (Timing Selectable) – Способ определения таймингов памяти
[Auto] [Manual]
Опция Manual активирует режим пользовательской настройки таймингов (задержек) оперативной памяти.


DRAM Voltage – Напряжение питания оперативной памяти
[Auto] [1.8V] …[2.2V]
Настройка «DRAM Voltage» позволяет устанавливать напряжения питание модулей оперативной памяти. Без этой настройки будет очень трудно обойтись, если вы решите использовать «оверлокерский» тип модулей для которых номинальное напряжение является выше стандартного и поэтому они требуют ручного повышения напряжения питания.

Execute Disable Bit – Механизм защиты от переполнения буфера
[Disabled] [Enabled]
Опция Enabled включает программно-аппаратный механизм защиты процессора от переполнения буфера, механизма используемого многими вредоносными программами для нанесения ущерба или проникновения в систему.

Floppy Diskette A – Определение типа дисковода.
[Disabled] [720K , 3.5 in.] [1.44M, 3.5 in.]
В этой настройке определяется тип Floppy-дисковода или производится его отключение. Самостоятельно определять вид дисковода BIOS не может, поэтому все будет зависеть от пользователя. Заметим, что единственным распространенным сегодня типом Floppy -дисководов является 1,44 Mб, 3,5" вариант.

Frame Buffer Size – Размер кадрового буфера.
[1M]. [16M]. [128M]. [1024M][Disable]
Задание объема оперативной памяти, который отводится для нужд встроенной видеокарты, некоторые операционные системы, например MS-DOS, могут использовать только помеченную таким образом память для ее нужд. В последних версиях ОС Windows объемом используемой оперативной памяти для большинства интегрированных видеокарт управляет драйвер, а описываемая опция только ограничивает нижний предел, т.е. какой минимальный объем всегда «отобрано» из оперативной памяти для нужд видеосистемы.

Front Panel Support Type – тип аудиоразъемов фронт панели
[AC97] [HD Audio]
Настройка «Front Panel Support Type» позволяет определить тип подключения аудио разъема фронт панели корпуса.

FSB Frequency – Частота системной шины
Позволяет вручную задавать опорную тактовую частоту системной шины и, соответственно, процессора (частота CPU равна частоте FSB умноженной на определенный множитель, который обычно жестко зашит в процессор).

FSB – Memory Clock Mode - Режим установки частот памяти и FSB
[Auto][Linked][Unlinked]
Опция определяет режим, в котором будет выставляться тактовая частота для системной шины и оперативной памяти:
Auto – автоматически в зависимости от свойств процессора и модулей памяти;
Linked – частота оперативной памяти пропорциональна изменяемой частоте FSB;
Unlinked – независимое задание частот системной шины и оперативной памяти.

FSB – Memory Ratio – Соотношение частот FSB и памяти
[1:1][5:4]. [3:2][Sync Mode]
Опция позволяет задать делитель для получения частоты оперативной памяти. Эта функция актуальна в двух случаях: когда устанавливаются «оверклокерские» модули оперативной памяти, но материнская плата в автоматическом режиме установила им меньшую тактовую частоту; когда производится разгон процессора и необходимо занизить рабочую частоту модулей памяти, чтобы они не ограничивали разгон.

FSB OverVoltage Control – увеличение сигнального уровня на FSB
[+0.05V]. [+0.35V]
Позволяет увеличивать на определенную величину уровень сигналов на системной шине, что может быть необходимо для достижения стабильности разогнанной системы. Как и любое увеличение рабочих напряжений, ведет к большему нагреву чипсета.

FSB Strap to North Bridge – Частота «страпа» FSB для северного моста
[Auto] [200] [266] [333]. или в виде результирующих [800] [1066] [1333].
По сути FSB Strap – это набор предустановленных задержек, которые с точки зрения производителя оптимально соответствуют определенной частоте системной шины, для определенного диапазона рабочих частот чипсета. Подбираются задержки так, чтобы обеспечивалась высокая стабильность работы системы и оставалась хорошая производительность. При этом, чем выше частота системной шины, тем большие задержки нужны для обеспечения стабильной работы чипсета. (По аналогии с оперативной памятью – чем выше тайтинги, т.е. задержки, тем на большей частоте может работать микросхема.) Соответственно, данная опция позволяет выбирать, с каким набором задержек будет работать чипсет. При установке значения FSB Strap следует учитывать, что при меньшем значении устанавливаются меньшие задержки и увеличивается производительность, а при установке большего значения немного падает производительность, но повышается стабильность. Наиболее актуальна опция при разгоне для обеспечения стабильности при высокой частоте FSB. (Примечание: для некоторых чипсетов и в некоторых BIOS установка FSB Strap делается только автоматически в зависимости от FSB используемого процессора и его максимального и выбранного в настройках множителей.)

FSB Termination Voltage – Напряжение на шине FSB
[Auto] [1.2V] …[1.5V]
Настройка «FSB Termination Voltage» определяет величину напряжения сигналов системной шины.

Full Screen LOGO Show – показывать полноэкранную заставку
[Disabled] [Enabled]
Разрешает при включении ПК вместо отчета BIOS о начале загрузки и инициализации устройств показывать фирменную заставку (или измененную пользователем).

GMCH OverVoltage Control – увеличения рабочего напряжения северного моста
[+0.025V]. [+0.175V] или [1.25V] …[1.7V]
Синонимы: MCH OverVoltage Control, North Bridge Voltage
Для увеличения стабильности работы разогнанной системы и/или увеличения разгонного потенциала зачастую необходимо увеличить рабочее напряжение Северного Моста (North Bridge, (G)MCH – обозначение по терминологии Intel с и без встроенного видео). Именно это и позволяет сделать данная опция. Но следует учитывать, что это вызывает повышенный нагрев микросхемы.

Halt on – Условия прекращения загрузки
Опция содержит варианты набора ошибок при появлении которых во время прохождения системой POST-теста следует прекратить загрузку:
No Errors – Система продолжает попытку загрузиться при любых ошибках;
All Errors – Загрузка прекращается при появлении любой ошибки, даже не значительной;
All, But Keyboard – Загрузка прекращается при появлении любых ошибок, за исключением ошибок клавиатуры;
All, But Diskette – Загрузка прекращается при появлении любых ошибок, за исключением ошибок флоппи-дисковода;
All, But Disk/Key – Загрузка прекращается при появлении любых ошибок, за исключением ошибок клавиатуры и флоппи-дисковода.

Hard Disk Write Protect
[Disabled] [Enabled]
Опция позволяет запрещать или разрешать запись на жесткий диск. Опция эффективна только если устройство получает доступ через BIOS.

High Definition Audio – аудио-контроллер
[Disabled] [Enabled]
Опция Disabled отключает встроенный в материнскую плату аудио-контроллер.

HPET Support – поддержка HPET
[Enable][Disable]
Контроллер HPET (High Precision Event Timer) разработан Intel для расширения возможностей и последующей замены Расширенного Программируемого Контроллера Прерываний (Advanced Programmable Interrupt Controller - APIC). Он добавляет поддержку большего числа прерываний, ускоренную реакцию на них и повышает точность системного времени. Работу с HPET поддерживают только новые операционные системы (Windows Vista, Mac OS X 10, Linux 2.6 and FreeBSD 7.0).

HPET Mode – режим счетчиков HPET
[32-bit][64-bit]
Поскольку контроллер HPET разрабатывался изначально с прицелом на 64-разрядные ОС, то и счетчики у него соответствующей ширины. При использовании 32-разрядной ОС с целью исключения конфликтов нужно уменьшить ширину счетчиков.

IDE Prefetch Mode – упреждающее чтение устройств IDE
[Enable][Disable]
По умолчанию обычно включен (Enable) режим упреждающего чтения данных IDE-контроллером с накопителей, что позволяет немного увеличить быстродействие дисковой подсистемы. Отключать эту функцию имеет смысл только в том случае, если подключено устройство отказывается корректно работать в этом режиме.

Initiate Graphic Adapter – инициализация видеоускорителя
[IGD], [PCI/IGD], [PCI/PEG], [PEG/IGD], [PEG/PCI], [PEG/PEG2]
Синонимы: Init Display First
Настройка «Initiate Graphic Adapter» устанавливает очередность инициализации видеоускорителя(лей). Обычно используются обозначения: IGD – интегрированное графическое ядро; PCI – видеокарта в слоте PCI; AGP - видеокарта в слоте AGP; PEG - видеокарта в слоте PCI Express; PEG2 - видеокарта во втором слоте PCI Express.

Intel Robson Technology – Технология Intel Robson (активна только для протокола AHCI)
[Disabled] [Enabled]
Enable включает технологию кэширования данных организованную с помощью дополнительного модуля флеш-памяти, призванную повысить скорость обмена данными и понизить энергопотребление.

Intel(R) SpeedStep (TM) Technology – технология энергосбережения
[Disabled] [Enabled]
Опция Enabled включает технология энергосбережения процессора Intel SpeedStep Technology, позволяющую уменьшать напряжение питания и тактовую частоту процессора во время низкой нагрузки на него.

Interrupt Mode – режим обработки прерываний
[PIC] [APIC]
Синонимы: APIC Function, IOAPIC Function - [ON/YES][OFF/NO]
Опция разрешает или запрещает использование усовершенствованного контроллера прерываний APIC (Advanced Programmable Interrupt Controller). При установке новых операционных систем рекомендуется включить поддержку APIC, т.к. этот режим обеспечит большее число прерываний и более быструю их обработку. Отключение может потребоваться только при использовании устаревших ОС. Выбор режима обработки прерываний настоятельно рекомендуется делать до установки ОС, поскольку изменение этого параметра может стать причиной невозможности загрузки и работы уже установленной и настроенной системы.

Защита от переполнения буфера является любой из различных методов , используемых в процессе разработки программного обеспечения для повышения безопасности исполняемых программ пути обнаружения переполнения буфера на стек -allocated переменных, и предотвращая их от порождения программы поведения или стать серьезной безопасностью уязвимостей. Переполнение буфера стека происходит, когда программа выполняет запись в адрес памяти в стеке вызовов программы за пределами предполагаемой структуры данных, которая обычно является буфером фиксированной длины. Ошибки переполнения буфера стека возникают, когда программа записывает в буфер, расположенный в стеке, больше данных, чем фактически выделено для этого буфера. Это почти всегда приводит к повреждению смежных данных в стеке, что может привести к сбоям программы, неправильной работе или проблемам с безопасностью.

Как правило, защита от переполнения буфера изменяет организацию данных, выделенных стеком, так что она включает канареечное значение, которое при уничтожении переполнением буфера стека показывает, что предшествующий ему буфер в памяти был переполнен. Путем проверки канареечного значения выполнение затронутой программы может быть прекращено, что предотвратит ее неправильное поведение или позволит злоумышленнику получить контроль над ней. Другие методы защиты от переполнения буфера включают проверку границ , которая проверяет доступ к каждому выделенному блоку памяти, чтобы они не могли выйти за пределы фактически выделенного пространства, и тегирование , которое гарантирует, что память, выделенная для хранения данных, не может содержать исполняемый код.

Переполнение буфера, выделенного в стеке, с большей вероятностью повлияет на выполнение программы, чем переполнение буфера в куче, потому что стек содержит адреса возврата для всех активных вызовов функций. Однако аналогичные средства защиты, зависящие от реализации, также существуют от переполнения на основе кучи.

Существует несколько реализаций защиты от переполнения буфера, в том числе для GNU Compiler Collection , LLVM , Microsoft Visual Studio и других компиляторов.

СОДЕРЖАНИЕ

Обзор

Переполнение буфера стека происходит, когда программа выполняет запись в адрес памяти в стеке вызовов программы за пределами предполагаемой структуры данных, которая обычно является буфером фиксированной длины. Ошибки переполнения буфера стека возникают, когда программа записывает в буфер, расположенный в стеке, больше данных, чем фактически выделено для этого буфера. Это почти всегда приводит к повреждению смежных данных в стеке, а в случаях, когда переполнение было инициировано по ошибке, часто приводит к сбою или неправильной работе программы. Переполнение буфера стека - это тип более общей неисправности программирования, известной как переполнение буфера (или переполнение буфера). Переполнение буфера в стеке с большей вероятностью нарушит выполнение программы, чем переполнение буфера в куче, потому что стек содержит адреса возврата для всех активных вызовов функций.

Переполнение буфера стека может быть вызвано намеренно как часть атаки, известной как разбиение стека . Если уязвимая программа работает с особыми привилегиями или принимает данные от ненадежных сетевых узлов (например, общедоступного веб-сервера ), то ошибка является потенциальной уязвимостью безопасности, которая позволяет злоумышленнику внедрить исполняемый код в работающую программу и принять контроль процесса. Это один из самых старых и надежных способов получения злоумышленниками несанкционированного доступа к компьютеру.

Как правило, защита от переполнения буфера изменяет организацию данных в кадре стека при вызове функции, чтобы включить «канареечное» значение, которое при уничтожении показывает, что предшествующий ему буфер в памяти был переполнен. Это дает преимущество предотвращения целого класса атак. По мнению некоторых исследователей, влияние этих методов на производительность незначительно.

Защита от разрушения стека не может защитить от определенных форм атак. Например, он не может защитить от переполнения буфера в куче. Не существует разумного способа изменить расположение данных в структуре ; Ожидается, что структуры модулей будут одинаковыми, особенно с разделяемыми библиотеками. Любые данные в структуре после буфера невозможно защитить с помощью канареек; таким образом, программисты должны быть очень осторожны с тем, как они организуют свои переменные и используют свои структуры.

Канареек

Канарейки или канареечные слова - это известные значения, которые помещаются между буфером и управляющими данными в стеке для отслеживания переполнения буфера. Когда буфер переполняется, первыми данными, которые будут повреждены, обычно будет канарейка, поэтому неудачная проверка канареечных данных будет предупреждать о переполнении, которое затем может быть обработано, например, путем аннулирования поврежденных данных. Не следует путать канареечное значение с контрольным значением .

Терминология является отсылкой к исторической практике использования канареек в угольных шахтах , поскольку они будут подвергаться воздействию токсичных газов раньше, чем шахтеры, что обеспечивает систему биологического предупреждения. Канарейки также известны как файлы cookie , которые предназначены для создания образа «сломанного файла cookie», когда значение повреждено.

Используются три типа канареек: терминатор , случайный и случайный XOR . Текущие версии StackGuard поддерживают все три, а ProPolice поддерживает терминатор и случайные канарейки.

Терминатор канарейки

Канарейки-терминаторы используют наблюдение, что большинство атак на переполнение буфера основаны на определенных строковых операциях, которые заканчиваются символами конца строки. Реакция на это наблюдение состоит в том, что канарейки состоят из нулевых терминаторов CR , LF и FF . В результате злоумышленник должен написать нулевой символ перед записью адреса возврата, чтобы избежать изменения канарейки. Это предотвращает атаки с использованием strcpy() и других методов, которые возвращаются при копировании нулевого символа, в то время как нежелательный результат - известность канарейки. Даже при наличии защиты злоумышленник потенциально может перезаписать канарейку с ее известным значением и контрольную информацию с несовпадающими значениями, передав таким образом код проверки канарейки, который выполняется незадолго до команды возврата из вызова конкретного процессора.

Случайные канарейки

Случайные канарейки генерируются случайным образом, обычно от демона сбора энтропии , чтобы злоумышленник не узнал их значение. Обычно читать канарейку на предмет эксплуатации невозможно с логической точки зрения или правдоподобно; канарейка - это безопасная ценность, известная только тем, кому она нужна - в данном случае это код защиты от переполнения буфера.

Обычно случайная канарейка генерируется при инициализации программы и сохраняется в глобальной переменной. Эта переменная обычно дополняется неотображенными страницами, поэтому попытка прочитать ее с помощью любых уловок, использующих ошибки для чтения из ОЗУ, вызывает ошибку сегментации, завершающую программу. Прочитать канарейку все еще можно, если злоумышленник знает, где она находится, или может заставить программу читать из стека.

Случайные канарейки XOR

Случайные канарейки XOR - это случайные канарейки, которые скремблируются с помощью XOR с использованием всех или части управляющих данных. Таким образом, после того, как канарейка или контрольные данные будут уничтожены, значение канарейки будет неправильным.

Случайные канарейки XOR имеют те же уязвимости, что и случайные канарейки, за исключением того, что метод «чтения из стека» получения канарейки немного сложнее. Злоумышленник должен получить канарейку, алгоритм и управляющие данные, чтобы заново сгенерировать исходную канарейку, необходимую для подделки защиты.

Кроме того, случайные канарейки XOR могут защитить от определенного типа атаки, включающей переполнение буфера в структуре указателем, чтобы изменить указатель, чтобы он указывал на часть управляющих данных. Из-за кодирования XOR канарейка будет ошибаться, если изменятся управляющие данные или возвращаемое значение. Из-за указателя управляющие данные или возвращаемое значение могут быть изменены без переполнения канарейки.

Хотя эти канарейки защищают управляющие данные от изменения с помощью затертых указателей, они не защищают никакие другие данные или сами указатели. Особой проблемой здесь являются указатели на функции, поскольку они могут быть переполнены и могут выполнять шелл-код при вызове.

Проверка границ

Проверка границ - это метод на основе компилятора, который добавляет информацию о границах времени выполнения для каждого выделенного блока памяти и проверяет все указатели на соответствие указателям во время выполнения. Для C и C ++ проверка границ может выполняться во время вычисления указателя или во время разыменования.

Реализации этого подхода используют либо центральный репозиторий, который описывает каждый выделенный блок памяти, либо жирные указатели , которые содержат как указатель, так и дополнительные данные, описывающие область, на которую они указывают.

Добавление тегов

Тегирование - это основанный на компиляторе или аппаратный (требующий тегированной архитектуры ) метод тегирования типа фрагмента данных в памяти, используемый в основном для проверки типов. Помечая определенные области памяти как неисполняемые, он эффективно предотвращает хранение исполняемого кода в памяти, выделенной для хранения данных. Кроме того, определенные области памяти могут быть помечены как невыделенные, что предотвращает переполнение буфера.

Исторически тегирование использовалось для реализации языков программирования высокого уровня; при соответствующей поддержке операционной системы тегирование также может использоваться для обнаружения переполнения буфера. Примером может служить аппаратная функция NX bit , поддерживаемая процессорами Intel , AMD и ARM .

Реализации

Коллекция компиляторов GNU (GCC)

Защита от разрушения стека была впервые реализована StackGuard в 1997 году и опубликована на симпозиуме по безопасности USENIX в 1998 году . StackGuard был представлен как набор исправлений для Intel x86 backend GCC 2.7. StackGuard поддерживался для дистрибутива Immunix Linux с 1998 по 2003 год и был расширен реализациями для терминатора, случайных и случайных канареек XOR. StackGuard был предложен для включения в GCC 3.x на конференции GCC 2003 Summit Proceedings, но этого так и не произошло.

С 2001 по 2005 год IBM разработала исправления GCC для защиты от разрушения стека, известные как ProPolice . Он улучшил идею StackGuard, разместив буферы после локальных указателей и аргументов функций в кадре стека. Это помогло избежать повреждения указателей, предотвращая доступ к произвольным участкам памяти.

Однако инженеры Red Hat выявили проблемы с ProPolice и в 2005 году повторно реализовали защиту от разбиения стека для включения в GCC 4.1. В этой работе был представлен -fstack-protector флаг, который защищает только некоторые уязвимые функции, и -fstack-protector-all флаг, который защищает все функции, независимо от того, нужны они им или нет.

В 2012 году инженеры Google внедрили -fstack-protector-strong флаг, чтобы добиться лучшего баланса между безопасностью и производительностью. Этот флаг защищает больше видов уязвимых функций, чем защищает -fstack-protector , но не каждую функцию, обеспечивая лучшую производительность, чем -fstack-protector-all . Он доступен в GCC, начиная с его версии 4.9.

Все пакеты Fedora компилируются с -fstack-protector Fedora Core 5 и -fstack-protector-strong с Fedora 20. Большинство пакетов в Ubuntu компилируются с -fstack-protector 6.10. Каждый пакет Arch Linux компилируется с -fstack-protector 2011 года. Все пакеты Arch Linux, созданные с 4 мая 2014 года, используют -fstack-protector-strong . Защита стека используется только для некоторых пакетов в Debian и только для базовой системы FreeBSD, начиная с версии 8.0. Защита стека является стандартной в некоторых операционных системах, включая OpenBSD , Hardened Gentoo и DragonFly BSD .

StackGuard и ProPolice не могут защитить от переполнения в автоматически выделенных структурах, которые переходят в указатели функций. ProPolice, по крайней мере, изменит порядок размещения, чтобы выделить такие структуры перед указателями на функции. Отдельный механизм защиты указателя был предложен в PointGuard и доступен в Microsoft Windows.

Microsoft Visual Studio

Пакет компиляторов от Microsoft реализует защиту от переполнения буфера с версии 2003 с помощью переключателя командной строки / GS , который включен по умолчанию с версии 2005. Использование / GS- отключает защиту.

Компилятор IBM

Защиту от разрушения стека можно включить с помощью флага компилятора -qstackprotect .

Clang / LLVM

Clang поддерживает три детектора переполнения буфера, а именно AddressSanitizer (-fsanitize = адрес), -fsanitize = bounds и SafeCode. Эти системы имеют разные компромиссы с точки зрения снижения производительности, накладных расходов на память и классов обнаруженных ошибок. Защита стека является стандартной в некоторых операционных системах, включая OpenBSD .

Компилятор Intel

Компилятор Intel C и C ++ поддерживает защиту от разрушения стека с параметрами, аналогичными тем, которые предоставляются GCC и Microsoft Visual Studio.

Отказоустойчивый C

Fail-Safe C - это компилятор ANSI C с открытым исходным кодом, безопасный для памяти, который выполняет проверку границ на основе жирных указателей и объектно-ориентированного доступа к памяти.

StackGhost (аппаратный)

Изобретенный Майк Frantzen , StackGhost простой твик в регистр окна разливы / заполнения процедур , что делает переполнение буфера гораздо труднее использовать. Он использует уникальную аппаратную функцию архитектуры Sun Microsystems SPARC (а именно: отложенное заполнение / заполнение окна регистров в стеке ) для прозрачного и автоматического обнаружения изменений указателей возврата (распространенный способ для эксплойта перехватывать пути выполнения) защита всех приложений без необходимости модификации двоичного кода или исходного кода. Влияние на производительность незначительно, менее одного процента. Спустя два года Марк Кеттенис решил возникшие проблемы с gdb , что позволило включить эту функцию. После этого события код StackGhost был интегрирован (и оптимизирован) в OpenBSD / SPARC.

Пример с канарейкой

Нормальное распределение буфера для архитектур x86 и других подобных архитектур показано в записи о переполнении буфера . Здесь мы покажем измененный процесс применительно к StackGuard.

Когда функция вызывается, создается кадр стека. Фрейм стека строится от конца памяти до начала; и каждый кадр стека помещается на вершину стека, ближайшую к началу памяти. Таким образом, переход от конца фрагмента данных в стековом фрейме изменяет данные, ранее введенные в стековый фрейм; и запуск с конца кадра стека помещает данные в предыдущий кадр стека. Типичный кадр стека может выглядеть, как показано ниже, с первым размещенным адресом возврата (RETA), за которым следует другая управляющая информация (CTLI).

В C функция может содержать множество различных структур данных для каждого вызова. Каждый фрагмент данных, созданный по запросу, помещается в кадр стека по порядку и, таким образом, упорядочивается от конца к началу памяти. Ниже представлена ​​гипотетическая функция и ее стековый фрейм.

В этой гипотетической ситуации, если в массив записано более десяти байтов c или в массив символов d , избыток будет переполняться в целочисленный указатель b , затем в целое число a , затем в управляющую информацию и, наконец, в адрес возврата. При перезаписи b указатель заставляется ссылаться на любую позицию в памяти, вызывая чтение с произвольного адреса. Путем перезаписи RETA функцию можно заставить выполнять другой код (при попытке возврата), либо существующие функции ( ret2libc ), либо код, записанный в стек во время переполнения.

В двух словах, плохое обращение с c и d , например, неограниченная зЬгсру () вызывает выше, может позволить злоумышленнику контролировать программу путем воздействия на значения , присвоенные c и d непосредственно. Целью защиты от переполнения буфера является обнаружение этой проблемы наименее навязчивым способом. Это делается путем удаления того, что может быть небезопасным, и размещения своего рода натяжной проволоки или канарейки после буфера.

Защита от переполнения буфера реализована как изменение компилятора. Таким образом, защита может изменять структуру данных в кадре стека. Именно так обстоит дело в таких системах, как ProPolice . Автоматические переменные вышеупомянутой функции переупорядочиваются более безопасно: массивы c и d выделяются первыми в кадре стека, который помещает целочисленный a и целочисленный указатели b перед ними в памяти. Таким образом, кадр стека становится

Поскольку невозможно переместить CTLI или RETA, не нарушив созданный код, используется другая тактика. Дополнительная информация, называемая «канарейкой» (CNRY), помещается после буферов в стековом фрейме. Когда буферы переполняются, канареечное значение меняется. Таким образом, чтобы эффективно атаковать программу, злоумышленник должен оставить определенное указание на свою атаку. Кадр стека

В конце каждой функции есть инструкция, которая продолжает выполнение с адреса памяти, указанного RETA . Перед выполнением этой инструкции проверка CNRY гарантирует, что она не была изменена. Если значение CNRY не проходит тест, выполнение программы немедленно прекращается. По сути, как преднамеренные атаки, так и непреднамеренные ошибки программирования приводят к прерыванию программы.

Канарский метод добавляет несколько служебных инструкций для каждого вызова функции с автоматическим массивом, непосредственно перед всем распределением динамического буфера и после освобождения динамического буфера. Накладные расходы, возникающие при использовании этого метода, незначительны. Однако это работает, если только канарейка не останется неизменной. Если злоумышленник знает, что он там, и может определить ценность канарейки, он может просто скопировать ее с собой. Обычно это сложно сделать намеренно, и крайне маловероятно в непреднамеренных ситуациях.

Положение канарейки зависит от реализации, но всегда между буферами и защищенными данными. Различное положение и длина имеют разные преимущества.

Напечатать страницу

Перечислим наиболее типичные для современных процессоров функции, которые можно задействовать, используя настройки BIOS.

CPU Ratio Clock - позволяет выбрать максимально доступное значение множителя процессора, тем самым ограничив его тактовую частоту (тактовая частота процессора определяется произведением множителя на опорную частоту системной шины). Рекомендуем оставить этот параметр в значении Авто. В этом случае система автоматически будет определять нужное значение множителя.

Max CPUID Value Limit - включение этого параметра (значение Enable) приведет к принятию ограничения для параметра CPUID (CpuIdentification - инструкция, позволяющая получить информацию о центральном процессоре. Параметр, вместе с которым она вызывается, определяет характер и объем получаемой в результате информации. Его максимальное значение в этом случае равно 3. Эта возможность актуальна при работе со старыми ОС, такими как Windows 98 или Windows МТ. При работе с современными операционными системами этот параметр следует оставить в состоянии Disable

C1E Support - включение этого параметра задействует функцию энергосбережения в состоянии простоя (Enhancet Halt State), благодаря которой будут отключены неиспользуемые процессором блоки, снизится его тактовая частота и напряжение питания. Этот параметр следует установить в состояние Enable

Vanterpool Technology, VisuaLization Technology, VT Technology или AMD-V - этот параметр позволяет включить поддержку технологии аппаратной виртуализации, реализованную в современных ЦП. Она позволяет более эффективно использовать ресурсы системы при работе виртуальных машин. Это параметр рекомендуется выставить в Enable

CPU TM Function, CPU Thermal Monitor 2 (TM2) или Cpu Thermal Control - параметр. встречающийся в системах с процессорами Intеl. Позволяет задействовать схемы термоконтороля Тhermal Моnitоr 2 или Тhermal Моnitоr 1. Этот параметр необходимо оставить в состоянии Enable, а при возможности выбора значений предпочтительнее указать технологию ТМ2, использующую для поддержания рабочего температурного режима механизмы снижения тактовой частоты и напряжения питания процессора

Exelute Disable Bit, NX Technology или XD Technology - функция, запрещающая выполнение программного кода в области данных и предотвращающая возможность проведения вредоносных атак, направленных на переполнение буфера. Работает только в том случае, если ее поддерживает операционная система (Начиная с Windows XP2). В терминах ОС данную функцию называют Data Execution Prevention (DEP). Естественно она должна быть включена (состояние Enable)

Enhanced Intel SpeedStep Technology (Intel EIST) или AMD Cool,n,Quiet - технология энергосбережения, позволяющая динамически изменять частоту и напряжение питания процессора в зависимости от его нагрузки. Следует установить соответствующий параметр в состояние Enable.


Даже если код написан на «безопасном» языке (например, на Python), если используются любые написанные на C, C++ или Objective C библиотеки, он все равно может быть уязвим для переполнения буфера.

Выделение памяти

Чтобы понять механизм возникновения переполнения буфера, нужно немного разобраться с выделением памяти в программы. В написанном на языке С приложении можно выделить память в стеке во время компиляции или в куче во время выполнения.

  • Объявление переменной в стеке: int numberPoints = 10 .
  • Объявление переменной в куче: int* ptr = malloc (10 * sizeof(int)) .

Переполнение буфера может происходить в стеке (переполнение стека) или в куче (переполнение кучи). Как правило, переполнение стека встречается чаще. Он содержит последовательность вложенных функций: каждая из них возвращает адрес вызывающей функции, к которой нужно вернуться после завершения работы. Этот возвращаемый адрес может быть заменен инструкцией для выполнения фрагмента вредоносного кода.

Поскольку куча реже хранит возвращаемые адреса, гораздо сложнее (хотя в ряде случаев это возможно) запустить эксплойт. Память в куче обычно содержит данные программы и динамически выделяется по мере ее выполнения. Это означает, что при переполнении кучи, скорее всего, перезапишется указатель функции – такой путь более сложен и менее эффективен чем переполнение стека.

Поскольку переполнение стека является наиболее часто используемым типом переполнения буфера, кратко рассмотрим, как именно они работают.

Переполнение стека

Эксплуатация уязвимости происходит внутри процесса, при этом каждый процесс имеет свой собственный стек. Когда он выполняет основную функцию, то находит как новые локальные переменные (которые будут «запушены» в начало стека), так и вызовы других функций (которые создадут новый «стекфрейм»).


Что такое stackframe?

Стек вызовов – это в основном код ассемблера для конкретной программы. Это стек переменных и стекфреймов, которые сообщают компьютеру, в каком порядке выполнять инструкции. Для каждой функции, которая еще не завершила выполнение, будет создан стекфрейм, а функция, которая выполняется в данный момент, будет находиться в верхней части стека.

Чтобы отслеживать этот процесс, компьютер хранит в памяти несколько указателей:

  • Stack Pointer: указывает на топ стека вызовов процесса (или на последний помещенный в стек элемент).
  • Instruction Pointer: указывает на адрес следующей инструкции процессора, которая будет выполнена.
  • Base Pointer (BP): (также известный как указатель кадра) указывает на основание текущего кадра стека. Он остается постоянным до тех пор, пока программа выполняет текущий стекфрейм (хотя указатель стека может измениться).

Для примера рассмотрим следующий код:

Стек вызовов будет выглядеть следующим образом, сразу после вызова firstFunction и выполнения оператора int x = 1+z :


Здесь main вызывает firstFunction (которая в данный момент выполняется), поэтому она находится в верхней части стека вызовов. Возвращаемый адрес – это адрес в памяти, относящийся к функции, которая его вызвала (он удерживается указателем инструкции при создании стекфрейма). Локальные переменные, которые все еще находятся в области видимости, также находятся в стеке вызовов. Когда они выполняются и выходят за пределы области действия, они удаляются из верха стека.

Таким образом, компьютер может отслеживать, какая инструкция должна быть выполнена и в каком порядке. Переполнение стека основано на перезаписи одного из этих сохраненных обратных адресов вредоносным адресом.

Пример уязвимости переполнения буфера:

Этот простой код считывает произвольное количество данных ( gets будет считывать до конца файла или символа новой строки). Рассмотрев его, можно понять опасность. Если пользователь вводит больше данных, чем помещается в выделенную для переменной область, введенная строка перезапишет следующие ячейки памяти в стеке вызовов. Если она достаточно длинная, перезапишется даже обратный адрес вызывающей функции.

Как компьютер отреагирует на это, зависит от реализации стеков и выделения памяти в конкретной системе. Реакция на переполнение буфера может быть совершенно непредсказуемой, начиная от сбоев программы и заканчивая выполнением вредоносного кода.

Почему происходит переполнение буфера?

Причина, по которой переполнение буфера стало такой серьезной проблемой, заключается в отсутствии проверки границ во многих функции управления памятью в C и C++. Хотя этот процесс сейчас довольно хорошо известен, он также очень часто эксплуатируется (например, зловред WannaCry использовал переполнение буфера).

Переполнение буфера чаще всего происходит, когда код зависит от внешних входных данных и слишком сложен для программиста, чтобы понять его поведение или когда он имеет зависимости за пределами прямой видимости кода.

Веб-серверы, серверные приложения и среды веб-приложений подвержены переполнению буфера. Исключение составляют написанные на интерпретируемых языках среды, хотя сами интерпретаторы тоже могут быть подвержены переполнению.

Как уменьшить влияние переполнения буфера:

  • Используйте интерпретируемый язык, который не подвержен этим проблемам.
  • Избегайте использования функций, которые не выполняют проверку буфера (например, в C вместо функции gets() используйте функцию fgets()).
  • Применяйте компиляторы, которые помогают определить небезопасные функции или найти ошибки.
  • Используйте canaries, которые могут помочь предотвратить переполнение буфера. Они вставляются перед обратным адресом в стеке и проверяются перед обращением к нему. Если программа обнаружит изменение значения canary, она прервет процесс, не позволив злоумышленнику пробиться. Значение canary является либо случайным (поэтому злоумышленнику очень трудно его угадать), либо строкой, которую по техническим причинам невозможно перезаписать.
  • Переставляйте локальные переменных таким образом, чтобы скалярные (отдельные объекты данных фиксированного размера) были выше переменных массива, содержащих несколько значений. Это означает, что если переменные массива переполняются, они не будут влиять на скалярные переменные. Этот метод в сочетании с canary-значениями очень помогает.
  • Сделайте стек неисполняемым, установив бит NX (No-eXecute), чтобы злоумышленник не вставлял шелл-код непосредственно в стек и не выполнял его там. Это неидеальное решение, так как даже неисполняемые стеки могут стать жертвами атак переполнения буфера, вроде return-to-libc. Эта атака происходит, когда обратный адрес стекового фрейма заменяется адресом библиотеки, уже находящейся в адресном пространстве процесса. К тому же не все процессоры позволяют установить бит NX.
  • ASLR (рандомизация расположения адресного пространства) может служить общей защитой, а также специфической защитой от атак return-to-libc. Это означает, что всякий раз, когда файл библиотеки или другая функция вызывается запущенным процессом, ее адрес сдвигается на случайное число. Это делает практически невозможным связать фиксированный адрес памяти процесса с функциями, из чего следует, что злоумышленнику может быть трудно узнать, откуда вызывать определенные функции. ASLR включен по умолчанию во многих версиях Linux, OS X и Android.

Stack Underflow

Такая уязвимость возникает, когда две части программы по-разному обрабатывают один и тот же блок памяти. Например, если вы выделите массив размером X, но заполните его массивом размером x < X, а затем попытаетесь извлечь все X байтов, скорее всего вы получите «грязные» данные для X – x байтов.

Вы, возможно, извлекли данные, которые остались после использования этой области памяти ранее. В лучшем случае это мусор, который ничего не значит, а в худшем – конфиденциальные данные, которыми может злоупотребить злоумышленник.

Заключение

Рассмотренная уязвимость является очень серьезной угрозой стабильной работе любого продукта. Необходимо приложить все усилия и проверить ваши проекты на ее наличие, т. к. последствия могут быть весьма плачевными (уже упоминался Ransome ) и болезненными. Используйте советы из статьи и вы уменьшите вероятность успешного проникновения злоумышленников в ваш код. Удачи в обучении!

Читайте также: